ES查询可以分为两大类,一类是Get,一类是Search,下面说一下Es内部是怎么实现的.
一:Get检索
通过ID检索特定的Doc
> 查询的时候是先查询内存中的TransLog,如果找到就立即返回
> 如果没找到再查询磁盘上的TransLog
> 如果还没有则再去查询磁盘上的Segment(原始Lucene)
二:Search检索
通过query查询来匹配对应的Doc文档,查询的时候是一起查询内存和磁盘上的Segment,最后将结果合并后返回
。其实它有三个对应的实现,默认使用的是第二个,第三个评分准确度最高,但是性能也是最低的,实际使用中需要根据具体的业务需求,选择对应的检索阶段。
1 query_and_fetch:第一阶段查询到匹配的DocID
2 query_then_fetch:第二阶段再查询DocID对应的完整文档
3 dfs_query_then_fetch:先收集所有Shard中的TF和DF值,然后将这些值带入请求中,再次执行query_then_fetch,这样算分的时候TF和DF就是准确的
三:检索具体流程
> 实现机制概括
第一阶段的Query Phase请求,则会调用SearchService的executeQueryPhase方法
第二阶段的Fetch Phase请求,则会调用SearchService的executeFetchPhase方法
> 具体步骤
ClientNode:客户端节点
Get Remote Cluster Shard:判断是否需要跨集群访问,如果需要,则获取到要访问的Shard列表。
Get Search Shard Iterator:获取当前Cluster中要访问的Shard,勾出要访问完整的shard列表
For Every Shard:Perform:遍历每个Shard,对每个Shard执行后面逻辑
Send Request To Query Shard:将查询阶段请求发送给相应的Shard
Merge Docs:
>> 异步等待返回结果,然后对结果合并
维护一个Top N大小的优先级队列,每当收到一个shard的返回,就把结果放入优先级队列做一次排序,直到所有的Shard都返回。
>>分页查询
search_after
返回的总数据量只是和Shard个数以及本次需要的个数有关,和历史已读取的个数无关
深度分页
通过scroll来实现
本质类似于游标
不能逆行查询,往返查询
只能查询下一页
QueryPhase:一阶段查询
Query Phase
1 Create Search Context
创建Search Context,之后Search过程中的所有中间状态都会存在Context中
2 Parse Query
解析Query的Source,将结果存入Search Context
3 Get From Cache
判断请求是否允许被Cache,如果允许,则检查Cache中是否已经有结果
4 Add Collectors
收集查询结果,实现排序,自定义结果集过滤和收集等
FilteredCollector
先判断请求中是否有Post Filter,Post Filter用于Search,Agg等结束后再次对结果做Filter,希望Filter不影响Agg结果。如果有Post Filter则创建一个FilteredCollector,加入Collector List中。
PluginInMultiCollector
判断请求中是否制定了自定义的一些Collector,如果有,则加入Collector List。
MinimumScoreCollector
:判断请求中是否制定了最小分数阈值,如果指定了,则创建MinimumScoreCollector加入Collector List中,在后续收集结果时,会过滤掉得分小于最小分数的Doc
EarlyTerminatingCollector
判断请求中是否提前结束Doc的Seek,如果是则创建EarlyTerminatingCollector,加入Collector List中。在后续Seek和收集Doc的过程中,当Seek的Doc数达到Early Terminating后会停止Seek后续倒排链
CancellableCollector
判断请求中是否提前结束Doc的Seek,如果是则创建EarlyTerminatingCollector,加入Collector List中。在后续Seek和收集Doc的过程中,当Seek的Doc数达到Early Terminating后会停止Seek后续倒排链
5 lucene::search
调用Lucene中IndexSearch的search接口,执行真正的搜索逻辑
6 rescore
根据Request中是否包含rescore配置决定是否进行二阶段排序,如果有则执行二阶段算分逻辑,会考虑更多的算分因子
7 suggest::execute()
如果有推荐请求,则在这里执行推荐请求
8 aggregation::execute()
如果含有聚合统计请求,则在这里执行
FetchPhase:二阶段查询
Fetch Phase
当Client Node选择出最终Top N的结果后,再对最终的Top N读取Doc内容
ExplainFetchSubPhase
DocValueFieldsFetchSubPhase
ScriptFieldsFetchSubPhase
FetchSourceSubPhase
VersionFetchSubPhase
MatchedQueriesFetchSubPhase
HighlightPhase
ParentFieldSubFetchPhase
通过插件的形式注册自定义的功能
> 牵涉核心类
SearchPhase
AggregationPhase
聚合查询
DfsPhase
三阶段查询
FetchPhase
二阶段查询
QueryPhase
一阶段查询
RescorePhase
二次加分查询
SuggestPhase
推荐查询
备注:es查询 默认没有实现保证全局精准的TF-IDF