标签:__ name xxx Hive 索引 hive zhangsan
Hive索引
文章目录
Compact索引
CREATE INDEX idx_xxx ON TABLE xxx(tablename) AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' WITH DEFERRED REBUILD;
使用 show tables;
命令查看,发现现在多了一个叫 default__xxx_idx_xxx__
的表,但是里面没有内容,因为CREATE INDEX
命令后面加了 WITH DEFERRED REBUILD
选项,所以索引不会自动创建,而是要执行:ALTER INDEX idx_xxx ON xxx REBUILD;
才会重建索引。
如果有分区的话,可以针对单独的分区重建索引: ALTER INDEX idx_xxx ON xxx PARTITION(month='2019-09') REBUILD;
HiveHive索引有很大的局限,其中之一就是占用空间。根据之前有位大佬(不是我)的测试:xxx表其中一个108G的分区,索引需要32G的左右空间(大佬说是在没有压缩的情况下,他还未验证索引是否可以压缩)。
REBUILD 索引后,会发现索引的分区结构和原表一致,对于Compact索引,其实就是索引字段名,文件,偏移值这三个字段组成的表。
可以用 select * from default__xxx_idx_xxx__;
查看。或用describe idx_xxx 会发现他有3个字段:
name string
_bucketname string
_offsets array<bigint>
其中:
name :是原xxx表种的字段
_bucketname :是xxx表在HDFS中的文件名。
_offsets :是该name在_bucketname 文件中的便宜地址,是一个数组。
例如:name=‘zhangsan’ 的字段在xxx表中出现了3次,那么 _offsets 就可能会有3个值(之所以为可能,因为存在3个文件中个出现一次的情况),分别是 3次 ‘zhangsan’ 在文件中的偏移量。
索引第二个缺点就是使用方法并不统一。例如我对name建立索引后,需要查询 select count(*) from xxx where name = 'zhangsan'
时,要写成:
select size(`_offsets`) from default__xxx_idx_xxx__ where name = 'zhangsan';
注意 _offsets 前后有反引号 `。
因为正常情况下,Hive字段名不允许以 _ 开头, _bucketname 和 _offsets 是隐藏字段,为了能够正常使用它,压价反引号,但不能用普通单引号(否则就直接变成字符串了)。
如果想要优化 select count(*) from xxx where name = 'zhangsan'
则要用下面复杂的步骤:
INSERT OVERWRITE DIRECTORY '/tmp/result'
select '_bucketname','_offsets' from default__xxx_idx_xxx__ where name = 'zhangsan';
set hive.index.compact.file=/tmp/result;
set hive.input.format=org.apache.hadoop.hive.ql.index.compact.HiveCompactIndexInputFormat;
select * from xxx where name = 'zhangsan';
而且索引效果不明显,甚至有时候会更差。
但类似 select name,count(*) from xxx group by name;
这种查询时,因为实际只需要扫描一次 default__xxx_idx_xxx__
并取每个 size 就可以了,而 default__xxx_idx_xxx__
要比原表 xxx 小得多。再大佬得分享中,直接对xxx表进行 group by
耗时 260秒,而从索引查询只耗时 100秒。
可见索引虽然使用场景有限,并且效果不稳定,但是的确能够减少全表扫描的范围,减少IO量。在大佬分享中,不使用索引时,需要扫描434个MR task。而在使用索引后,第一阶段只需要扫描30G的文件,第二阶段直接定位到 _bucketname 的文件中(分享中 name='zhangsan’的值只有一个),所以总共只占用了122个MR task。
Aggregation索引
CREATE INDEX idx2_xxx ON TABLE tablename AS 'org.apache.hadoop.hive.ql.index.AggregateIndexHandler'
WITH DEFERRED REBUILD IDXPROPERTIES("AGGREGATES"="count(value)") STORED AS TEXTFILE;
其中 AGGREGATES
表示需要聚合的操作,本例中为 count,也可以改为 sum。同样用 ALTER 进行 REBUILD。
用 DESCRIBE default__xxx_idx2_xxx__
可以看到其结构:
name string
_bucketname string
_offsets array<bigint>
_count_of_value bight
也就是说
select count(value) from xxx where name='zhangsan';
现在可以改为:
select `_count_of_value` from xxx where name='zhangsan';
另一方面可以看到:CompactIndex
所包含的字段已经在 AggregateIndex
里面了,即 AggregateIndex
可以当作 CompactIndex
用了。
如果将 IDXPROPERTIES
里面的 count 换成 sum,那么最后一个字段将是 _sum_of_value
,但奇怪的是,类型仍然为bigint。而不是double。但是这个问题可以通过修改字段类型将其修改为 double。
ALTER TABLE default__xxx_idx2_xxx__ CHANGE `_sum_of_value` `_sum_of_value` double;
在大佬的分享中,108G的分区建立的聚合索引大小为48.8G,因为 Aggregation 实际上包含了 Compact,所以更大了。
如果表中name 字段的重复值很多,这个空间大小应该可以降下来,上面案例中的重复值为 1/3.
Bitmap索引
Hive中的位图索引非常不完善,几乎不可用。
大佬分享的案例:
有表,数据如下:
name | country | gender |
---|---|---|
zhangsan | China | male |
lily | China | male |
Tom | USA | male |
xiaofang | China | famale |
可以为country字段建立位图索引如下:
china | 1101 |
---|---|
USA | 0010 |
再为gender建立性别的位图索引,如下:
male | 1110 |
---|---|
famale | 0001 |
现在要查询数据库中来自中国的男性:
select * from xxx where country='China' and gender='male';
可以直接从country索引中取出 China的位图 1101 ,再从gender 索引中取出 male 的位图 1110,然后进行 & 操作,得到 1100,于是可以直接选取第 1,2行数据。
在Hive中,用上面说的生成位图索引如下:
索引字段名 | _bucketname | _offset | _bitmaps |
---|---|---|---|
y | hdfs://hacluster/user/hive/warehouse/xxx/xxx.txt | 0 | [1,2,4,8589934592,1,0] |
n | hdfs://hacluster/user/hive/warehouse/xxx/xxx.txt | 6 | [1,2,4,8589934592,1,0] |
先看看每个字段的含义,用 describe 命令可以看到位图索引由4个字段,分别是索引字段名,文件名 _bucketname
,偏移量 _offset
,位图 _bitmaps
。
其中最后那串古怪的数字就是字段 _bitmaps
,类型是 bitint 数组: [1,2,4,8589934592,1,0]
这是EWAHCompressedBitmap 的格式,EWAHCompressedBitmap 是一种压缩的 Bitmap Set,尝试了一下,发现第一位表示 size in bits,表示最大位 bit 位,第二位表示 size in words,表示后面用了几个long来保存数据。整张有意义的是 [8589934592,1] 这两个数字。
其中 8589934592 转换位二进制是 1 后面 33 个 0,猜测 8589934592 低 33 位表示是否压缩,这里全为 0,表示不压缩(所谓压缩,其实就是将全 0 的跳过);位 33 值为 1,表示后面 1个 long 值是有效值,而后面的long值就是 1,所以这么长的遗传数组,其实想表达的就是1而已。
从上面结果来看,根本不是位图索引。首先位图索引应该是每个取值只有1行,不会有重复的 y 和 n。其次,位图索引应该是一个大整数(更多情况是long 的数组,数组大小就是整个表大小除以 64),且y 和 n的 _bitmaps
应各不相同。
所以正确的位图索引应该是:
索引字段名 | _bucketname | _offset | _bitmaps |
---|---|---|---|
y | hdfs://hacluster/user/hive/warehouse/xxx/xxx.txt | [0,12,24,36,48,60] | [1365] |
n | hdfs://hacluster/user/hive/warehouse/xxx/xxx.txt | [6,18,30,42,54,66] | [2730] |
其中 [0,12,24,36,48,60] 是 hdfs://hacluster/user/hive/warehouse/xxx/xxx.txt 中所有字段值为 y 的偏移地址,而1365 的二进制就是 010101010101
(注意这里是反序的,这里假设最低位表示0行,越往左行号越大)。否则便利原表的 y 值,在索引表中还有重新遍历一次,根本没有发挥位图索引的作用。
108G的分区,Hive建立的位图索引大小为 54.2G,光是那个 Bitmap 数组就花了不少。
所以结论:Hive索引很不完善,效果不加。
主要缺点:占用空间大,精确查询反而降低,使用麻烦,不便于二次开发。
主要优点:对于count 和 sum 提升明显。
标签:__,name,xxx,Hive,索引,hive,zhangsan 来源: https://blog.csdn.net/xxydzyr/article/details/100974920
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。