在大数据分析中,对数据进行计数去重是比较常见的需求,而druid.io中提供了多种去重计数的aggregtions函数,对于这些去重的aggregtions也不尽相同。druid中提供的去重aggregation如下:
1、DataSketches aggregtions :
yahoo提供的分析包,此算法也是采用最大估计的算法,在数据摄入阶段(ingestion time),druid会存储sketch 相关数据,在query查询阶段,查询效率也可以更快,此hyperloglog准确一些,速度也快一点。
简单配置说明:
"metricsSpec": [
{
"name" : "count",
"type" : "count"
},
{
"name":"sketch_deviceid",
"type":"thetaSketch",
"fieldName":"deviceid",
"isInputThetaSketch":"false",
"size":"16384"
}
],
query阶段:
"aggregations": [
{
"type": "longSum",
"name": "count",
"fieldName": "count"
},
{
"type" : "thetaSketch",
"name": "sketch_success",
"fieldName" : "sketch_deviceid"
}
]
官方参考文档:http://druid.io/docs/latest/development/extensions-core/datasketches-aggregators.html
2、HyperUnique aggregtions:
利用HyperLogLog计算估计值,结果为小数,但需要在indexing time阶段加入“hyperUnique” metric 以支持此aggregation。在摄入阶段进行优化,比Cardinality aggregtions聚合效率要高。
官方参考文档: http://druid.io/docs/latest/querying/aggregations
3、Cardinality aggregtions :
基于HyperLogLog算法,只在查询阶段做了优化,不能减少存储容量,基数大时,效率可能会有问题。
由于在metabase 中对druid数据源采用的是Cardinality aggregtions,所以重点研究了一下。
首先Cardinality aggregtions结果返回值也为估算值小数,在metabase中对于Cardinality 的postaggregation是错误的,是个bug,对于cardinality和hyperUnique的聚合, post-aggregator type 的类型为“finalizingFieldAccess”,而非“fieldAccess”,采用fieldAccess type的话,查询会报 java.lang.ClassCastException 。正确的写法如下:
{ "queryType":"timeseries",
"dataSource": "out-tvs-timeon.behavior",
"granularity":{"type":"period","period":"P1D","timeZone":"UTC"},
"context":{"timeout":60000,"queryId":"2f8cd622-0aca-48a7-8945-f21f869a2886"} ,
"descending": "true",
"aggregations": [
{ "type": "count", "name": "___COUNT_209" },
{ "type": "cardinality", "name": "___DISTINCT_210", "fields": ["session_id"],"round":"true" }
],
"postAggregations": [
{ "type": "arithmetic",
"name": "sample_divide",
"fn": "/",
"fields": [
{ "type": "fieldAccess","name":"___COUNT_2091","fieldName": "___COUNT_209" },
{ "type": "finalizingFieldAccess","name":"___DISTINCT_2101","fieldName": "___DISTINCT_210"}
]
}],
"intervals": ["2018-07-22T00:00:00.000Z/2018-08-23T00:00:00.000Z"]
}
注意并且当在druid的0.10版本中,上述查询会出现“finalizingFieldAccess not recoginez”,此错误为druid的0.10版本的bug,将druid的版本升级至0.12版本即可。
类似,druid已支持简单的SQL查询,但在0.10上不支持,需升级druid至0.12
4、druid-distinctCount:
第三方community extensions包,结果为整数。效率还未大数据量测试。
首先需要到maven仓库下载对应druid版本的jar,并druid中的extensions目录下,并建立druid-distinctcount,将jar复制到目录下,并在druid 的common.runtime.properties中添加此extension的配置
druid.extensions.loadList=["mysql-metadata-storage", "druid-hdfs-storage","druid-kafka-indexing-service","kafka-emitter","druid-datasketches","druid-distinctcount"]
重启druid即可。
但是distinctCount 存在较大的误差,有时候会出现错误,其具有较多限制,也不适合生产环境使用。具体可参照官网
http://druid.io/docs/latest/development/extensions-contrib/distinctcount.html
去重计数聚合函数 | cardinality aggregator | HyperLogLog | 1、RSE标准差: 1.04/sqrt(m) m an auxiliary memory of m units (typically, “short bytes”) 2、e.g:10^9 with a typical accuracy of 2% while using a memory of only 1.5 kilobytes |
1:datasketches的基数运算比HyperLogLog丰富:支持集合的交、并、补运算。 2:datasketches使用扩展插件实现,HyperUnique为内置功能。 3:datasketches精度高于HyperLoglog,并且可以进行灵活的参数调整。 |
1、此聚合函数比hyperUnique aggregator要慢,官方建立此采用hyperUnique aggregator 2、提供了round配置可提供数值型,但经测试round不起作用 3、druid未提供关于调优参数 m的参数配置 4、只在查询阶段进行优化 |
HyperUnique aggregator | HyperLogLog | 1:在druid接入时,需添加“hyperUnique” metric { "type" : "hyperUnique", "name" : "fieldName" : "isInputHyperUnique" : false, "round" : false } 2:数据druid接入和查询均做了优化 |
|||
DataSketches aggregator | datasketches | 1、RSE标准差: < 1/√ k - 1 sketch size of k Thus, the confidence level (the fractional area) between +1 RSE (+1 SD) and -1 RSE (-1 SD) is 68.27%. Similarly, the confidence level between +2 RSE (+2 SD) and -2 RSE (-2 SD) is 95.4% 2、参考文档:https://datasketches.github.io/docs/Theta/ThetaAccuracy.html |
1:在druid接入时,需添加添加“thetaSketch” { "type":"thetaSketch", "name":"theta_pdid", "fieldName":"pdid" } 2:数据druid接入和查询均做了优化 3:可灵活调精度参数 |
||
DistinctCount aggregator | 未知 | 前提: 1:必须保证相同某个dimension的值存储到相同的segments中。 2:必须保证queryGranularity 能被segmentGranularity 整除 限制: 1:groupBy keys的数量不能超过 maxIntermediateRows ,否则结果错误 2:当用到topN时,numValuesPerPass 不能太大,否则会内存溢出。 |
|||
测试结论: 采用thetaSketch,并根据实际数据进行参数的调整优化以达到较高精度 |
1、datasketches 对空不计数,HyperLogLog则对空计数 2、datasketch返回为整数,HyperLogLog返回为15小数。 3、datasketch可调整参数提高计数精度,而HyperLogLog未提供参数优化 |
||||
维度 | 结果 | 误差 | |||
{ "queryType":"timeseries", "dataSource": "out_timeon_behavior_merge_t", "intervals": ["2018-10-09T00:00:00.000Z/2018-10-09T09:00:00.000Z"] } thetaSketch: size: 16384 |
page_session | groupby :342 | |||
cardinality:344.40075465357125 | 2.4 | ||||
thetaSketch:342.0 | 0 | ||||
pdid | groupby : 1407 | ||||
cardinality: 1401.6440668974283 7.4 | 7.4 | ||||
thetaSketch:1407.0 | 0 | ||||
session_id | groupby : 1439 | ||||
cardinality: 1405.613060387714 | 34 | ||||
thetaSketch:1438 | 1,其中有一个session_id为空 | ||||
page_id | groupby : 30969 | ||||
cardinality: 31643.23982223063 | 674 2% | ||||
thetaSketch:30798.883625510232 | 171 0.5% | ||||
{ "queryType":"timeseries", "dataSource": "out_timeon_behavior_merge_t", "intervals": ["2018-10-09T00:00:00.000Z/2018-10-09T09:00:00.000Z"] } thetaSketch: size: 16384*2 |
page_id | groupby : 30969 | |||
cardinality: 31643.23982223063 | 674 2% | ||||
thetaSketch:30969.0 | 0 0% |
综合上述分析,DataSketches 和HyperUnique的聚合效率要比cardinality的高,两者在ingestion 阶段就做了相关优化,druid并提供了DataSketches 参数调整的参数,可通过调参来调整算法的准确度,cardinality的效率较前两者较低,误差与HyperUnique一样,大约在2%左右,druid-distinctCount的聚合结果为整数,但是存在较多限制和误差的问题,不易采用,并且在大数据量的效率如何还需验证。DataSketches为最优选择。