24 · filter / filters 桶聚合
阶段:第三阶段 / 聚合能力
ES:
filter/filtersagg | PostgreSQL:COUNT(*) FILTER (WHERE ...)
1. 概念
filter聚合:只对满足某条件的文档 做子聚合,相当于 SQL 的FILTER (WHERE ...)。filters聚合(复数):一次定义多个命名条件桶 ,各自统计,
相当于在一个查询里同时算多个FILTER分类。
2. PostgreSQL 对照
sql
-- 一次查询里分别统计不同条件
SELECT
COUNT(*) FILTER (WHERE geo_cd = 'AP') AS ap_cnt,
COUNT(*) FILTER (WHERE geo_cd = 'EMEA') AS emea_cnt,
SUM(net_amount) FILTER (WHERE net_amount > 1000) AS big_total
FROM salesdata;
3. ES DSL
单条件 filter
GET salesdata_idx/_search
{
"size": 0,
"aggs": {
"big_orders": {
"filter": { "range": { "net_amount": { "gt": 1000 } } },
"aggs": {
"total": { "sum": { "field": "net_amount" } }
}
}
}
}
多命名桶 filters
GET salesdata_idx/_search
{
"size": 0,
"aggs": {
"by_geo_group": {
"filters": {
"filters": {
"ap": { "term": { "geo_cd": "AP" } },
"emea": { "term": { "geo_cd": "EMEA" } }
}
},
"aggs": {
"total": { "sum": { "field": "net_amount" } }
}
}
}
}
返回 ap / emea 两个命名桶,各带 doc_count 和子聚合。
4. Spring Boot 实现
java
@Component
public class Doc24FilterAgg {
@Autowired
private ElasticsearchClient elasticsearchClient;
/** 多命名条件桶:分别统计各 geo 的金额 */
public Map<String, Double> totalByNamedGeo(String indexName) throws IOException {
Map<String, Query> named = Map.of(
"ap", Query.of(q -> q.term(t -> t.field("geo_cd").value("AP"))),
"emea", Query.of(q -> q.term(t -> t.field("geo_cd").value("EMEA"))));
SearchResponse<Void> resp = elasticsearchClient.search(s -> s
.index(indexName)
.size(0)
.aggregations("by_geo_group", a -> a
.filters(f -> f.filters(fl -> fl.keyed(named)))
.aggregations("total", sub -> sub.sum(su -> su.field("net_amount")))),
Void.class);
Map<String, Double> result = new LinkedHashMap<>();
var buckets = resp.aggregations().get("by_geo_group").filters().buckets().keyed();
buckets.forEach((name, bucket) ->
result.put(name, bucket.aggregations().get("total").sum().value()));
return result;
}
}
import:
co.elastic.clients.elasticsearch._types.query_dsl.Query。命名(keyed)桶用
.buckets().keyed()取到Map<String, Bucket>。
5. 坑与最佳实践
filtervsquery:filter聚合作用在聚合层,query作用在整个搜索层;
只想影响某个子统计用filter聚合。filters的other_bucket:可开启other_bucket收集不匹配任何条件的文档。- keyed 结果更好读:用命名桶(keyed)比匿名数组桶更方便取值。
- 条件多时性能:每个 filter 都要过一遍,条件极多时注意开销。
- 组合 bool :filter 里可以放
bool,实现复杂多条件分类。
阶段小结
第三阶段完成后,你应该能把常见 SQL 聚合翻译成 ES:
GROUP BY→terms、date_trunc→date_histogram、多级分组→嵌套子聚合、
FILTER (WHERE ...)→filter/filters。
下一篇
27-pipeline-管道聚合.md(对聚合结果再算一层:累计/环比/移动平均)。