你不会是程序猿吧?

timeout设置1ms,实际took:4ms以上响应正常数据并提示time_out:false

Elasticsearch | 作者 layseallone | 发布于2018年05月05日 | 阅读数:4025

各位好,如题,我设置了timeout但是毫无效果。就算设置成0或者0.1或更低值,实际结果都是响应正常并提示time_out:false。请问是什么原因呢?
 
还有一个问题,正常情况下,time_out如果返回true,但took那里还是显示的实际花费的时间,例如设置timeout为1ms,实际结果took:1000ms,time_out:true。这是不是意味着,虽然超时了不再等待后续响应数据了,但其实还是会等待执行完,不然这个实际花费1000ms是怎么来的?
QQ图片20180505174433.png
已邀请:

JackGe

赞同来自: CarrieJin rochy cccthought

dsl语句中的timeout值是针对lucene查询,见代码QueryPhase的execute方法片段
            //searchContext.timeoutInMillis()的值就是查询语句传入的timeout的值
final boolean timeoutSet = searchContext.timeoutInMillis() != SearchService.NO_TIMEOUT.millis();
if (timeoutSet && collector != null) { // collector might be null if no collection is actually needed
final Collector child = collector;
// TODO: change to use our own counter that uses the scheduler in ThreadPool
// throws TimeLimitingCollector.TimeExceededException when timeout has reached
collector = Lucene.wrapTimeLimitingCollector(collector, searchContext.timeEstimateCounter(), searchContext.timeoutInMillis());
if (doProfile) {
collector = new InternalProfileCollector(collector, CollectorResult.REASON_SEARCH_TIMEOUT,
Collections.singletonList((InternalProfileCollector) child));
}
}

try {
if (collector != null) {
if (doProfile) {
searchContext.getProfilers().getCurrent().setCollector((InternalProfileCollector) collector);
}
searcher.search(query, collector);
}
} catch (TimeLimitingCollector.TimeExceededException e) {
//如果查询超时searchTimedOut为true
assert timeoutSet : "TimeExceededException thrown even though timeout wasn't set";
queryResult.searchTimedOut(true);
} catch (Lucene.EarlyTerminationException e) {
assert terminateAfterSet : "EarlyTerminationException thrown even though terminateAfter wasn't set";
queryResult.terminatedEarly(true);
} finally {
searchContext.clearReleasables(SearchContext.Lifetime.COLLECTION);
}
SearchPhaseController的merge方法会合并结果,并得到是否超时
boolean timedOut = false;
Boolean terminatedEarly = null;
for (AtomicArray.Entry<? extends QuerySearchResultProvider> entry : queryResults) {
QuerySearchResult result = entry.value.queryResult();
if (result.searchTimedOut()) {
//只要其中一个shard查询超时,整个查询语句就超时
timedOut = true;
}
if (result.terminatedEarly() != null) {
if (terminatedEarly == null) {
terminatedEarly = result.terminatedEarly();
} else if (result.terminatedEarly()) {
terminatedEarly = true;
}
}
totalHits += result.topDocs().totalHits;
if (!Float.isNaN(result.topDocs().getMaxScore())) {
maxScore = Math.max(maxScore, result.topDocs().getMaxScore());
}
}
......
InternalSearchHits searchHits = new InternalSearchHits(hits.toArray(new InternalSearchHit[hits.size()]), totalHits, maxScore);

return new InternalSearchResponse(searchHits, aggregations, suggest, shardResults, timedOut, terminatedEarly);
至于took的计算是当AbstractAsyncAction对象实例化(TransportSearchAction类的doExecute方法),把当前系统时间作为startTime的值,在请求最终结束时System.currentTimeMillis() - startTime。took是es内部真正处理时间,但不包括在search bulk排队的时间和从你程序所在节点的网络交互时间。
 

总结:timeout为到毫秒的整数,最小为1ms。查询结果中timed_out为true则表明至少一个shard执行lucene query时超时,查询因超时而返回,该lucene query结果不完整。另一种设置超时方法为在cluster settings中设置search.default_search_timeout。

yayg2008

赞同来自: cccthought

这个实际上是你对timeout的理解问题,timeout指的是等待Lucence执行query的时间,超过这个时间如果当前shard没有返回数据则不再等待(该shard的query还是会继续执行),直接返回其他shard已经返回的数据(如果有)。而took是ES统计整个query所消耗的时间。两个衡量的不是同一个时间。

要回复问题请先登录注册