连载中 11/20

聚合:把搜索页变成数据分析页

2026-08-15 · 1047 阅读 · 0 评论 · 0 赞

运营的报表需求来了

搜索和翻页都稳了,运营的周会材料升级成数据分析:各品牌有多少商品、均价多少;商品价格分几个段卖得好;上架量按月什么趋势。老王原计划写定时任务导 MySQL 慢慢算,同事提了一句:ES 的聚合(aggregation)就是干这个的。搜索靠倒排,聚合靠正排,第 2 篇埋的 doc values 伏笔,这篇开始收利息。

两大家族:分桶与指标

聚合就两个家族。分桶(bucket)负责「把文档按规则扔进格子」:按品牌扔、按价格段扔、按月份扔;指标(metric)负责「对每个格子算数」:算平均价、总销量、最大值。两者嵌套起来,就是一张报表:

GET /product/_search
{
  "size": 0,
  "aggs": {
    "brands": {
      "terms": { "field": "brand.keyword", "size": 10 },
      "aggs": {
        "avg_price": { "avg": { "field": "price" } },
        "total_sales": { "sum": { "field": "sales" } }
      }
    }
  }
}

terms 按品牌分桶,桶里再嵌 avg 和 sum 两个指标,一次请求拿回「前十品牌加各自均价销量」。size 设 0 是关键细节:只要聚合结果,不要命中文档,省掉整个返回文档的开销。聚合和 query 可以同台:query 先筛出「上架商品」,aggs 只在这个结果集里统计——先过滤后聚合,这本身就是个常用模式。

价格段、时间轴与去重

价格段分布用 range 聚合,边界自己画:

"price_bands": {
  "range": {
    "field": "price",
    "ranges": [
      { "to": 10 }, { "from": 10, "to": 50 }, { "from": 50 }
    ]
  }
}

上架趋势用 date_histogram,按月分桶自动处理大小月和时区,桶里嵌 terms 看每月哪个品类卖得多,一张运营驾驶舱的骨架就出来了。想知道「有多少个不同品牌」用 cardinality 做去重计数——注意它是近似算法,亿级数据下误差在百分之一内,报表够用,财务对账就别用它。还有一族 pipeline 聚合能在聚合结果上再算数(比如算环比),进阶需求再碰。

聚合字段用 keyword,别用 text

老王顺手想对 name 聚合,ES 报错提醒 Fielddata is disabled——这就是第 5 篇那笔账的后续。规则:terms 聚合认词条,text 字段的词条是切碎的,聚出来的桶没有业务意义(按「燕」「麦」分桶毫无用处)。所以字符串聚合一律走 keyword 子字段:brand.keyword、tags.keyword。ES 报错其实是在拦你,真要用 text 聚合可以打开 fielddata,但那会把切碎的词条全装进堆内存,属于自残操作,别开。

性能上再记两条:聚合走的是 doc values 正排(列式存储,第 2 篇讲过),不算分不走倒排,所以聚合天然快;terms 的 size 别贪大,一次拉一千个桶,正排扫描和返回体积都跟着涨,报表页先问自己真的要看前一千个品牌吗。

小结

聚合一句话:bucket 分格子,metric 算格子,先 query 过滤再 aggs 统计,字符串聚合走 keyword,去重计数是近似值。运营的周会报表,从此一条 API 请求搞定。

读和查都顺了,老王开始关心写:商品同步的高峰期,bulk 写入把集群 CPU 干到报警。下一篇讲写入调优:bulk 批量、副本与刷新的写入三角,让导入快五倍的实操清单。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#Elasticsearch#聚合#terms#range#date_histogram

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10101 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9873 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9294 阅读 · 21 评论 · 287 赞