Keyviz:实时键鼠可视化工具终极指南 - 让操作透明化的专业解决方案
2026/6/9 18:56:54
profile API 把一次查询在 Coordinator 节点和每个 Shard 上的执行过程拆成可读的“时间线”与“调用树”,粒度到 Lucene 的 Weight→Scorer→BulkScorer→TwoPhaseIterator。返回 JSON 里包含:
query数组:每个 Shard 的 rewrite、create_weight、build_scorer、next_doc、advance、match 等阶段耗时(单位 ns)collector数组:TopScoreDocCollector、TopDocsCollector 的 reduce 时间、收集文档数、提前结束(early_termination)次数children嵌套:布尔查询的 should/must/filter 子句各自耗时,可一眼定位“慢子句”breakdown明细:底层统计,如set_min_competitive_score调用次数,用于判断是否真的触发了 WAND 优化不能看的:
"profile": trueSearchRequestreq=SearchRequest.of(b->b.index("shop").query(q->q.term(t->t.field("brand").value("sony"))).profile(true));SearchResponse<Map>resp=client.search(req,Map.class);resp.profile().shards().forEach(shard->{shard.searches().forEach(s->s.query().forEach(q->{System.out.println(q.type()+" "+q.timeInNanos());}));});场景:商品索引 1.2 亿 doc,查询“品牌=sony 且 上架时间≥now-7d”,响应 2.3 s。
profile 片段(已换算 ms):
"query":[{"type":"BooleanQuery","time":"1934.2ms","breakdown":{"build_scorer":1821ms,"next_doc":78ms,"advance":12ms},"children":[{"type":"TermQuery@brand","time":"41ms"},{"type":"RangeQuery@onShelfTime","time":"1890ms"}]}]结论:
Elasticsearch 默认使用“Query Then Fetch”(QTF):
问题:当 Shard 之间 TF-IDF 统计差异大时,局部分数不可比,导致“好文档”被提前截断。典型症状:副本数越多、数据越倾斜,同一查询的 Top10 结果在不同副本上不一致。
DFS query_then_fetch(DFS=Distributed Frequency Search)在 Query 前增加一轮“广播收集”:
代价:两次 RPC,多一轮序列化;若查询包含大量高基数字段,DFS 报文体可能膨胀到几十 MB,Coordinator 节点网络与内存压力骤增。
推荐打开的场景:
不建议打开:
profile 返回根节点新增dfs段:
"dfs":{"time_in_nanos":842000000,"statistics":{"term_count":3,"df_fetch_count":15}}若 DFS 时间占比 > 30% 且 term_count 很小,说明分片之间全局统计差异大,可继续保留 DFS;若 term_count 上千,DFS 时间反而超过 Query 阶段,就应考虑: