filter不贡献评分,查询目标是判定是或者否,还可以使用缓存,效率更高。
query计算评分,查询目标是判定相关性,效率比filter低。
关于三者各自的作用可以查看我的另一篇文章。
我们可以将es对数据的存储查询过程分为三个阶段,索引index,查询search,取回fetch。
index阶段,es解析源文档,按照mapping配置、字段配置对字段进行索引,将整个源文档存储(如果没有禁用_source),将指定的字段进行store,另外存储一份(如果store设置为true),对指定字段建立doc_values存储(如果doc_values可用)。
search阶段,解析query dsl,通过通过索引或者doc_values对字段进行检索和过滤,找到符合条件的文档id,对于需要聚合计算的,取出文档并进行计算?
fetch阶段,按需返回指定的字段,指定_source,fields,或者docvalue_fields,这三个对应三个不同的存储位置,三者存在的作用也不同。
这四个都是获取自己想要的字段,通常情况下,es推荐的是使用fields。
fields和_source filter差不多,但是fields会从_source取出相应的字段数据并按照mapping设置进行一些格式处理、运行时字段计算等。
stored_fields是取出被store的字段,通常不建议使用。
docvalue_fields是取出建立了doc_values的字段,部分类型不支持。
按照特定的字段分组,每组均返回结果,例如搜索手机,每个品牌都想看看,按品牌字段折叠,返回每个品牌的可排序、过滤的数据。
GET /book/_search
{
"size": 5,
"_source": false,
"query": {
"match": {
"info": "化学"
}
},
"collapse": {
"field": "publish",
"inner_hits": {
"_source": {
"excludes": {
"*vector"
}
},
"name": "test",
"size": 2,
"from": 2
}
}
}
有两种使用filter的方式
使用带filter的bool查询,filter会在检索和聚合之前生效。
直接使用post_filter查询,对检索无影响,在聚合之后生效,可以使用rescore提高检索的相关性。
rescore在所有分片上对query和post_filter的top-k个结果进行算分,可以调整top-k,原score权重,rescore权重,原score和rescore的计算方式(加减乘除平均)。
对存在检索关键词的结果字段添加特殊标签。es支持三种Highlighter。
既然需要高亮指定的句子短语,highlighter需要知道每个词的起始字符位置,有以下几种方式。
索引时分析文本的结果。如果mapping中index_options设置为offsets,unfied highlighter使用这些信息完成高亮而不用再次使用分析器分析文本。它会在预先分析的结果上再次运行查询并从索引中匹配字符偏移。对于大字段来说,不需要重新分析文本是很有意义的,同时相比于term_vector占用更小的磁盘空间。
Term vector。如果term_vector参数设置为with_positions_offsets,unified highlighter会自动使用这些信息高亮字段,因为可以直接访问到每个文档的词典,所以能提高大字段(1MB以上)和muti-term查询比如prefix或者wildcard的高亮速度。Fast vector highlighter只能使用term vector。
Plain highlighter,当其他highlighter不能用时会使用这个,对于大文本会很耗时间和内存。
Highlighter是怎么工作的?对于一个查询,highlighter需要找到最佳的文本片段并且高亮目标词句,这里所指的片段是指一个词、多个词或者词句,这必须解决以下三个问题。
如何将文本切片?
Plain highlighter基于给定的分析器分词,然后遍历每一个词并添加到片段中,当片段将要超过最大fragment_size时,创建新的片段。如果分词不恰当,比如标点符号被单独分出或词以标点符号开头,可能会导致某个片段以标点符号开始。
Unified或者FVH highlighter使用Java的BreakIterator进行切片,在允许的片段大小下,尽量保证词句的完整性。
相关的配置选项fragment_size
, fragmenter
, type
, boundary_chars
, boundary_max_scan
, boundary_scanner
, boundary_scanner_locale
。
如何找到最佳的片段?
三者都是在给定的查询上对片段进行评分,但是评分计算方式不同。
Plaing highlighter会在内存中为分词结果重新创建一个索引并执行Lunene的查询并计算得分。片段中每出现一个查询的term,片段的得分加1(boost决定,默认是1),每个片段的每个term只会被计算一次。
FVH既不需要对文本进行分析,也不需要重新执行查询,而是term_vector的结果,进行切片,按照和Plain highlighter类似的方式计算片段得分,不同的是每个片段的term可以被计算多次。
Unified highlighter可以使用term_vector或者index_options配置的term_offsets,如果这两者不可用,将会使用Plain highlighter的方式在内存中建立索引并再次进行查询。Unified highlighter使用BM25算法j评分。
如何高亮片段中的词句?
How to highlight the query terms in a fragment?
支持异步查询,可使用 get async search查看检索的运行状态。
添加或更新文档不修改旧的索引文件,写新文件到缓存,延迟刷盘,可通过API强制更新索引。
普通分页,深度分页scroll,search after。
搜索嵌套对象或Join检索、字段折叠等情况下,可以查出具体每个阶段的文档。
例如字段折叠,inner_hits可以查询出折叠每个分组下具体有哪些文档。
支持name、sort、from、size参数。
使用_source filter、fileds、docvalue_fields、stored_fields返回需要的文档字段。
支持多种检索API的分布式搜索。
支持同时从一次从多个索引检索数据。
ES将索引分片并可以重复保存在多个节点上,可以提高容错和检索能力。默认情况下ES自动根据负载情况、响应时间选择合适的节点查询。在查询中可以配置preference优先去哪个节点查询,可以配置routing指定分片查询,可以配置每个节点同时并发检索的分片数。
复用的检索模板,根据不同变量生成不同query dsl,Mustache语法。
定义同义词集,在索引和检索阶段可以被文本分析器中的tokenfilter使用,提高检索准确度。ES中提供了三种方法配置同义词
以下是同义词文件示例
# 左边的词在tokenfilter会被替换为右边的词
i-pod, i pod => ipod
sea biscuit, sea biscit => seabiscuit
# 取决于同义词的expand配置
ipod, i-pod, i pod
foozball , foosball
universe , cosmos
lol, laughing out loud
# expand为true的情况(默认),左边任意一个词会被替换为右边三个词
ipod, i-pod, i pod => ipod, i-pod, i pod
# expand为false,相当于左边任意三个词替换为右边一个词
ipod, i-pod, i pod => ipod
# 以下两行配置
foo => foo bar
foo => baz
# 相当于下面一行配置
foo => foo bar, baz
何时使用同义词替换
索引阶段,也就是说分词之后tokenfilter进行同义词替换,然后建立索引,如果同义词更新,需要重建索引。
搜索阶段,同义词替换只发生在搜索阶段,同义词库文件变化不需要重建索引。
通过配置analyzer和search_analyzer指定何时使用同义词替换。
支持多字段,数组字段、嵌套字段排序,对于数组的排序,可以选择数组的最大值、最小值、平均值等作为排序依据。对一个字段指定排序后,不再计算评分,除非指定track_score。
最邻近搜索knn search,检索最邻近的向量,常用于相关性排名、搜索建议、图像视频检索。
语义检索semantic search,按语义和意图检索,而不是词汇检索,基于NLP和向量检索,支持上传模型,在存储和检索时自动编码,支持混合检索。
所有的检索特性可以查看官方文档
query用于回答相似度是多少的问题,计算评分。
filter用于回答是或否的问题,不计算评分,可使用缓存,效率更高
match,最常用,分词,全文检索。
match_phrase,与match类似,但是索引分词和查询分词结果必须相同,包括分词得到的顺序,可配置参数slop,允许词和词之间出现其他token的数量。
本人在ik分词测试,需要将analyzer和search_quote_analyzer设置成一样的分词器,才能正确检索出结果。
match_phrase容易受到停用的影响,不配置ik的停用词影响match搜索,配置之后影响match_phrase,本人使用ik的tokenizer自定义analyzer,但是
ik的tokenizer就完成了中文标点去除、停用词去除以及分词的功能,无法配置其仅完成分词,需要修改源码。