《Elastic Stack 实战手册》——三、产品能力——3.4.入门篇——3.4.2.Elasticsearch基础应用——3.4.2.17.Text analysis, settings 及 mappings——3.4.2.17.3.全文搜索/精确搜索(15) https://developer.aliyun.com/article/1229924
4.8 intervals
这是一种根据匹配的 term 的顺序和相似度返回文档的一种方法。
intervals 查询根据一些定义的匹配规则,来查询某个字段与词项一致的 tokens 是否符合规则组合排序。主要根据词项的顺序和间隔来组装规则。
使用方法:
POST _search { "query": { "intervals" : { "my_text" : { "all_of" : { "ordered" : true, "intervals" : [ { "match" : { "query" : "my favorite food", "max_gaps" : 0, "ordered" : true } }, { "any_of" : { "intervals" : [ { "match" : { "query" : "hot water" } }, { "match" : { "query" : "cold porridge" } } ] } } ] } } } } }
上面的查询要求在 my_text 字段先无间隔按照词项顺序匹配出 my favorite food 的文档,再去查询符合 hot water 或者 cold porridge 的文档。
intervals方法对各个查询场景的类型如下:
l match:普通的 match 场景。
l prefix:前缀匹配查询。
l wildcard:使用贪婪匹配查询。
l fuzzy:模糊匹配查询。
l all_of:返回全部满足子查询的条件的文档。
l any_of:返回任意满足一个子查询条件的文档。
l filter:为其它 intervals 查询添加规则条件。
在 intervals 方法中主要有下面几个特定参数可以选择:
1、max_gaps: 词项间最大的位置距离,比这个距离更远的词项则认为不匹配,默认是 -1。设置为 -1 则是没有距离限制,设置为 0 则是词项必须相邻出现。用于 match、all_of 类型。
2、ordered: 默认 false,如果为 true,则词项必须按照顺序出现。用于 match、all_of 类型。
对于 filter 类型主要是相关条件的关系判断,有 after/before/contained_by/containing/not_contained_by/not_containing/not_overlapping/overlapping/script.
查询字段的数量限制:在 combined_fields 查询中,这个查询字段的限制受制于查询逻辑中产生的组合字段与词项匹配出的子查询数量。
与 multi_match 的比较:
1、在查询效果上 combined_fields 与 cross_fields 的效果是一致的。
2、combined_fields 只能查询相同分词器的字段,如果有不同的分词器。
5 实现精确搜索
在之前的内容中,主要介绍了 ES 对文本内容基于全文搜索的主要方法,也是全文搜索的场景。
那么,对于文本内容,ES 是否可以做到精确搜索呢?比如:查询 "The quick brown fox" 只
返回 "The quick brown fox" 这个文档,其余文档均不会返回。
答案是使用 term 对 keyword 字段进行查询。当然 match 也是可以的。
我们来看下面例子:
首先,索引一些实验数据:
PUT exact-search POST exact-search/_mapping {"properties":{"title":{"type":"keyword"}}} POST exact-search/_bulk { "index": { "_id": 1 }} { "title": "The quick brown fox" } { "index": { "_id": 2 }} { "title": "The quick brown fox jumps over the lazy dog" } { "index": { "_id": 3 }} { "title": "The quick brown fox jumps over the quick dog" } { "index": { "_id": 4 }} { "title": "Brown fox brown dog" }
然后,使用 term 查询“The quick brown fox”。
GET exact-search/_search { "query": { "term": { "title": { "value": "The quick brown fox" } } } }
查询逻辑如下:
1、字段类型为 keyword,不会因为分词的过程导致各种 token 的形成,因此倒排索引中的
token 即文本本身。
2、使用 term 查询,被查询的内容不会被分词,"The quick brown fox" 不会形成 "The "、"quick"、"brown"、"fox" 这些词项,被搜索文本内容即词项本身。
3、词项匹配只有文档 1 符合条件。
因此,查询结果只有文档 1.
{ "_index" : "exact-search", "_type" : "_doc", "_id" : "1", "_score" : 1.2039728, "_source" : { "title" : "The quick brown fox" }
6 思考和总结
1、在磁盘允许的情况下,多字段设置 keyword 和 text 可以更方便的查询。
2、对于日常文档搜索,match_phrase 相比 match 可能更加实用,但是 match 和 multi_match 则能满足更多的使用场景。
3、对于搜索查询没有达到预期匹配的情况,可以多使用 _analyze API 进行解析查看词项的分词情况。