关于timeAllowed
TimeLimitingCollector
TimeLimitingCollector的getLeafCollector方法返回一个FilterLeafCollector对象,在collect每个doc的时候判断是否超时:
代码语言:txt复制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:
代码语言:txt复制long timeAllowed = req.getParams().getLong(CommonParams.TIME_ALLOWED, -1L);
if (timeAllowed >= 0L) {
SolrQueryTimeoutImpl.set(timeAllowed);
}
那么在执行reader在执行加载term的时候就会进行时间检查,超时则会抛出ExitingReaderException异常。
ExitableFilterAtomicReader:
代码语言:txt复制/**
* 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的时候。
代码语言:txt复制public void search(Query query, Collector results) throws IOException {
query = rewrite(query);
search(leafContexts, createWeight(query, results.scoreMode(), 1), results);
}
createWeight会调用
IndexSearch.createNormalizedWeight
TermQuery.createWeight
TermContext.build
ExitableTermsEnum
类所有过程会调用checkAndThrow检查超时。
TermContext.build方法:
代码语言:txt复制 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阶段
代码语言:txt复制scorer = modelWeight.scorer(readerContext);
一般语法为正常的召回,都会在scorer阶段创建weight。同时加载term。
2. score阶段
一般是函数计算阶段发生term加载。例如:
FloatPayloadValueSource.getValues
代码语言:txt复制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;
}
...
}