《Elastic Stack 实战手册》——三、产品能力——3.4.入门篇——3.4.2.Elasticsearch基础应用——3.4.2.17.Text analysis, settings 及 mappings——3.4.2.17.3.全文搜索/精确搜索(2) https://developer.aliyun.com/article/1229942
二、基于词项和文本的查询
在解析 term 与 match 方法之前,我们先来理解两个在 ES 搜索查询中需要知道的两个概念 term 和 token 。
Term 代表文本中的一个单词。这是搜索单元,即搜索的最小元素(可以称之为词项)。
Token 文档进行索引后的最小元素,即语汇单元。Token 一般由词项(term)、位置(position)、偏移量(offset)、类型(type)、标志位(flags)和有效负载这些要素组成。
Token 的产生其实也是倒排索引产生的过程,是通过一定的解析规则将一段文档解析成一堆不可再拆分的词干的过程。而解析规则的制定主要依靠分词器的设置。
ES 搜索的最终过程就是 term 与 token 中词项进行比对的过程(我们在这里称它为词项比对)。
我们可以通过 _analyze API 体验到文档解析成 token 的过程。
POST _analyze { "analyzer": "standard", "text": [ "Quick Foxes Brown !" ] }
返回结果:
{ "tokens" : [ { "token" : "quick", "start_offset" : 0, "end_offset" : 5, "type" : "<ALPHANUM>", "position" : 0 }, { "token" : "foxes", "start_offset" : 6, "end_offset" : 11, "type" : "<ALPHANUM>", "position" : 1 }, { "token" : "brown", "start_offset" : 12, "end_offset" : 17, "type" : "<ALPHANUM>", "position" : 2 } ] }
通过 API 可以看到,文档内容 "Quick Brown Foxes!" 经过 standard 分词器解析后形成
"quick","brown","foxes" 三个 token 。
也可以看到每个 token 的 offset、type 和 position 的属性,这些属性主要用于搜索过程中的相关性算分,算分内容在这里不进行详细介绍。
然后我们再看看 ES 中搜索与索引时的处理过程:
注意:搜索和索引的过程中,分词器可以选择不一样的,但并不推荐这么做(控制不好就会造成搜索结果的难以理解 )。
对于基于全文搜索(full text queries)和基于词项搜索(term-level queries)的定义主要如下:
l 基于词项的搜索:如 term 或 fuzzy 这样的底层查询不需要分词阶段,将被查询的内容直接作为词项,对相应字段进行词项匹配和相关性算分,得出匹配的查询结果。
l 基于全文的搜索:像 match 或 query_string 这样的查询是高层查询,根据字段的格式信息,特别是分词器的配置,形成词项列表。这个查询会对词项列表中的每个词项逐一执行底层的查询(比如 term 查询),再将结果合并,然后为每个文档生成一个最终的相关度评分。返回对应相关性文档结果。
这里基于词项和基于全文的分别在于,被查询的字符串是否会被分词。词项即 term,基于词项即将被查询的字符串作为一个 term 去查询。而基于全文,则将被查询的字符串作为一个 text文本,进分词成 term 后进行查询。
在实际使用中,对于复杂文本内容的查询,使用基于全文的搜索比基于词项的更加实用。比如之前使用 "term": {"full_text": "brown foxes"} 查询 "quick brown foxes!" 这个文本就失败了,"brown foxes" 这个查询内容更适合全文搜索,需要进行分词。
下面基于实例,来看下基于全文查询的实现过程:
首先,索引一些实验数据:
PUT full-text-query POST full-text-query/_mapping {"properties":{"title":{"type":"text"}}} POST full-text-query/_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" }
然后使用 match 查询进行全文搜索。
GET /full-text-query/_search { "query": { "match": { "title": "QUICK!" } } }
在这个过程中,ES 主要做了以下操作:
1、检查字段类型。这里字段类型是 text,使用默认的 standard 分词器。
2、解析被查询的字符串。将查询的字符串 QUICK! 传入 standard 分析器中,输出的结果是单个项 quick 。因为只有一个单词项,所以 match 查询执行的是单个底层 term 查询。
3、查找匹配文档。用 term 查询在倒排索引中查找 quick 然后获取一组包含该项的文档,本例的结果是文档:1、2 和 3 。
4、文档评分。用 term 查询计算每个文档相关度评分 _score 。根据相关性评分,文档 3 等分最高。
{ "_index" : "full-text-query", "_type" : "_doc", "_id" : "3", "_score" : 0.4425555, "_source" : { "title" : "The quick brown fox jumps over the quick dog" } }, { "_index" : "full-text-query", "_type" : "_doc", "_id" : "1", "_score" : 0.423274, "_source" : { "title" : "The quick brown fox" } }, { "_index" : "full-text-query", "_type" : "_doc", "_id" : "2", "_score" : 0.30818442, "_source" : { "title" : "The quick brown fox jumps over the lazy dog" } }
两者之间的比对如下图:
下面我们看一下这两类查询的具体使用方法
《Elastic Stack 实战手册》——三、产品能力——3.4.入门篇——3.4.2.Elasticsearch基础应用——3.4.2.17.Text analysis, settings 及 mappings——3.4.2.17.3.全文搜索/精确搜索(4) https://developer.aliyun.com/article/1229940