1.hive的源码distinct与groupby的区别是什么?
2.开发实战角度:distinct实现原理及具体优化总结
3.Hive常ç¨ç®åå®ç°åçç®è¿°--MapReduceç
4.HIVE-SQL优化(持续更新ing)
5.Hiveä¼åçåååè
6.通过深挖Clickhouse源码,我精通了数据去重!源码
hive的源码distinct与groupby的区别是什么?
理解Hive中的DISTINCT与GROUP BY功能,需从它们各自的源码核心作用入手。DISTINCT功能旨在去除结果集中的源码重复行,确保返回的源码逆序打印源码数据集不包含任何重复记录。具体而言,源码Hive在处理时,源码若未明确指定ALL或DISTINCT选项,源码则默认返回所有匹配行,源码而DISTINCT选项则确保结果集中只包含唯一行,源码多余重复的源码记录被去除。
相比之下,源码GROUP BY操作则侧重于数据的源码分组与聚合。其本质是源码对数据进行逻辑上的分组处理,然后基于每个分组返回计算结果。数据处理的顺序是先进行分组操作,根据指定的字段将数据划分为不同的组,之后对每组数据执行聚合操作,如计算每组的总和、平均值等。这一过程充分体现了Hive在数据处理上的高效与灵活性。
在理解了它们的基本逻辑与实现方式后,我们可以得出,尽管DISTINCT与GROUP BY在表面功能上存在差异,但在实际应用中,它们的性能表现可能较为相近。Hive优化器通常会将DISTINCT操作转换为GROUP BY操作,以更高效地利用并行计算资源。Arkmri源码因此,选择使用DISTINCT还是GROUP BY,应基于个人习惯与具体需求,不必过于纠结。
以具体的例子说明,当我们使用Hive执行SQL时,优化器可能自动将带有DISTINCT的查询转换为使用GROUP BY的查询,如以下执行计划所示,使用了Group By Operator。这一转换体现了Hive在优化过程中,为提高执行效率而采取的策略。
开发实战角度:distinct实现原理及具体优化总结
Distinct是一种在数据库SQL语言中至关重要的操作,尤其在Hive中,它通过MapReduce机制来实现。Distinct操作可以应用于单列或多列,其基本原理是对数据集按照指定列进行分组,去除每个分组内的重复值,最终合并成唯一值的结果集。
在最近的一次学习过程中,有位伙伴在研究count distinct时遇到了难题。虽然对单个count distinct原理理解尚可,但面对多字段count distinct时,讲解起来就变得复杂。下面将为大家总结这方面的内容。
在深入Distinct之前,先来了解一下group by操作的实现原理。group by操作适合与distinct紧密相关的聚合操作,因此,ima源码总结distinct之前,需要了解group by的具体实现。
在map阶段,将group by后的字段组合作为key,如果是单个字段,则key为一个。group by之后要进行的聚合操作字段作为值,如count则值为1;若sum另一个字段,则value是该字段值。shuffle阶段,按照key的不同分发到不同的reducer。reduce阶段,如果是count则将相同key的值累加,如果是其他操作,则按需要的聚合操作得到结果。
在map阶段如果出现数据倾斜,可以进行相应的处理,常见的方法有单独计算key、替换随机数等。针对group by的特殊方法有几种。
Distinct单字段原理:当执行Distinct操作时,Hive将其转化为MapReduce作业,并按指定列进行分组。Map阶段,每个Mapper读取输入数据,将指定列作为输出的key,通过Shuffle过程将具有相同key的数据发送到同一个Reducer中。由于使用了distinct,patchupdate源码Map端的combine无法合并重复数据,因此必须将id作为Key输出,在Reduce阶段再进行消重。
对于count(distinct)全聚合操作,即使设置了reduce task的具体个数,Hive最终也只会启动一个reducer。这导致所有map端传来的数据都在一个tasks中执行,唯一的Reduce Task需要处理大量的数据,这成为整个作业的IO和运算瓶颈。
Distinct一个字段时,将group by的字段和distinct的字段组合作为map输出的key,value设置为1,同时将group by的字段定为分区键。这样就可以将GroupBy字段作为reduce的key,在reduce阶段利用mapreduce的排序,输入天然就是按照组合key排好序的。根据分区键将记录分发到reduce端后,按顺序取出组合键中的distinct字段,这时distinct字段也是排好序的。依次遍历distinct字段,每找到一个不同值,计数器就自增1,即可得到count distinct结果。
对于单distinct的优化,可以通过将原来一个MapReduce作业转换为两个作业,在第一阶段选出全部的非重复的字段id,在第二阶段再对这些已消重的id进行计数。这样可以在第一阶段通过增大Reduce的134源码并发数来处理Map输出,在第二阶段,由于id已经消重,COUNT(*)操作在Map阶段不需要输出原id数据,只输出一个合并后的计数即可。
对于mult-distinct,如果按照上面一个distinct字段的方法,无法根据uid和date分别排序,也就无法通过LastKey去重,仍然需要在reduce阶段在内存中通过Hash去重。Hive会使用另一种处理方式,对所有的distinct字段编号,那么相同字段就会分别排序,这时只需要在reduce阶段记录LastKey即可去重。这种实现方式利用了MapReduce的排序,节省了reduce阶段去重的内存消耗,但缺点是增加了shuffle的数据量。
对于多重distinct的操作,可以按照一定步骤进行优化。
Hive常ç¨ç®åå®ç°åçç®è¿°--MapReduceç
Hiveä¸ç常ç¨ç®åå æ¬distinctãjoinãgroup byãorder byãdistribute byãsort byãcountçï¼è¿äºæä½ç¬¦å¨SQLä¸ä½¿ç¨èµ·æ¥å¾æ¹ä¾¿ï¼è½å¿«éè¾¾å°æ们æ³è¦çææï¼ä½æ¯è¿äºç®åå¨åºå±æ¯æä¹å®ç°çå¢ï¼
order byå¾å®¹ææ³å°æ§è¡åçï¼å¨ä¸ä¸ªreduceä¸å°ææè®°å½æå¼æåºå³å¯ãå æ¤order byå¨æ°æ®é大çæ åµä¸æ§è¡æ¶é´é常é¿ï¼å®¹æout of memoryï¼éç¹æ®ä¸å¡éæ±ä¸è¬ä¸ä½¿ç¨ãdistribute byä¹æ¯è¾ææ¾ï¼æ ¹æ®hashå¼å°distributeçå¼ååå°ä¸åçreduceãsort byæ¯å°å·çorder byï¼åªè´è´£å°æ¬reducerä¸çå¼æåºï¼è¾¾å°å±é¨æåºçææãsort byådistribute byé å使ç¨é£å³æ´ä½³ï¼äºè å¯ä»¥å并ç®å为cluster byãcountåæ´å ææ°ï¼å¨combineræreducerå¤æç¸åé®ç´¯å å¼å°±è½å¾å°ã
æ¯è¾å¤æçæ¯distinctãjoinãgroup byï¼æ¬æéç¹è®¨è®ºè¿ä¸ä¸ªç®åå¨MapReduceå¼æä¸ç大è´å®ç°åçãçé¨å¼æ§ï¼æç å¼çã
mapé¶æ®µï¼å°group byåçå段ç»åä½ä¸ºkeyï¼å¦ægroup byåå段é£ä¹keyå°±ä¸ä¸ªãå°group byä¹åè¦è¿è¡çèåæä½å段ä½ä¸ºå¼ï¼å¦è¦è¿è¡countï¼åvalueæ¯1ï¼å¦è¦sumå¦ä¸ä¸ªå段ï¼åvalueå°±æ¯è¯¥å段ã
shuffleé¶æ®µï¼æç §keyçä¸åååå°ä¸åçreducerã注ææ¤æ¶å¯è½å 为keyåå¸ä¸ååèåºç°æ°æ®å¾æçé®é¢ã
reduceé¶æ®µï¼å°ç¸åkeyçå¼ç´¯å æä½å ¶ä»éè¦çèåæä½ï¼å¾å°ç»æã
对group byçè¿ç¨è®²è§£çæ¯è¾æ¸ æ¥çæ¯è¿ç¯æç« /info-detail-.html å¾æ并èï¼å¾çå¨ã
å®ä¾å¦ä¸å¾ï¼å¯¹åºè¯å¥æ¯ select rank, isonline, count(*) from city group by rank, isonline;
å¦ægroup byåºç°æ°æ®å¾æï¼é¤å»æ¿æ¢key为éæºæ°ãæåæåºå¤§æ°é级keyå¼çéç¨è°ä¼æ¹æ³ï¼éç¨äºgroup byçç¹æ®æ¹æ³æ以ä¸å ç§ï¼
ï¼1ï¼set hive.map.aggr=trueï¼å³å¼å¯map端çcombinerï¼åå°ä¼ å°reducerçæ°æ®éï¼åæ¶é设置åæ°hive.groupby.mapaggr.checkinterval è§å®å¨ map 端è¿è¡èåæä½çæ¡ç®æ°ç®ã
ï¼2ï¼è®¾ç½®mapred.reduce.tasks为è¾å¤§æ°éï¼éä½æ¯ä¸ªreducerå¤ççæ°æ®éã
ï¼3ï¼set hive.groupby.skewindata=trueï¼è¯¥åæ°å¯èªå¨è¿è¡è´è½½åè¡¡ãçæçæ¥è¯¢è®¡åä¼æ两个 MR Jobã第ä¸ä¸ª MR Job ä¸ï¼Map çè¾åºç»æéåä¼éæºåå¸å°Reduce ä¸ï¼æ¯ä¸ª Reduce åé¨åèåæä½ï¼å¹¶è¾åºç»æï¼è¿æ ·å¤ççç»ææ¯ç¸åç Group By Keyæå¯è½è¢«ååå°ä¸åç Reduce ä¸ï¼ä»èè¾¾å°è´è½½åè¡¡çç®çï¼ç¬¬äºä¸ª MR Job åæ ¹æ®é¢å¤ççæ°æ®ç»ææç § Group ByKey åå¸å° Reduce ä¸ï¼è¿ä¸ªè¿ç¨å¯ä»¥ä¿è¯ç¸åç Group By Key 被åå¸å°åä¸ä¸ª Reduceä¸ï¼ï¼æåå®ææç»çèåæä½ã
Hiveä¸æ两ç§joinæ¹å¼ï¼map joinåcommon join
å¦æä¸æ¾å¼æå®map side joinï¼æè 没æè¾¾å°è§¦åèªå¨map joinçæ¡ä»¶ï¼é£ä¹ä¼è¿è¡reduce端çjoinï¼å³common joinï¼è¿ç§joinå å«mapãshuffleãreduceä¸ä¸ªæ¥éª¤ã
ï¼1ï¼Mapé¶æ®µ
读åæºè¡¨çæ°æ®ï¼Mapè¾åºæ¶å以Join onæ¡ä»¶ä¸çå为keyï¼å¦æJoinæå¤ä¸ªå ³èé®ï¼å以è¿äºå ³èé®çç»åä½ä¸ºkeyãMapè¾åºçvalue为joinä¹åæå ³å¿ç(selectæè whereä¸éè¦ç¨å°ç)åï¼åæ¶å¨valueä¸è¿ä¼å å«è¡¨çTagä¿¡æ¯ï¼ç¨äºæ ææ¤value对åºåªä¸ªè¡¨ãç¶åæç §keyè¿è¡æåºã
ï¼2ï¼Shuffleé¶æ®µ
æ ¹æ®keyçå¼è¿è¡hash,并å°key/valueæç §hashå¼æ¨éè³ä¸åçreduceä¸ï¼è¿æ ·ç¡®ä¿ä¸¤ä¸ªè¡¨ä¸ç¸åçkeyä½äºåä¸ä¸ªreduceä¸
ï¼3ï¼Reduceé¶æ®µ
æ ¹æ®keyçå¼å®æjoinæä½ï¼æé´éè¿Tagæ¥è¯å«ä¸å表ä¸çæ°æ®ã
以ä¸é¢çSQL为ä¾ï¼å¯ç¨ä¸å¾æ示è¿ç¨å¤§è´è¡¨è¾¾å ¶joinåçã
SELECT u.name, o.orderid FROM user u JOIN order o ON u.uid = o.uid;
å ³èå段æ¯uidï¼å æ¤ä»¥uid为mapé¶æ®µçè¾åºkeyï¼value为éåçå段nameåæ è®°æºè¡¨çtagãshuffleé¶æ®µå°ç¸åkeyçé®å¼å¯¹åå°ä¸èµ·ï¼reduceé¶æ®µå°ä¸åæºè¡¨ãåä¸keyå¼çè®°å½æ¼æ¥èµ·æ¥ï¼å¯è½åå¨ä¸å¯¹å¤çæ åµã
å¦ææå®ä½¿ç¨map joinçæ¹å¼ï¼æè joinçå ¶ä¸ä¸å¼ 表å°äºæ个ä½ç§¯ï¼é»è®¤MBï¼ï¼åä¼ä½¿ç¨map joinæ¥æ§è¡ãå ·ä½å°è¡¨æå¤å°ï¼ç±åæ° hive.mapjoin.smalltable.filesize æ¥å³å®ã
Hive0.7ä¹åï¼éè¦ä½¿ç¨hintæ示 /*+ mapjoin(table) */æä¼æ§è¡MapJoin,å¦åæ§è¡Common Joinï¼ä½å¨0.7çæ¬ä¹åï¼é»è®¤èªå¨ä¼è½¬æ¢Map Joinï¼ç±åæ° hive.auto.convert.join æ¥æ§å¶ï¼é»è®¤ä¸ºtrueã
以ä¸å¾ä¸ºä¾è¯´æmap joinå¦ä½æ§è¡ï¼è¯¥å¾æ¥èª /archives///.htm ï¼å主æ¯ä¸ä¸ªæ°´å¹³æ·±ååä¹äºå享çåè¾ï¼å¾çæ°´å°ä¸ä¹æå ¶ç½åã
yarnä¼å¯å¨ä¸ä¸ªLocal Taskï¼å¨å®¢æ·ç«¯æ¬å°æ§è¡çTaskï¼--Task Aï¼è´è´£æ«æå°è¡¨bçæ°æ®ï¼å°å ¶è½¬æ¢æä¸ä¸ªHashTableçæ°æ®ç»æï¼å¹¶åå ¥æ¬å°çæ件ä¸ï¼ä¹åå°è¯¥æ件å è½½å°DistributeCacheä¸ã
æ¥ä¸æ¥æ¯Task Bï¼è¯¥ä»»å¡æ¯ä¸ä¸ªæ²¡æReduceçMRï¼å¯å¨MapTasksæ«æ大表a,å¨Mapé¶æ®µï¼æ ¹æ®açæ¯ä¸æ¡è®°å½å»åDistributeCacheä¸b表对åºçHashTableå ³èï¼å¹¶ç´æ¥è¾åºç»æã
ç±äºMapJoin没æReduceï¼æ以ç±Mapç´æ¥è¾åºç»ææ件ï¼æå¤å°ä¸ªMap Taskï¼å°±æå¤å°ä¸ªç»ææ件ã
distinctä¸è¬ågroup byåæ¶åºç°ã
å½distinctä¸ä¸ªå段æ¶ï¼å°group byçå段ådistinctçå段ç»åå¨ä¸èµ·ä½ä¸ºmapè¾åºçkeyï¼value设置为1ï¼åæ¶å°group byçå段å®ä¸ºååºé®ï¼è¿å¯ä»¥ç¡®ä¿ç¸ågroup byå段çè®°å½é½åå°åä¸ä¸ªreducerï¼å¹¶ä¸mapçè¾å ¥å¤©ç¶å°±æ¯æç §ç»åkeyæ好åºçãæ ¹æ®ååºé®å°è®°å½ååå°reduce端åï¼æ顺åºååºç»åé®ä¸çdistinctå段ï¼è¿æ¶distinctå段ä¹æ¯æ好åºçãä¾æ¬¡éådistinctå段ï¼æ¯æ¾å°ä¸ä¸ªä¸åå¼ï¼è®¡æ°å¨å°±èªå¢1ï¼å³å¯å¾å°count distinctç»æãä¾å¦ä¸é¢çSQLè¯å¥ï¼è¿ç¨å¯ä»¥ä¸å¾ç¤ºæã
æææ¶æ²¡æç解è¿æ¯æä¹å®ç°çï¼å«äººåçä¹æ²¡æçæç½ãæåè¯çå¦å¯äºè½¦ç大佬æç¹ä¸ä¸åï¼
HIVE-SQL优化(持续更新ing)
优化HIVE SQL主要包括配置优化、SQL语句优化以及任务优化等方案。在开发过程中,主要关注SQL优化。优化的核心思想包括减少数据量、避免数据倾斜、避免全表扫描以及减少job数。
在SQL优化中,关键点包括使用分区剪裁和列剪裁以减少数据量。避免数据倾斜,通常通过调整参数和Key打散来实现。避免全表扫描,通过在ON语句中添加分区等条件来优化。减少job数,通过合并具有相同ON条件的JOIN操作到一个任务中。
优化HQL语句时,应尽量减少使用COUNT DISTINCT,因为它可能需要一个Reduce Task处理大量数据,导致Job难以完成。使用WITH子句可以提取子查询并将其结果用作临时表,减少重复计算,提高效率。在处理大表和小表的JOIN时,遵循将条目少的表放在Join操作符左侧的原则,可以减少OOM错误的几率。数据倾斜发生在shuffle过程中,常见触发此现象的算子包括distinct、groupByKey等。
优化HIVE SQL的策略还包括通过参数调整来优化性能,但具体设置不在本文详细描述。核心优化思想旨在通过减少数据量、避免数据倾斜、避免全表扫描以及合理安排job和JOIN操作,实现SQL执行效率的提升。这些优化策略对于HIVE的性能优化至关重要,确保查询任务能够高效执行。
Hiveä¼åçåååè
éè¦æ»¡è¶³ä»¥ä¸æ¡ä»¶ï¼hive.mapred.mode=trueï¼ä¸¥æ ¼æ¨¡å¼ä¸å 许æ§è¡ä»¥ä¸æ¥è¯¢ï¼
ååºè¡¨ä¸æ²¡ææå®äºååº
没ælimitéå¶çorder byè¯å¥
ç¬å¡å°ç§¯ï¼JOINæ¶æ²¡æONè¯å¥
两个èéå½æ°ä¸è½æä¸åçDISTINCTåï¼ä»¥ä¸è¡¨è¾¾å¼æ¯é误çï¼
SELECTè¯å¥ä¸åªè½æGROUP BYçåæè èéå½æ°ã
第ä¸ä¸ªMRJob ä¸ï¼
Mapçè¾åºç»æéåä¼éæºåå¸å°Reduceä¸ï¼æ¯ä¸ªReduceåé¨åèåæä½ï¼å¹¶è¾åºç»æï¼è¿æ ·å¤ççç»ææ¯ç¸åçGroupBy Key
æå¯è½è¢«ååå°ä¸åçReduceä¸ï¼ä»èè¾¾å°è´è½½åè¡¡çç®çï¼ç¬¬äºä¸ªMRJobåæ ¹æ®é¢å¤ççæ°æ®ç»ææç §GroupBy Keyåå¸å°
Reduceä¸ï¼è¿ä¸ªè¿ç¨å¯ä»¥ä¿è¯ç¸åçGroupBy Key被åå¸å°åä¸ä¸ªReduceä¸ï¼ï¼æåå®ææç»çèåæä½ã
FROM test
INSERT OVERWRITE TABLE count1
SELECT count(DISTINCT test.dqcode)
GROUP BY test.zipcode
INSERT OVERWRITE TABLE count2
SELECT count(DISTINCT test.dqcode)
GROUP BY test.sfcode;
ORDER BY colName ASC/DESC
hive.mapred.mode=strictæ¶éè¦è·limitåå¥
hive.mapred.mode=nonstrictæ¶ä½¿ç¨å个reduceå®ææåº
SORT BY colName ASC/DESC ï¼æ¯ä¸ªreduceå æåº
DISTRIBUTE BY(åæ¥è¯¢æ åµä¸ä½¿ç¨ )ï¼æ§å¶ç¹å®è¡åºè¯¥å°åªä¸ªreducerï¼å¹¶ä¸ä¿è¯reduceå æ°æ®ç顺åº
CLUSTER BY ï¼å½SORT BY ãDISTRIBUTE BY使ç¨ç¸åçåæ¶ã
å¢å mapæ°ç®ï¼
å½inputçæ件é½å¾å¤§ï¼ä»»å¡é»è¾å¤æï¼mapæ§è¡éå¸¸æ ¢çæ¶åï¼å¯ä»¥èèå¢å Mapæ°ï¼æ¥ä½¿å¾æ¯ä¸ªmapå¤ççæ°æ®éåå°ï¼ä»èæé«ä»»å¡çæ§è¡æçã
å设æè¿æ ·ä¸ä¸ªä»»å¡ï¼
ããselect data_desc, count(1), count(distinct id),sum(case when â¦),sum(case when ...),sum(â¦) from a group by data_desc
å¦æ表aåªæä¸ä¸ªæ件ï¼å¤§å°ä¸ºMï¼ä½å å«å åä¸çè®°å½ï¼å¦æç¨1个mapå»å®æè¿ä¸ªä»»å¡ï¼è¯å®æ¯æ¯è¾èæ¶çï¼è¿ç§æ åµä¸ï¼æ们è¦èèå°è¿ä¸ä¸ªæ件åççæåæå¤ä¸ªï¼è¿æ ·å°±å¯ä»¥ç¨å¤ä¸ªmapä»»å¡å»å®æã
ããset mapred.reduce.tasks=;
ããcreate table a_1 as select * from a distribute by rand();
è¿æ ·ä¼å°a表çè®°å½ï¼éæºçåæ£å°å å«ä¸ªæ件ça_1表ä¸ï¼åç¨a_1代æ¿ä¸é¢sqlä¸ça表ï¼åä¼ç¨ä¸ªmapä»»å¡å»å®æãæ¯ä¸ªmapä»»å¡å¤ç大äºMï¼å ç¾ä¸è®°å½ï¼çæ°æ®ï¼æçè¯å®ä¼å¥½å¾å¤ã
reduceæ°ç®è®¾ç½®ï¼
ãåæ°1ï¼hive.exec.reducers.bytes.per.reducer=1Gï¼æ¯ä¸ªreduceä»»å¡å¤ççæ°æ®é
ãåæ°2ï¼hive.exec.reducers.max=(0. TaskTrackeræ°)ï¼æ¯ä¸ªä»»å¡æ大çreduceæ°ç®
ãreduceræ°=min(åæ°2,æ»è¾å ¥æ°æ®é/åæ°1)
ãset mapred.reduce.tasksï¼æ¯ä¸ªä»»å¡é»è®¤çreduceæ°ç®ãå ¸å为0. reduce槽æ°ï¼hiveå°å ¶è®¾ç½®ä¸º-1ï¼èªå¨ç¡®å®reduceæ°ç®ã
.使ç¨ç´¢å¼ï¼
hive.optimize.index.filterï¼èªå¨ä½¿ç¨ç´¢å¼
hive.optimize.index.groupbyï¼ä½¿ç¨èåç´¢å¼ä¼åGROUP BYæä½
通过深挖Clickhouse源码,我精通了数据去重!
数据去重的Clickhouse探索
在大数据面试中,数据去重是一个常考问题。虽然很多博主已经分享过相关知识,但本文将带您深入理解Hive引擎和Clickhouse在去重上的差异,尤其是后者如何通过MergeTree和高效的数据结构优化去重性能。Hive去重
Hive中,distinct可能导致数据倾斜,而group by则通过分布式处理提高效率。面试时,理解MapReduce的数据分区分组是关键。然而,对于大规模数据,Hive的处理速度往往无法满足需求。Clickhouse的登场
面对这个问题,Clickhouse凭借其列存储和MergeTree引擎崭露头角。MergeTree的高效体现在它的数据分区和稀疏索引,以及动态生成和合并分区的能力。Clickhouse:Yandex开源的实时分析数据库,每秒处理亿级数据
MergeTree存储结构:基于列存储,通过合并树实现高效去重
数据分区和稀疏索引
Clickhouse的分区策略和数据组织使得去重更为快速。稀疏索引通过标记大量数据区间,极大地减少了查询范围,提高性能。优化后的去重速度
测试显示,Clickhouse在去重任务上表现出惊人速度,特别是通过Bitmap机制,去重性能进一步提升。源码解析与原则
深入了解Clickhouse的底层原理,如Bitmap机制,对于优化去重至关重要,这体现了对业务实现性能影响的深度理解。总结与启示
对于数据去重,无论面试还是日常工作中,深入探究和实践是提升的关键。不断积累和学习,即使是初入职场者也能在大数据领域找到自己的位置。小技巧一:把roaring bitmap引入hive/spark,再也不怕count(distinct)了
小技巧一:引入Roaring Bitmap到Hive/Spark,解决count(distinct)问题
在SQL中,`count(distinct xxx)`常用于计算去重数量。当`xxx`为byte, shortint, int等数值类型时,可以将其转化为bitmap位运算,加速运算。对于非数值类型,可以考虑将其转换为一个唯一的数字,构建广义字典。Roaring Bitmap的基本思想是使用一个位图来唯一标记某个正整数,用于记录无重复的整数数组。
例如,数组[2,3,4,5]可以通过一个字节记录。通过依次设置数字n在第n+1个位置的位,可以表示数组。对于数字范围0到n,需要`n/ +1`字节的存储空间。与数组存储相比,Roaring Bitmap的存储空间通常更小,约为数组的1/。
Roaring Bitmap适用于无法直接存储的其他类型数字,通过转换为唯一数字进行存储。在处理如`[0,]`的场景中,使用Roaring Bitmap需要字节的空间,而数组存储只需要8字节,因此不划算。Roaring Bitmap在底层采用数组存储,以适应数字分散的场景。
当处理如`[0,]`和`[,0]`的场景时,Roaring Bitmap可能无法区分数字顺序或正确识别重复值。在大数据领域,如活跃人数等去重指标的计算中,Roaring Bitmap可以加速计算过程,尤其是在离线执行引擎Hive/Spark中引入Roaring Bitmap来实现精准去重。
考虑到Hive本身不支持Roaring Bitmap数据类型,可以将其序列化为`binary`类型使用。在函数体系方面,需要实现一系列的UDF和UDAF函数,如`bitmap_count`、`bitmap_and`、`bitmap_not`、`bitmap_union`、`bitmap_contains`、`range_bitmap`、`bitmap_to_array`、`array_to_bitmap`等,以支持bitmap的集合计数、交集、差集、并集和查询操作。
在留存分析场景中,可以利用Roaring Bitmap构建活跃位图来加速计算,如连续N天登录问题。通过将用户活跃日期构建为位图,可以快速判断用户是否连续活跃。在用户画像和用户圈选场景中,Roaring Bitmap可以用于构建用户活跃画像,提高数据处理效率。在电商场景中,通过构建轻度汇总表并使用Roaring Bitmap存储去重人数,可以有效避免重复计算,提高数据聚合的准确性。
对于大数值范围(如bigint),Roaring Bitmap也支持。考虑到实际应用中数值范围超过`2**`的情况较少,是否需要支持bigint取决于具体需求。在数据索引优化方面,可以考虑重新编码,使得连续分布,进一步提高查询性能。