Elasticsearch 7.13.2 如何实现多字段组合的cardinality去重计数
Elasticsearch 多字段组合去重计数方案
问题背景
当前使用Elasticsearch 7.13.2版本,索引名为r2332,需要统计maid和date两个字段组合的唯一去重计数,原有两种实现方案均存在错误无法得到正确结果。
原有方案错误原因
- 运行时字段方案错误:
- 自定义的运行时字段名为
type_and_promoted,但cardinality聚合中错误填写字段值为runtime_mappings,没有指向正确的运行时字段 - 多余添加了
reverse_nested聚合,无嵌套文档场景下不需要该配置
- 自定义的运行时字段名为
- 脚本直接聚合方案错误:
- 脚本语法错误:
doc'date'].value缺失左方括号,正确写法为doc['date'].value date字段为date类型,直接拼接需要先转为字符串格式,避免类型不兼容报错
- 脚本语法错误:
正确实现方案
方案1:修正后的运行时字段方案
{ "size": 0, "query": { "bool": { "filter": [ { "terms": { "site_id": [7560, 7566] } }, { "range": { "date": { "gte": "2021-09-01", "lte": "2021-09-15" } } } ] } }, "runtime_mappings": { "maid_date_combine": { "type": "keyword", "script": """ // 先判断字段非空,避免空指针报错 if(doc['maid'].size()!=0 && doc['date'].size()!=0){ emit(doc['maid'].value + '#' + doc['date'].value.toString()) } """ } }, "aggs": { "group_by": { "terms": { "field": "site_id", "size": 100 }, "aggs": { "bydate": { "terms": { "field": "date", "size": 100 }, "aggs": { "byhour": { "terms": { "field": "hour", "size": 24 }, "aggs": { "uv": { "cardinality": { "field": "maid_date_combine" } } } } } } } } } }
方案2:修正后的cardinality直接使用脚本方案
{ "size": 0, "query": { "bool": { "filter": [ { "terms": { "site_id": [7560, 7566] } }, { "range": { "date": { "gte": "2021-09-01", "lte": "2021-09-15" } } } ] } }, "aggs": { "group_by": { "terms": { "field": "site_id", "size": 100 }, "aggs": { "bydate": { "terms": { "field": "date", "size": 100 }, "aggs": { "byhour": { "terms": { "field": "hour", "size": 24 }, "aggs": { "uv": { "cardinality": { "script": { "source": """ if(doc['maid'].size()!=0 && doc['date'].size()!=0){ return doc['maid'].value + '#' + doc['date'].value.toString(); } return ""; """ } } } } } } } } } } }
注意事项
- 如果对去重计数的精度要求极高,可以调整
cardinality聚合的precision_threshold参数,最高可设置为40000,低于该阈值的去重计数误差接近0 - 如果该统计是高频查询,建议在数据写入时提前拼接好maid和date的组合字段存入索引,查询性能远高于运行时计算和脚本计算
内容的提问来源于stack exchange,提问作者Apricot
相关产品推荐
相关产品推荐

