嘿~ 今天天气不错嘛

ElasticSearch 5.2 查询 先分组,再聚合?

Elasticsearch | 作者 Charles | 发布于2017年05月03日 | 阅读数:7964

要实现一个这样的功能,通话记录表(CallRecords )有 UserId, 电话号码(PhoneNumber )等字段,现在要统计每个号码有多少个用户联系过(主叫或被叫), 每个用户对一个号码有多次联系
SQL 是这个样子
select   count( PhoneNumber )   from  (select   UserId,  PhoneNumber   from CallRecords group by UserId,  PhoneNumber) 
 
用ES如何写?在线求啊
已邀请:

kennywu76 - Wood

赞同来自: Charles

ES里最接近的实现是对userid做terms aggregation,然后内层嵌套对phonenumber做cardinality aggregation
POST callrecords/_search
{
"size": 0,
"aggs": {
"top_users": {
"terms": {
"field": "userid",
"size": 10
},
"aggs": {
"phonenum_cnt": {
"cardinality": {
"field": "phonenum",
"precision_threshold": 40000
}
}
}
}
}
}
其中外层的"size"控制返回多少个userID,如果userID非常多的话(例如上百万,千万 ),就要注意避免将这个值对应设置那么大,否则因为返回的bucket过多导致内存溢出。
内层的cardinality聚合是近似计算,其中"precision_threshold"设置越大,结果误差越小,但是内存消耗也越大。 这个参数最大值是40000。
 
总结来说,ES的terms aggs只适合对low cardinality的字段来计算,并且只适合返回top N bucket (最新版的ES也开始支持对high cardinality字段做全量计算了,需要借助于partition特性,参考https://www.elastic.co/guide/e ... tions  )。 
 
而cardinality aggs只是近似计算,如果可以接受一定的误差就可以用。否则如果需要精确计算,则需要考虑使用其他非ES方案。

要回复问题请先登录注册