solr分布式搜索源码分析

基于solr4.4   

   分布式搜索的主控逻辑是在SearchHandler.handleRequestBody方法中实现的,参见distributed request分支
分布式搜索过程是分阶段stage的,stage的控制在每个componnet的distributedProcess方法中,每个stage的请求输出都会封装在outgoing.add(sreq)中。
component针对每个stage做相应的参数的设置和处理,并输出到outgoing中,在while循环中检测到outgoing有值,则代表需要对该请求,进行分布式的调用;
分布式调用会针对当前的stage提交每个shard的查询,并异步收集所有shard的返回结果。
 每个stage计算完成后,对结果进行处理
 for(SearchComponent c : components) {
              c.handleResponses(rb, srsp.getShardRequest());
            }

所有的stage都完成后,调用component.finishStage进行后续的处理
   for(SearchComponent c : components) {
          c.finishStage(rb);
        }


stage主要分两个stage,为makeQuery和getFileds
      makeQuery,给url带上查询参数fl=id,score根据情况是否会带,我们知道fl是代表只返回那些field,Solr会取schema配置文件的uniquerField,所以这次请求就只返回id的值。得到id值后,QueryComponent会合并id,如果不同的shard有相同的id,则会只取一个
      getFileds,通过QueryComponent来封装请求参数,其中最关键的是封装ids参数,即根据上面请求得到的ids参数把他作为值放到url里,再一次发请求根据id来取对应的field
其实在这两个阶段之前,还有一个阶段是STAGE_PARSE_QUERY,在这个阶段可以计算分布式的idf,不过目前solr没有实现,而是默认每个shard只计算自己的idf,并不会计算全局的idf,在数据量较大的情况下,基于Shard层次的TF-IDF不会有太大的偏差,但是如果分布式索引非常不均衡,可能就要重视相关度的计算问题.

      makeQuery stage完成后,对所有shards返回的docs进行mergeIds操作,mergeIds实现中会根据分页把doc放到优先级队列中,根据sort和score进行比较排序,获取当前页面的doc list,这里存在一个问题,优先级队列的size是start+rows,只返回rows大小的给客户端,不过需要对top的start+rows数量的doc进行排序,的对于翻页比较多的情况,代理节点内存的开销和排序计算的CPU开销都会比较大

比如
QueryComponent,
  private void handleRegularResponses(ResponseBuilder rb, ShardRequest sreq) {
    if ((sreq.purpose & ShardRequest.PURPOSE_GET_TOP_IDS) != 0) {
      mergeIds(rb, sreq);
    }

    if ((sreq.purpose & ShardRequest.PURPOSE_GET_FIELDS) != 0) {
      returnFields(rb, sreq);
    }
  }

你可能感兴趣的:(分布式,Solr,源码分析)