官方文档
https://solr.apache.org/guide/8_6/result-grouping.html
功能描述
近似于facet, 相当于facet结果的每个桶里追加上几个桶内的文档.
几个关键点
- 分桶字段(group.field)
- 关于桶的设置
- 返回桶的最大数量(rows)
- 桶的排序方式(sort)
- 关于每个桶返回文档的设置
- 桶内返回文档的最大数量(group.limit)
- 桶内文档的排序方式(group.sort)
- 桶内文档返回哪些字段 (fl)
执行过程
分两阶段执行:
阶段1: 确定返回哪些桶, 以及桶的排序. 桶的排序只与sort参数有关, group.sort阶段1不会用到.
阶段2: 给每个桶补充文档.
阶段1
数据节点
Query: 原始查询q.
Collector: FirstPassGroupingCollector
数据节点在阶段1获取自己shard内的Top N个桶(也称为group).
可以看成是先把group.field的所有取值values枚举出来, 生成N个桶, 每个桶代表一个值value. 如果一个文档的group.field取值为value, 那么他就被装到值为value的桶里.
每个桶有一个sortValue, 这个sortValue就是桶内所有文档的最佳排序值. 比如说sort=score desc, 那么每个桶的排序值就是桶内所有文档得分取max. 比如说sort=field1 asc, 那么每个桶的排序值就是桶内所有文档的field1字段值取min.
然后所有的桶根据sort方式, 按照桶的排序值排序, 取 Top rows个, 就得到了最终要返回桶的列表.
协调节点
Merge处理器: SearchGroupShardResponseProcessor.
每个shard返回自己的Top N个group时, 每个group会带上其最佳文档排序值(即sortValue).
协调节点对多个shard返回的桶列表做合并, 把每个数据节点返回的 Top N个桶最终合并为全局的Top N个桶.
合并的时候也是根据sort排序方式和每个桶的最佳文档排序值作为根据.
综合数据节点和协调节点的处理可以看出, 最终返回桶的列表只和group.field, rows, sort 3个参数有关.
阶段2
数据节点
Query: 原始查询q.
Collector: TopGroupsCollector(extends SecondPassGroupingCollector)
核心逻辑就是给每个桶创建一个collector, collector的numHits设置为group.limit, collector的排序方式是group.sort. 用查询q重新查一遍, 每个文档先获取其group.field值, 根据值可以确定当前文档属于哪个桶, 然后把这个文档加入该桶(在每个桶内是以group.sort方式给所有文档排序的, 最终每个桶取Top group.limit 个文档.).
协调节点
Merge处理器: TopGroupsShardResponseProcessor.
这块源码没细看, 猜也能猜到:
应该以group为粒度合并多个shard返回的文档列表. 具体的合并逻辑就和正常搜索合并多个shard的文档列表一样的, 无非是每个group下的文档列表单独走一遍合并逻辑.