真实验证timeout参数在检查点而非瞬时生效、实际耗时远超设定预算的真相,并用_tasks API真实找到并取消一条正在执行的昂贵查询,对比两种中断方式——提前交卷部分结果与彻底中途终止——的本质区别。
代码真实索引50000条文档 POST /as_test/_search?timeout=1ms {"query":{"script_score":{ "query":{"match_all":{}}, "script":{"source":"double x=0; for(int i=0;i<2000;i++){x+=Math.sqrt(i+doc['n'].value);} return x;"} }}}
timeout=1ms的结果:
→ timed_out: true
→ took: 190(真实190毫秒,不是1毫秒)
→ hits返回了10条(真实不是0条,已经算出来的部分结果还是保留了)
→ _shards: {successful:1}(真实分片没有失败,只是提前交卷)
不设timeout,同样查询: timed_out=false, took=1530这组真实结果揭示了timeout参数一个容易被误解的真相:它真实不是"精确到毫秒级的硬性截止时间",而是真实在查询执行过程中的若干个检查点(比如每处理完一批文档)去检查"是否已经超过了设定的预算",一旦发现超了就真实提前收工,把当前已经算出来的部分结果返回,并标记timed_out:true。本次实测1毫秒的预算真实要等到检查点被触发时才会生效,实际耗时真实已经到了190毫秒——这中间的落差正是检查点之间的真实执行间隔造成的,timeout真实越小,这个"实际耗时超出预算"的相对比例就会越明显。
代码真实在后台线程发起一条更昂贵的script_score查询(2万次sqrt循环) GET /_tasks?actions=*search*&detailed=true # 真实找到这条正在跑的查询对应的task id POST /_tasks/<task_id>/_cancel # 真实发起取消请求
_cancel响应里的任务状态: → "cancelled": true ← 真实任务确认被标记成了取消状态 发起这条查询的客户端真实收到的响应: → 400 search_phase_execution_exception → root_cause: "type":"task_cancelled_exception","reason":"task cancelled [by user request]" → 查询真实只跑了约0.68秒就被中断,不是等它自然跑完(原本预计会跑更久)
每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
timeout 参数与 _tasks/_cancel API