ElasticSearch 源码分析十 ES搜索实现 Search(三)
fetch阶段的步骤 :通过文档id获取完整的文档内容
(1)首先对query结果进行排序,获取要fetch的doc id
(2)按shard把这些id填充到docIdsToLoad对象中
(3)按shard去elasticsearch获取文档详情
(4)将第一步中已经排好序的文档与fetch到的结果按照顺序合并
(5)如果请求中有scroll,重新构建scroll id
(6)向调用方返回响应数据
(7)如果不是scroll请求,则释放search context
继续执行到moveToNextPhase,执行下一个阶段
循环获取每一个docIds
1.发送获取请求,也即是Transport发送,sendExecuteFetchScroll,最后归结为发送sendChildRequest
2.监听结果为innerOnResponse,fetchResults会存储从这个shard收集到的结果,每收到一个shard的数据,就执行一次
counter.countDown
看fetch的详细流程
3.执行fetch的过程,即将fetch请求发送到指定的节点执行,在获取执行结果后执行finishHim()进行数据的merge()
直接看executeFetch的实现
4.还是发送fetch请求到指定的节点node
5.执行在FetchPhase的execute方法
(1)首先创建FieldsVisitor对象,根据是否要fetch source,创建UidAndSourceFieldsVisitor或JustUidFieldsVisitor
(2)遍历每个要fetch的文档,判断文档是否为Nested结构,然后分别调用createNestedSearchHit()或者createSearchHit()得到SearchHit
(3)获取SearchHit后再补充如下阶段的结果:ScriptFieldsPhase, PartialFieldsPhase, MatchedQueriesPhase, ExplainPhase, HighlightPhase, FetchSourceSubPhase, VersionPhase, FieldDataFieldsFetchSubPhase, InnerHitsFetchSubPhase
(4)将hit结果集hits、全部命中结果数totalHits和最大得分maxScore放入context.fetchResult().hits对象中
在创建SearchHit时,使用loadStoredFields从lucene中获取已经存储的字段信息,如下图
6. 在成功获取到fetch数据后,将调用listener.onResult() 进行设置fetch result及调用finishHim()完成数据合并并返回响应数据,具体逻辑如下:
(1)elasticsearch调用SearchPhaseController的merge()方法进行数据合并
(2)如果请求中包含scroll,则需要重写生成scroll id,用于后面继续scroll
(3)调用listener.onResponse()向调用放返回响应数据
(4)如果当前不是scroll请求,则需要释放search context
合并数据的逻辑主要如下:
(1)获取文档的最大得分maxScore和命中总的文档数totalHits
(2)按照fetch开始时已经排好序的sortedDocs顺序,填充shard、score和fetch结果SearchHit
(3)merge其他信息,如suggest、facets、aggregation等等
(4)返回merge后的结果集
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
关于节点上的搜索
1.先从缓存获取,这个cache是该节点的所有分片共享,基于LRU实现数据清除
2.没有就调用queryPhase.execute(context) 底层是 调用lucene实现搜索,同时实现聚合