Elasticsearch 查询之 单字符串多字段查询

单字符串多字段查询

Disjunction Max Query

查询示例

示例代码

PUT /blogs/_doc/1
{
    "title": "Quick brown rabbits",
    "body":  "Brown rabbits are commonly seen."
}

PUT /blogs/_doc/2
{
    "title": "Keeping pets healthy",
    "body":  "My quick brown fox eats rabbits on a regular basis."
}

image-20201214212736358

查询结果

image-20201214212843528

分析算分过程

  • 查询should语句中的两个查询
  • 加和两个查询的评分
  • 乘以匹配语句的总数
  • 除以匹配语句的总数

按照这个过程,

文档1 的标题和body都包含了brown

文档2 只有body 完全匹配了

所以出现了文档1分数比文档2高的情况

查询分析

image-20201214213146794

引入Disjunction Max Query

为了避免这种将分数简单叠加的情况出现。

我们需要使用 Disjunction Max Query,他可以将任何与任一查询匹配的文档做为结果返回。采用字段上最匹配的评分作为最终评分返回

POST blogs/_search
{
    "query": {
        "dis_max": {
            "queries": [
                { "match": { "title": "Quick pets" }},
                { "match": { "body":  "Quick pets" }}
            ]
        }
    }
}

image-20201214213703357

tie_breaker 参数使用

tie_breaker 是一个介于0-1之间的浮点数。0表示使用最佳匹配;1表示所有语句同样重要

生效过程:

  • 获取最佳匹配语句的评分
  • 将其他语句的评分与tie_breaker 相乘
  • 对以上评分进行求和并规范化

针对本例,我们修改查询

POST blogs/_search
{
    "query": {
        "dis_max": {
            "queries": [
                { "match": { "title": "Quick pets" }},
                { "match": { "body":  "Quick pets" }}
            ]
        }
    }
}

image-20201214215302089

查询结果分数是一样的

使用tie_breaker 之后

POST blogs/_search
{
    "query": {
        "dis_max": {
            "queries": [
                { "match": { "title": "Quick pets" }},
                { "match": { "body":  "Quick pets" }}
            ],
            "tie_breaker": 0.1
        }
    }
}

image-20201214215350163

文档2分数比文档1高了

MultiMatch Query

三种查询场景

  • 最佳字段(Best Fields)
    • 当字段之间相互竞争,又相互关联,如上文中的title和body 之类的字段,评分来自最匹配的字段
  • 多数字段(Most Fields)
    • 处理英文内容时:一种常见的手段是,在主字段使用英文分词器,抽取词干,将过去式和现在式和进行式等作为同义词处理,以匹配更多的文档。相同的文本,加入子字段,子字段使用标准分词器,以提供更加精确的匹配。因为标准分词器不会把过去式和现在式和进行式等做为同义词看待。所以就有了更多的匹配字段,
  • 混合字段 (Cross Field)
    • 对于某些实体,如人名,地址,图书信息。需要在多个字段中确定信息,单个字段只能作为整体的一部分。希望在任何这些列出的字段中找到尽可能多的词

最佳字段(Best Fields)

POST blogs/_search
{
  "query": {
    "multi_match": {
      "type": "best_fields",
      "query": "Quick pets",
      "fields": ["title","body"],
      "tie_breaker": 0.2,
      "minimum_should_match": "20%"
    }
  }
}

best_fields是默认类型,可以不用指定

minimum_should_match等参数可以传递到生成的query中

多数字段(Most Fields)

一般场景

使用案例-创建index,插入文档

DELETE /titles
PUT /titles
{
    "settings": { "number_of_shards": 1 },
    "mappings": {
        "my_type": {
            "properties": {
                "title": {
                    "type":     "string",
                    "analyzer": "english",
                    "fields": {
                        "std":   {
                            "type":     "string",
                            "analyzer": "standard"
                        }
                    }
                }
            }
        }
    }
}

PUT /titles
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "english"
      }
    }
  }
}

POST titles/_bulk
{ "index": { "_id": 1 }}
{ "title": "My dog barks" }
{ "index": { "_id": 2 }}
{ "title": "I see a lot of barking dogs on the road " }

查询

GET titles/_search
{
  "query": {
    "match": {
      "title": "barking dogs"
    }
  }
}

结果如图

image-20201214221321601

为什么第二个明显匹配,但是分数却更低呢

因为我们指定了索引titles的title属性的分词器为英文分词器,英文分词器会将进行时,过去式,现在式等看作为同义词,而match query 在查询时会进行分词,然后就导致了 barking dogs 被理解为了 bark 和 dog 2个词。文档1和文档2 中都有这2个词,而文档1更短,所以分数高。

如何改变这种情况。

首先修改index的mapping

DELETE /titles
PUT /titles
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "english",
        "fields": {"std": {"type": "text","analyzer": "standard"}}
      }
    }
  }
}

POST titles/_bulk
{ "index": { "_id": 1 }}
{ "title": "My dog barks" }
{ "index": { "_id": 2 }}
{ "title": "I see a lot of barking dogs on the road " }

查询

GET /titles/_search
{
   "query": {
        "multi_match": {
            "query":  "barking dogs",
            "type":   "most_fields",
            "fields": [ "title", "title.std" ]
        }
    }
}

image-20201214222909132

通过为一个字段增加英文分词和标准分词器,再使用most fields方式进行查询,就可以返回最匹配的结果

混合字段 (Cross Field)

{
    "street" : "5 Poland Street",
    "city" : "London",
    "country" : "United Kingdom",
    "postcode" : "W1V 3DG"
}

这是一个地址信息

我们查询的内容是 :Poland Street W1V

可以看到,这是几个字段的一个组合

在没学习 **混合字段 (Cross Field)**这种类型的查询方式时,我们可以使用copy_to,将需要的字段进行组合生成新的字段。来解决这种查询。但是copy_to的查询方式会使用额外的存储空间。并且cross_fields查询方式也支持使用operator

POST address/_search
{
    "query": {
        "multi_match": {
            "query": "",
            "type": "cross_fields",
            "operator": "and",
            "fields":["street","city","country","postcode"]
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值