在Kylin中使用distinct_count

#refer: http://kylin.apache.org/blog/2016/08/01/count-distinct-in-kylin/

在OLAP多维分析中,Count Distinct(去重计数)是一种非常常用的指标度量,比如一段时间内的UV、活跃用户数等等;从1.5.3开始,Apache Kylin提供了两种Count Distinct计算方式,一种是近似的,一种是精确的,精确的Count Distinct指标在Build时候会消耗更多的资源(内存和存储),Build的过程也比较慢;

近似Count Distinct

Apache Kylin使用HyperLogLog算法实现了近似Count Distinct,提供了错误率从9.75%到1.22%几种精度供选择;算法计算后的Count Distinct指标,理论上,结果最大只有64KB,最低的错误率是1.22%;
这种实现方式用在需要快速计算、节省存储空间,并且能接受错误率的Count Distinct指标计算。

精准Count Distinct

从1.5.3版本开始,Kylin中实现了基于bitmap的精确Count Distinct计算方式。当数据类型为tiny int(byte)、small int(short)以及int,会直接将数据值映射到bitmap中;当数据类型为long,string或者其他,则需要将数据值以字符串形式编码成dict(字典),再将字典ID映射到bitmap;指标计算后的结果,并不是计数后的值,而是包含了序列化值的bitmap。这样才能确保在任意维度上的Count Distinct结果是正确的。
这种实现方式提供了精确的无错误的Count Distinct结果,但是需要更多的存储资源,如果数据中的不重复值超过百万,结果所占的存储应该会达到几百MB。

全局字典(Global Dictionary)

默认情况下,Kylin在每个Segment中,将数据值编码到一个字典中,同一个数据值,在不同Segment中编码后的ID值也是不同的,因此在这跨两个Segment中进行Count Distinct计算时候,结果是不正确的;在1.5.3版本中,Kylin引进了”Global Dictionary”,用来确保同一个数据值编码后的ID值始终是相同的,与此同时,字典的容量也进行了扩充,一个字典的最大容量达到了20亿,之前默认的字典最大容量为500万。全局字典可以代替之前的默认字典。
当前版本1.5.3的UI中,没有提供定义全局字典的地方,需要手动修改Cube的json。

"dictionaries": [
    {
       "column": "SUCPAY_USERID",
       "reuse": "USER_ID",
       "builder": "org.apache.kylin.dict.GlobalDictionaryBuilder"
    }
]

“column”是需要编码(进行Count Distinct计算)的字段,”builder”指定了字典的builder类,目前只能是”org.apache.kylin.dict.GlobalDictionaryBuilder”。
“reuse”是用来优化字典的,当多个字段的值是同一个数据集的时候,指定复用同一个字典即可,不需要再建立字典,后面会详细说明。

#全局字典不能用在维度的编码中,如果一个字段即是维度,又是Count Distinct指标,那么就需要在Model定义中为维度指定其他的编码方式,比如dict编码方式。

#

#性能优化

全局字典是比较大的,在Build时候,”Build Base Cuboid Data”这一步会消耗较长时间。
如果字典大小超过Mapper的内存大小时候,字典需要消耗大量时间在缓存加载和回收上,解决该问题的办法是修改Cube的参数,适当增大Mapper使用的内存:
kylin.job.mr.config.override.mapred.map.child.java.opts=-Xmx8g
kylin.job.mr.config.override.mapreduce.map.memory.mb=8500

总结

选择哪种Count Distinct计算方式呢?
1. 如果能接受1.22%以内的误差,近似计算肯定是最好的方式;
2. 如果业务需要精确去重计数,那么肯定得选择精确Count Distinct;
3. 如果不需要跨Segment(天)的去重,或者字段值是tinyint/smallint/int, 或者字段去重后的值小于500万,那么就是用默认字典;否则,就需要配置全局字典,同时,如果可以,则是用”reuse”来进行优化。

#

你可能感兴趣的:(在Kylin中使用distinct_count)