温馨提示:要看高清无码套图,请使用手机打开并单击图片放大查看。
Fayson的github: https://github.com/fayson/cdhproject
提示:代码块部分可以左右滑动查看噢
1.文档编写目的
对于HBase而言,如果想精确地定位到某行记录,唯一的办法是通过rowkey来查询。如果不通过rowkey来查找数据,就必须逐行地比较每一列的值,即全表扫瞄。对于较大的表,全表扫描的代价是不可接受的。
但是,很多情况下,需要从多个角度查询数据。例如,在定位某个人的时候,可以通过姓名、身份证号、学籍号等不同的角度来查询,要想把这么多角度的数据都放到rowkey中几乎不可能(业务的灵活性不允许,对rowkey长度的要求也不允许)。
所以,需要secondary index来完成这件事。secondary index的原理很简单,即通过索引表来实现,但是如果自己维护的话则会麻烦一些。在很早的版本中,Phoenix就已经提供了对HBase secondary index的支持。
Fayson在前面的文章《Cloudera Labs中的Phoenix》和《如何在CDH中使用Phoenix》中介绍了Cloudera Labs中的Phoenix,以及如何在CDH5.11.2中安装和使用Phoenix4.7。本文Fayson主要介绍如何在CDH中使用Phoenix在HBase上建立二级索引。
- 内容概述:
1.建表与数据准备
2.启用Kafka的Sentry赋权
3.Kafka的赋权测试
4.总结
- 测试环境:
1.CM5.14.3/CDH5.14.2
2.Phoenix4.7.0
3.操作系统版本为Redhat7.4
4.采用root用户进行操作
5.集群未启用Kerberos
2.建表与数据准备
1.首先确保你的CDH集群已经安装Phoenix的Parcel,安装过程省略,具体可以参考《如何在CDH中使用Phoenix》。
2.准备一个测试csv文件用来导入Phoenix的表中,Fayson这里准备一个1.2GB,995W行,11个字段的数据文件。
代码语言:javascript复制[root@ip-172-31-6-83 generatedata]# cat hbase_data.csv | wc -l
9950000
[root@ip-172-31-6-83 generatedata]# du -sh hbase_data.csv
1.2G hbase_data.csv
[root@ip-172-31-6-83 generatedata]# head hbase_data.csv
340111200507061443,鱼言思,0,遂宁,国家机关,13004386766,15900042793,广州银行1,市场三街65号-10-8,0,1
320404198104281395,暨梅爱,1,临沧,服务性工作人员,13707243562,15004903315,广州银行1,太平角六街145号-9-5,0,3
371326195008072277,人才奇,1,黔西南,办事人员和有关人员,13005470170,13401784500,广州银行1,金湖大厦137号-5-5,1,0
621227199610189727,谷岚,0,文山,党群组织,13908308771,13205463874,广州银行1,仰口街21号-6-2,1,3
533324200712132678,聂健飞,1,辽阳,不便分类的其他劳动者,15707542939,15304228690,广州银行1,郭口东街93号-9-3,0,2
632622196202166031,梁子伯,1,宝鸡,国家机关,13404591160,13503123724,广州银行1,逍遥一街35号-14-8,1,4
440883197110032846,黎泽庆,0,宝鸡,服务性工作人员,13802303663,13304292508,广州银行1,南平广场113号-7-8,1,4
341500196506180162,暨芸贞,0,黔西南,办事人员和有关人员,13607672019,13200965831,广州银行1,莱芜二路117号-18-3,1,4
511524198907202926,滕眉,0,南阳,国家机关,15100215934,13406201558,广州银行1,江西支街52号-10-1,0,3
420205198201217829,陶秀,0,泸州,商业工作人员,13904973527,15602017043,广州银行1,城武支大厦126号-18-2,1,0
(可左右滑动)
3.连接到Phoenix的终端,在Phoenix中建表hbase_test
代码语言:javascript复制cd /opt/cloudera/parcels/CLABS_PHOENIX/bin
./phoenix-sqlline.py ip-172-31-6-83.ap-southeast-1.compute.internal:2181:/hbase create table hbase_test
(
s1 varchar not null primary key,
s2 varchar,
s3 varchar,
s4 varchar,
s5 varchar,
s6 varchar,
s7 varchar,
s8 varchar,
s9 varchar,
s10 varchar,
s11 varchar
);
(可左右滑动)
4.将准备好的csv文件put到HDFS,然后通过Phoenix自带的bulkload工具将准备好的csv文件批量导入到Phoenix的表中。
代码语言:javascript复制[root@ip-172-31-6-83 generatedata]# hadoop fs -mkdir /fayson
[root@ip-172-31-6-83 generatedata]# hadoop fs -put hbase_data.csv /fayson
[root@ip-172-31-6-83 generatedata]#
(可左右滑动)
代码语言:javascript复制[root@ip-172-31-6-83 generatedata]# HADOOP_CLASSPATH=/opt/cloudera/parcels/CDH/lib/hbase/hbase-protocol-1.2.0-cdh5.7.6.jar:/opt/cloudera/parcels/CDH/lib/hbase/conf hadoop jar /opt/cloudera/parcels/CLABS_PHOENIX/lib/phoenix/phoenix-4.7.0-clabs-phoenix1.3.0-client.jar org.apache.phoenix.mapreduce.CsvBulkLoadTool -t hbase_test -i /fayson/hbase_data.csv
(可左右滑动)
5.在Phoenix和hbase shell中分别查询确认数据入库成功。
代码语言:javascript复制select * from HBASE_TEST limit 10;
scan 'HBASE_TEST',{LIMIT => 1}
(可左右滑动)
3.Covered Indexes(覆盖索引)
1.使用覆盖索引获取数据的过程中,内部不需要再去HBase的原表获取数据,查询需要返回的列都会被存储在索引中。要想达到这种效果,你的select的列,where的列都需要在索引中出现。举个例子,如果你的SQL语句是select s2 from hbase_test where s6='13505503576',要最大化查询效率和速度最快,可以建立覆盖索引。
代码语言:javascript复制CREATE INDEX index1_hbase_test ON hbase_test(s6) INCLUDE(s2)
(可左右滑动)
提示要对HBase进行一些配置才能执行该语句。
2.将以下配置增加到hbase-site.xml,通过Cloudera Manager搜索HBase服务的“hbase-site.xml 的 HBase 服务高级配置代码段(安全阀)”。
代码语言:javascript复制<property>
<name>hbase.regionserver.wal.codec</name>
<value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
</property>
(可左右滑动)
保存更改,然后重启HBase。
3.在执行建立覆盖索引之前,我们先执行2个查询语句方便后面跟建立索引后的查询时间进行对比。
代码语言:javascript复制select s6 from hbase_test where s6='13505503576';
select s2 from hbase_test where s6='13505503576';
(可左右滑动)
4.再次执行建立覆盖索引的语句
代码语言:javascript复制CREATE INDEX index1_hbase_test ON hbase_test(s6) INCLUDE(s2);
(可左右滑动)
5.再次执行上面2个查询语句。
代码语言:javascript复制select s6 from hbase_test where s6='13505503576';
select s2 from hbase_test where s6='13505503576';
(可左右滑动)
发现都是毫秒级返回,而之前2个查询都是需要30几秒。
6.我们再来具体看看建立覆盖索引的语句。
代码语言:javascript复制CREATE INDEX index1_hbase_test ON hbase_test(s6) INCLUDE(s2);
(可左右滑动)
果查询项中不包含除s2和s6之外的列,而且查询条件不包含除s2之外的列,则可以确保该查询使用Index,关键字INCLUDE包含需要返回数据结果的列。这种索引方式的最大好处就是速度快,而我们也知道,索引就是空间换时间,所以缺点也很明显,存储空间耗费较多。
如上图所示,Phoenix的索引其实就是建了一张HBase的表。你可以通过hbase shell的list命令看到。查看表index1_hbase_test,你会发现,这张表一共三列,一列就是索引,第二列是RowKey,最后一列就是s2的值。很明显在这里记录的RowKey,就是为了快速查找HBase中的数据。只是这里用不到,s2已经被保存到了这张索引表中,直接返回。
4.Functional Indexes(函数索引)
函数索引从从Phoenix4.3版本就有,这种索引的内容不局限于列,还能在表达式上建立索引。如果你使用的表达式正好就是索引的话,数据也可以直接从这个索引获取,而不需要从数据库获取。
1.在建立函数索引时,我们先执行两个查询语句好方便与建立索引以后的性能进行对比。
代码语言:javascript复制select s1,s7 from hbase_test where substr(s7,1,10)='1550864580';
select s1,substr(s7,1,10) from hbase_test where substr(s7,1,10)='1550864580';
(可左右滑动)
2.建立函数索引
代码语言:javascript复制create index index2_hbase_test on hbase_test (substr(s7,1,10));
(可左右滑动)
3.再次执行前面的查询语句进行比较
代码语言:javascript复制select s1,s7 from hbase_test where substr(s7,1,10)='1550864580';
select s1,substr(s7,1,10) from hbase_test where substr(s7,1,10)='1550864580';
(可左右滑动)
如果查询项包含substr(s7,1,10),则查询时间在毫秒级,而之前需要30多秒。如果查询项不包含substr(s7,1,10),则跟不建索引时是一样的。如果想让第一个查询语句走索引,我们可以在建立索引时采用INCLUDE(S7)来实现。
5.Global Indexes(全局索引)
全局索引适合那些读多写少的场景。如果使用全局索引,读数据基本不损耗性能,所有的性能损耗都来源于写数据。数据表的添加、删除和修改都会更新相关的索引表(数据删除了,索引表中的数据也会删除;数据增加了,索引表的数据也会增加)。而查询数据的时候,Phoenix会通过索引表来快速低损耗的获取数据。默认情况下,如果你的查询语句中没有索引相关的列的时候,Phoenix不会使用索引。
6.Local Indexes(本地索引)
本地索引适合那些写多读少,或者存储空间有限的场景。和全局索引一样,Phoenix也会在查询的时候自动选择是否使用本地索引。本地索引之所以是本地,只要是因为索引数据和真实数据存储在同一台机器上,这样做主要是为了避免网络数据传输的开销。如果你的查询条件没有完全覆盖索引列,本地索引还是可以生效。因为无法提前确定数据在哪个Region上,所以在读数据的时候,还需要检查每个Region上的数据而带来一些性能损耗。
1.先删除之前建立的函数索引INDEX2_HBASE_TEST。
代码语言:javascript复制drop index INDEX2_HBASE_TEST on hbase_test;
(可左右滑动)
2.建立本地索引
代码语言:javascript复制create local index index2_hbase_test on hbase_test (s7);
(可左右滑动)
3.在查询项中不包含索引字段的条件下,一样查询比较快速。
代码语言:javascript复制select s2 from hbase_test where s7='13500591348';
select * from hbase_test where s7='13500591348';
(可左右滑动)
可以发现这2个查询语句返回时间都在毫秒级,而如果不建立索引,查询时间为35S以上。
7.总结
Phoenix的二级索引主要有两种,即全局索引和本地索引。全局索引适合那些读多写少的场景。如果使用全局索引,读数据基本不损耗性能,所有的性能损耗都来源于写数据。本地索引适合那些写多读少,或者存储空间有限的场景。
索引定义完之后,一般来说,Phoenix会判定使用哪个索引更加有效。但是,全局索引必须是查询语句中所有列都包含在全局索引中,它才会生效。举个例子,下面是创建索引的语句:
代码语言:javascript复制create index my_index on hbase_test (s6);
(可左右滑动)
而查询语句是
代码语言:javascript复制select s2 from hbase_test where s6='13505503576';
(可左右滑动)
上例就不会用到索引my_index。因为s2并没有包含在索引中。所以使用全局索引,必须要所有的列都包含在索引中。那么怎样才能使用索引呢?有三种方法。
1.创建索引时使用覆盖索引
代码语言:javascript复制CREATE INDEX index1_hbase_test ON hbase_test(s6) INCLUDE(s2)
(可左右滑动)
这种索引会把s2加到索引表里面,同时s2也会随着原数据表中的变化而变化。这种方式很明显的缺点是索引表的大小较大,然后就是全局索引不适合写特别多的情况。
这个查询效果具体可以参考第三章
2.使用类似于Oracle的Hint,强制索引。
代码语言:javascript复制select /* INDEX(hbase_test index1_hbase_test)*/ s5 from hbase_test where s6='13505503576';
(可左右滑动)
如果不带hint,查询时间为35s,带了hint强制使用索引后查询时间为0.099秒。
查询引擎会使用index1_hbase_test这个索引,由于它会发现索引表中没有s5数据,所以每一行它都会去原数据表中获取s5的值。这个强制索引只有在你认为索引有比较好的选择性的时候才是好的选择,也就是说s6等于13505503576的行数不多。不然的话,使用Phoenix默认的全表扫描的性能也许会更好。
3.创建本地索引
代码语言:javascript复制create local index index2_hbase_test on hbase_test (s7);
(可左右滑动)
本地索引和全局索引不同的是,查询语句中,即使所有的列都不在索引定义中,它也会使用索引,这是本地索引的默认行为。Phoenix知道原数据和索引数据在同一个RegionServer上,能保证索引查找是本地的。本地索引查询效果具体可参见第6章。
注:使用函数索引,查询语句中带上hint也没有作用。
参考:
https://phoenix.apache.org/secondary_indexing.html
https://www.cnblogs.com/haoxinyue/p/6724365.html
https://blog.csdn.net/u011491148/article/details/45749807
https://www.cnblogs.com/MOBIN/p/5467284.html
提示:代码块部分可以左右滑动查看噢
为天地立心,为生民立命,为往圣继绝学,为万世开太平。 温馨提示:要看高清无码套图,请使用手机打开并单击图片放大查看。
推荐关注Hadoop实操,第一时间,分享更多Hadoop干货,欢迎转发和分享。
原创文章,欢迎转载,转载请注明:转载自微信公众号Hadoop实操