第五阶段 45 · percentiles 与 cardinality 精度(近似聚合的真相)
2026/8/5 8:25:44 网站建设 项目流程

45 · percentiles 与 cardinality 精度(近似聚合的真相)

阶段:第五阶段 / 进阶(第 20 篇指标聚合的深入)
ES:percentiles/percentile_ranks/cardinality| PostgreSQL:percentile_cont/COUNT(DISTINCT)


1. 概念:ES 的分位数和去重计数是“近似”的

为了在海量数据、多分片下还能快,ES 用了近似算法:

聚合算法特点
cardinality(去重计数)HyperLogLog++内存固定,有误差(可控)
percentiles(分位数)TDigest(或 HDR)极值附近更准,中间近似

它们不是精确值。数据量小时几乎无差,量大时要理解误差来源,别当精确数用于对账。


2. PostgreSQL 对照

-- 精确分位数(PG 精确,ES 近似)SELECTpercentile_cont(0.95)WITHINGROUP(ORDERBYlatency)FROMreq;-- 精确去重(PG 精确,ES cardinality 近似)SELECTCOUNT(DISTINCTuser_id)FROMreq;

PG 是精确计算;ES 用近似换性能。要精确去重且量不大,可用terms桶数或 composite。


3. ES DSL

3.1 percentiles(分位数)

GET req_idx/_search { "size": 0, "aggs": { "latency_pct": { "percentiles": { "field": "latency_ms", "percents": [50, 90, 95, 99] } } } }

3.2 percentile_ranks(反查:某值排在第几百分位)

"aggs": { "rank": { "percentile_ranks": { "field": "latency_ms", "values": [200, 500] } } }

3.3 cardinality(近似去重)+ 精度阈值

"aggs": { "uv": { "cardinality": { "field": "user_id", "precision_threshold": 3000 } } }

precision_threshold:低于此基数时几乎精确,越大越准但越占内存(上限 40000)。


4. Spring Boot 实现

@ComponentpublicclassDoc45Percentiles{@AutowiredprivateElasticsearchClientelasticsearchClient;/** P50/P90/P95/P99 延迟 */publicMap<String,Double>latencyPercentiles(StringindexName)throwsIOException{SearchResponse<Void>resp=elasticsearchClient.search(s->s.index(indexName).size(0).aggregations("pct",a->a.percentiles(p->p.field("latency_ms").percents(50.0,90.0,95.0,99.0))),Void.class);// percentiles 结果是 key(分位)->value(值) 的 mapreturnresp.aggregations().get("pct").tdigestPercentiles().values().keyed();}/** 近似 UV,指定精度阈值 */publiclongapproxUv(StringindexName)throwsIOException{SearchResponse<Void>resp=elasticsearchClient.search(s->s.index(indexName).size(0).aggregations("uv",a->a.cardinality(c->c.field("user_id").precisionThreshold(3000))),Void.class);returnresp.aggregations().get("uv").cardinality().value();}}

percentiles 默认 TDigest,读取用.tdigestPercentiles();用 HDR 时读.hdrPercentiles()
keyed()返回Map<String,Double>(key 是 “95.0” 这样的字符串)。


5. 坑与最佳实践

  1. 近似 ≠ 精确cardinality/percentiles别用于财务对账等要求精确的场景。
  2. cardinalityprecision_threshold:按可接受误差和内存权衡,别无脑拉满。
  3. percentiles 极值更准:P99/P1 比 P50 更可靠,这是 TDigest 的特性。
  4. 高延迟要 P99 而非 avg:平均值会被掩盖,SLO 看高分位。
  5. 要精确去重:小基数用terms桶计数;大基数只能接受近似或离线精确算。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询