真实验证collapse按字段分组保留每组最优结果、不影响hits.total总数的行为,验证它对text字段的硬性限制,并用inner_hits把每组被折叠掉的详情文档重新展开取回。
代码真实索引6篇文章: alice写了3篇, bob写了2篇, carol写了1篇 POST /cl_test/_search {"query":{"match":{"title":"elasticsearch"}},"sort":[{"date":"desc"}]} POST /cl_test/_search {"query":{"match":{"title":"elasticsearch"}},"collapse":{"field":"author"},"sort":[{"date":"desc"}]}
不加collapse: 真实返回全部6条命中,alice出现3次,bob出现2次,carol出现1次 加collapse(field=author): → hits.total = 6 ← 真实没有跟着收窄,依然是完整的6 → 返回的文档数: 3条 alice "elasticsearch guide part 3"(真实alice 3篇里日期最新的那篇) bob "elasticsearch basics"(真实bob 2篇里日期最新的那篇) carol "elasticsearch deep dive"(真实carol唯一的一篇)
这组真实结果验证了collapse的核心行为:它真实按指定字段对命中结果做分组,每组真实只保留排序最靠前的那一条,就像SQL里的GROUP BY加上取每组第一条记录。本次实测真实按date desc排序,所以每位作者真实保留的都是日期最新的那篇文章。值得注意的是hits.total真实依然精确反映原始匹配的6条记录,不会因为collapse把展示结果收窄到3条就跟着变成3——这跟本系列前面验证过的post_filter有相似之处,都是"只影响最终返回的文档,不影响底层匹配总数"。
代码POST /cl_test/_search {"query":{"match_all":{}},"collapse":{"field":"title"}} # title是text类型
→ "collapse is not supported for the field [title] of the type [text]"
这条真实报错说明collapse底层真实依赖字段的doc_values结构来做分组(跟聚合依赖的底层存储结构类似),text类型字段默认真实不开启doc_values(本系列第13篇验证过text字段的index/doc_values/store开关),所以真实没法直接拿它做collapse分组。这也是为什么本次实测分组用的是author这个keyword字段——collapse真实只支持keyword、数值、日期这类天生带doc_values的字段类型。
代码POST /cl_test/_search {"query":{"match":{"title":"elasticsearch"}}, "collapse":{"field":"author","inner_hits":{"name":"top_docs","size":2,"sort":[{"date":"desc"}]}}, "sort":[{"date":"desc"}]}
alice 顶层结果: "elasticsearch guide part 3" inner_hits: "elasticsearch guide part 3", "elasticsearch guide part 2" bob 顶层结果: "elasticsearch basics" inner_hits: "elasticsearch basics", "elasticsearch tutorial" carol 顶层结果: "elasticsearch deep dive" inner_hits: "elasticsearch deep dive"(carol真实只有这一篇,没有第二条)
每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
collapse 与 inner_hits API