Solr学习笔记 - 关于timeAllowed

时间:2022-07-22
本文章向大家介绍Solr学习笔记 - 关于timeAllowed,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

关于timeAllowed

TimeLimitingCollector

TimeLimitingCollector的getLeafCollector方法返回一个FilterLeafCollector对象,在collect每个doc的时候判断是否超时:

return new FilterLeafCollector(this.collector.getLeafCollector(context)) {
    public void collect(int doc) throws IOException {
        long time = TimeLimitingCollector.this.clock.get();
        if (time - TimeLimitingCollector.this.timeout > 0L) {
            if (TimeLimitingCollector.this.greedy) {
                this.in.collect(doc);
            }

            throw new TimeLimitingCollector.TimeExceededException(TimeLimitingCollector.this.timeout - TimeLimitingCollector.this.t0, time - TimeLimitingCollector.this.t0, TimeLimitingCollector.this.docBase + doc);
        } else {
            this.in.collect(doc);
        }
    }
}

SolrQueryTimeoutImpl

如果参数设置了timeAllowed,还会设置一个SolrQueryTimeoutImpl

SearchHandler:

long timeAllowed = req.getParams().getLong(CommonParams.TIME_ALLOWED, -1L);
if (timeAllowed >= 0L) {
    SolrQueryTimeoutImpl.set(timeAllowed);
}

那么在执行reader在执行加载term的时候就会进行时间检查,超时则会抛出ExitingReaderException异常。

ExitableFilterAtomicReader:

/**
 * Throws {@link ExitingReaderException} if {@link QueryTimeout#shouldExit()} returns true,
 * or if {@link Thread#interrupted()} returns true.
 */
private void checkAndThrow() {
  if (queryTimeout.shouldExit()) {
    throw new ExitingReaderException("The request took too long to iterate over point values. Timeout: "
        + queryTimeout.toString()
        + ", PointValues=" + in
    );
  } else if (Thread.interrupted()) {
    throw new ExitingReaderException("Interrupted while iterating over point values. PointValues=" + in);
  }
}

主要是在IndexSearch.search方法中加载term的时候。

public void search(Query query, Collector results) throws IOException {
    query = rewrite(query);
    search(leafContexts, createWeight(query, results.scoreMode(), 1), results);
}

createWeight会调用

  1. IndexSearch.createNormalizedWeight
  2. TermQuery.createWeight
  3. TermContext.build
  4. ExitableTermsEnum 类所有过程会调用checkAndThrow检查超时。

TermContext.build方法:

 for (final LeafReaderContext ctx : context.leaves()) {
  final Terms terms = ctx.reader().terms(field);
  if (terms != null) {
    final TermsEnum termsEnum = terms.iterator();
    if (termsEnum.seekExact(bytes)) { 
      final TermState termState = termsEnum.termState();
      perReaderTermState.register(termState, ctx.ord, termsEnum.docFreq(), termsEnum.totalTermFreq());
    }
  }
}

召回阶段

如果召回阶段超时,抛出 ExitableDirectoryReader.ExitingReaderException 异常,在SearchHandler.handleRequestBody方法里会捕获这个异常,增加partialResults=trued的标识,并返回已经收集的结果。

rerank阶段

topCollector.topDocs

如果rerank阶段超时,由于ReRankCollector.topDocs捕获了所有异常,然后抛出SolrException,导致无结果

rerank有两处会排除ExitingReaderException异常。

1. scorer阶段
scorer = modelWeight.scorer(readerContext);

一般语法为正常的召回,都会在scorer阶段创建weight。同时加载term。

2. score阶段

一般是函数计算阶段发生term加载。例如:

FloatPayloadValueSource.getValues

public void reset() throws IOException {
    if (terms != null) {
        final TermsEnum termsEnum = terms.iterator();
        if (termsEnum.seekExact(indexedBytes)) {
            docs = termsEnum.postings(null, PostingsEnum.ALL);
        } else {
            docs = null;
        }
    } else {
        docs = null;
    }
    ...
}