es7.x(7)—短语搜索(match_phrase)

phrase:[freɪz] 短语

1. 简述

match_phrase查询分析文本并根据分析的文本创建一个短语查询。match_phrase 会将检索关键词分词。match_phrase的分词结果必须在被检索字段的分词中都包含,默认情况下顺序必须相同且必须都是连续的。

ES7.x官方文档—匹配词组搜索

match_phrase搜索的数据类型为text类型,会将查询条件进行分词,但要求待匹配的文档需要同时包含分词后的数据。

流程:

  1. es会先过滤不符合query条件的doc。
  2. es会根据分词的position对分词进行过滤和评分,可通过slop参数来设置,默认为0。即查询条件中的词组相隔的的位置。

2. 实战

2.1 数据准备

# 创建索引
PUT test_phrase

# 创建映射
PUT test_phrase/_mapping
{
  "properties":{
    "name":{
         "type":"text" 
    },
    "createTime":{
      "type":"date",
      "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
    }
  }
}
# 创建数据
POST test_phrase/_doc
{
  "name":"java,es,redis",
  "createTime":"2021-04-21"
}
POST test_phrase/_doc
{
  "name":"java,redis",
  "createTime":"2021-04-21"
}
POST test_phrase/_doc
{
  "name":"java,es,go",
  "createTime":"2021-04-21"
}
POST test_phrase/_doc
{
  "name":"java,go,es",
  "createTime":"2021-04-21"
}

2.2 匹配前提

query条件会进行分词,得到goredis两个条件。去寻找同时包含这两个条件的文档。

# 短语搜索
GET test_phrase/_search
{
    "query": {
        "match_phrase" : {
            "name" : {
                "query" : "go,redis",
                "slop" : 3
            }
        }
    }
}

如下图2.2-1所示,doc文档中不存在同时存在goredis两个词语的name字段,故未找到。

es7.x(7)—短语搜索(match_phrase)_第1张图片
图2.2-1.png

2.3 计算相关得分

match_phrase的分词结果必须在被检索字段的分词中都包含时,match_phrase分词结果也会计算在doc中的顺序。match_phrase的分词的doc中越靠近,则评分越高。

GET test_phrase/_search
{
    "query": {
        "match_phrase" : {
            "name" : {
                "query" : "java,es,go",
                "slop" : 3
            }
        }
    }
}
es7.x(7)—短语搜索(match_phrase)_第2张图片
image.png

2.3 slop控制词组偏移

默认情况下,match_phrase的slop为0,即顺序必须相同且必须都是连续的。

es7.x(7)—短语搜索(match_phrase)_第3张图片
image.png

当然可以通过slop参数来控制短语的偏移量:

es7.x(7)—短语搜索(match_phrase)_第4张图片
image.png

短语搜索到的doc文档,不必顺序相同,只要slop足够,依旧可以搜索出来。

es7.x(7)—短语搜索(match_phrase)_第5张图片
image.png

3. 性能分析

  • 由于match_phrase是在搜索阶段进行的计算,会影响搜索效率,据说比term查询慢20倍,所以不要进行大文本量的字段搜索,尽量进行标题,名字这种类型的搜索才使用这个;

  • 使用match_phrase性能是要比单纯的全文检索性能低的,因为他要计算位置。那么想提高性能可以通过先使用match进行过滤数据,然后利用rescore api对已经match的结果进行加分,这样就减少了部分不必要的非match过滤;

GET test_phrase/_search
{
  "query": {
    "match": {
      "name": "java,go"
    }
  },
  "rescore" : {
    "window_size" : 50,
    "query" : {
      "rescore_query" : {
        "match_phrase" : {
          "name" : {
            "query" : "java,go",
            "slop" : 1
          }
        }
      }
    }
  },
"from":0,
"size":2
}

相当参数:

  1. window_size:每个分片中返回的前50条数据。
  2. from,size:分页,对所有分片的window_size数据的相对页做重评分计算。

推荐阅读

es 基于match_phrase/fuzzy的模糊匹配原理及使用

ElasticSearch系列——使用rescoring机制优化近似匹配搜索的性能

你可能感兴趣的:(es7.x(7)—短语搜索(match_phrase))