共计 7558 个字符,预计需要花费 19 分钟才能阅读完成。
Phoenix
Hbase 适合存储大量的对关系运算要求低的 NOSQL 数据,受 Hbase 设计上的限制不能直接使用原生的 API 执行在关系数据库中普遍使用的条件判断和聚合等操作。Hbase 很优秀,一些团队寻求在 Hbase 之上提供一种更面向普通开发人员的操作方式,Apache Phoenix 即是。
Phoenix 基于 Hbase 给面向业务的开发人员提供了以标准 SQL 的方式对 Hbase 进行查询操作,并支持标准 SQL 中大部分特性: 条件运算, 分组,分页,等高级查询语法。
Phoenix1、Phoenix 搭建 1、关闭 hbase 集群,在 master 中执行 2、上传解压配置环境变量 3、将 phoenix-4.15.0-HBase-1.4-server.jar 复制到所有节点的 hbase lib 目录下 4、启动 hbase,在 master 中执行 5、配置环境变量 2、Phoenix 使用 1、连接 sqlline2、常用命令 3、phoenix 表映射 3.1、视图映射 3.2、表映射 3、Phoenix 二级索引 1、开启索引支持 2、创建索引 2.1、全局索引 2.2、本地索引 2.3、覆盖索引 4、Phoenix JDBC
1、Phoenix 搭建
Phoenix 4.15 HBase 1.4.6 hadoop 2.7.6
1、关闭 hbase 集群,在 master 中执行
stop-hbase.sh
2、上传解压配置环境变量
解压
tar -xvf apache-phoenix-4.15.0-HBase-1.4-bin.tar.gz -C /usr/local/soft/
改名
mv apache-phoenix-4.15.0-HBase-1.4-bin phoenix-4.15.0
mv phoenix-4.15.0-HBase-1.4-server.jar ../hbase-1.4.6/lib/
3、将 phoenix-4.15.0-HBase-1.4-server.jar 复制到所有节点的 hbase lib 目录下
scp /usr/local/soft/phoenix-4.15.0/phoenix-4.15.0-HBase-1.4-server.jar master:/usr/local/soft/hbase-1.4.6/lib/
scp /usr/local/soft/phoenix-4.15.0/phoenix-4.15.0-HBase-1.4-server.jar node1:/usr/local/soft/hbase-1.4.6/lib/
scp /usr/local/soft/phoenix-4.15.0/phoenix-4.15.0-HBase-1.4-server.jar node2:/usr/local/soft/hbase-1.4.6/lib/
4、启动 hbase,在 master 中执行
start-hbase.sh
5、配置环境变量
vim /etc/profile
2、Phoenix 使用
1、连接 sqlline
sqlline.py master,node1,node2
# 出现
163/163 (100%) Done
Done
sqlline version 1.5.0
0: jdbc:phoenix:master,node1,node2>
2、常用命令
# 1、创建表
CREATE TABLE IF NOT EXISTS STUDENT (
id VARCHAR NOT NULL PRIMARY KEY,
name VARCHAR,
age BIGINT,
gender VARCHAR ,
clazz VARCHAR
);
# 2、显示所有表
!table
# 3、插入数据
upsert into STUDENT values('1500100004','葛德曜',24,'男','理科三班');
upsert into STUDENT values('1500100005','宣谷芹',24,'男','理科六班');
upsert into STUDENT values('1500100006','羿彦昌',24,'女','理科三班');
# 4、查询数据, 支持大部分 sql 语法,select * from STUDENT ;
select * from STUDENT where age=24;
select gender ,count(*) from STUDENT group by gender;
select * from student order by gender;
# 5、删除数据
delete from STUDENT where id='1500100006';
# 6、删除表
drop table STUDENT;
# 7、退出命令行
!quit
更多语法参照官网
https://phoenix.apache.org/language/index.html#upsert_select
3、phoenix 表映射
默认情况下,直接在 hbase 中创建的表,通过 phoenix 是查看不到的
如果需要在 phoenix 中操作直接在 hbase 中创建的表,则需要在 phoenix 中进行表的映射。映射方式有两种:视图映射和表映射
3.1、视图映射
Phoenix 创建的视图是只读的,所以只能用来做查询,无法通过视图对源数据进行修改等操作
# hbase shell 进入 hbase 命令行
hbase shell
# 创建 hbase 表
create 'test','name','company'
# 插入数据
put 'test','001','name:firstname','zhangsan1'
put 'test','001','name:lastname','zhangsan2'
put 'test','001','company:name','数加'
put 'test','001','company:address','合肥'
# 在 phoenix 创建视图,primary key 对应到 hbase 中的 rowkey
create view "test"(
empid varchar primary key,
"name"."firstname" varchar,
"name"."lastname" varchar,
"company"."name" varchar,
"company"."address" varchar
)column_encoded_bytes=0;
CREATE view "student" (
id VARCHAR NOT NULL PRIMARY KEY,
"info"."name" VARCHAR,
"info"."age" VARCHAR,
"info"."gender" VARCHAR ,
"info"."clazz" VARCHAR
) column_encoded_bytes=0;
# 在 phoenix 查询数据,表名通过双引号引起来
select * from "test";
# 删除视图
drop view "test";
3.2、表映射
使用 Apache Phoenix 创建对 HBase 的表映射,有两类:
1)当 HBase 中已经存在表时,可以以类似创建视图的方式创建关联表,只需要将 create view 改为 create table 即可。
2)当 HBase 中不存在表时,可以直接使用 create table 指令创建需要的表,并且在创建指令中可以根据需要对 HBase 表结构进行显示的说明。
第 1)种情况下,如在之前的基础上已经存在了 test 表,则表映射的语句如下:
create table "test" (
empid varchar primary key,
"name"."firstname" varchar,
"name"."lastname"varchar,
"company"."name" varchar,
"company"."address" varchar
)column_encoded_bytes=0;
upsert into "test" values('1','2','3','4','5');
CREATE table "student" (
id VARCHAR NOT NULL PRIMARY KEY,
"info"."name" VARCHAR,
"info"."age" VARCHAR,
"info"."gender" VARCHAR ,
"info"."clazz" VARCHAR
) column_encoded_bytes=0;
upsert into "student" values('1500110004','葛德曜','24','n ü','理科三班');
使用 create table 创建的关联表,如果对表进行了修改,源数据也会改变,同时如果关联表被删除,源表也会被删除。但是视图就不会,如果删除视图,源数据不会发生改变。
3、Phoenix 二级索引
对于 Hbase,如果想精确定位到某行记录,唯一的办法就是通过 rowkey 查询。如果不通过 rowkey 查找数据,就必须逐行比较每一行的值,对于较大的表,全表扫描的代价是不可接受的。
1、开启索引支持
# 关闭 hbase 集群
stop-hbase.sh
# 在 /usr/local/soft/hbase-1.4.6/conf/hbase-site.xml 中增加如下配置
hbase.regionserver.wal.codec
org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec
hbase.rpc.timeout
60000000
hbase.client.scanner.timeout.period
60000000
phoenix.query.timeoutMs
60000000
# 同步到所有节点
scp hbase-site.xml node1:`pwd`
scp hbase-site.xml node2:`pwd`
# 修改 phoenix 目录下的 bin 目录中的 hbase-site.xml
hbase.rpc.timeout
60000000
hbase.client.scanner.timeout.period
60000000
phoenix.query.timeoutMs
60000000
# 启动 hbase
start-hbase.sh
# 重新进入 phoenix 客户端
sqlline.py master,node1,node2
2、创建索引
2.1、全局索引
(全局索引创建完成后,默认在 hbase 中是可以看到的,可以操作,如 scan、count 等,可以获取数据)
全局索引适合读多写少的场景。如果使用全局索引,读数据基本不损耗性能,所有的性能损耗都来源于写数据。数据表的添加、删除和修改都会更新相关的索引表(数据删除了,索引表中的数据也会删除;数据增加了,索引表的数据也会增加)
注意: 对于全局索引在默认情况下,在查询语句中检索的列如果不在索引表中,Phoenix 不会使用索引表将,除非使用 hint。
# 创建 DIANXIN.sql
CREATE TABLE IF NOT EXISTS DIANXIN (
mdn VARCHAR ,
start_date VARCHAR ,
end_date VARCHAR ,
county VARCHAR,
x DOUBLE ,
y DOUBLE,
bsid VARCHAR,
grid_id VARCHAR,
biz_type VARCHAR,
event_type VARCHAR ,
data_source VARCHAR ,
CONSTRAINT PK PRIMARY KEY (mdn,start_date)
) column_encoded_bytes=0;
# 上传数据 DIANXIN.csv
# 导入数据
psql.py master,node1,node2 DIANXIN.sql DIANXIN.csv
# 创建全局索引
CREATE INDEX DIANXIN_INDEX ON DIANXIN (end_date);
# 查询数据 (索引未生效)
select * from DIANXIN where end_date = '20180503154014';
# 强制使用索引(索引生效)hint
select /*+ INDEX(DIANXIN DIANXIN_INDEX) */ * from DIANXIN where end_date = '20180503154014';
select /*+ INDEX(DIANXIN DIANXIN_INDEX) */ * from DIANXIN where end_date = '20180503154014' and start_date = '20180503154614';
# 取索引列,(索引生效)select end_date from DIANXIN where end_date = '20180503154014';
# 创建多列索引
CREATE INDEX DIANXIN_INDEX1 ON DIANXIN (end_date,COUNTY);
注意:查询的时候,如果前面出现的某一列既不在 rowkey 中,也不在索引列中,默认是不会生效的。# 多条件查询(索引生效)select end_date,MDN,COUNTY from DIANXIN where end_date = '20180503154014' and COUNTY = '8340104';
# 查询所有列 (索引未生效)
select * from DIANXIN where end_date = '20180503154014' and COUNTY = '8340104';
# 查询所有列(索引生效)select /*+ INDEX(DIANXIN DIANXIN_INDEX1) */ * from DIANXIN where end_date = '20180503154014' and COUNTY = '8340104';
# 单条件 (索引未生效)
select end_date from DIANXIN where COUNTY = '8340103';
# 单条件 (索引生效) end_date 在前
select COUNTY from DIANXIN where end_date = '20180503154014';
# 删除索引
drop index DIANXIN_INDEX on DIANXIN;
2.2、本地索引
本地索引适合写多读少的场景,或者存储空间有限的场景。和全局索引一样,Phoenix 也会在查询的时候自动选择是否使用本地索引。本地索引因为索引数据和原数据存储在同一台机器上,避免网络数据传输的开销,所以更适合写多的场景。由于无法提前确定数据在哪个 Region 上,所以在读数据的时候,需要检查每个 Region 上的数据从而带来一些性能损耗。
注意: 对于本地索引,查询中无论是否指定 hint 或者是查询的列是否都在索引表中,都会使用索引表。
# 创建本地索引
CREATE LOCAL INDEX DIANXIN_LOCAL_IDEX ON DIANXIN(grid_id);
# 索引生效
select grid_id from dianxin where grid_id='117285031820040';
# 索引生效
select * from dianxin where grid_id='117285031820040';
2.3、覆盖索引
覆盖索引是把原数据存储在索引数据表中,这样在查询时不需要再去 HBase 的原表获取数据就,直接返回查询结果。(相当于全局索引 + 数据)
注意:查询是 select 的列和 where 的列都需要在索引中出现。
# 创建覆盖索引
CREATE INDEX DIANXIN_INDEX_COVER ON DIANXIN (x,y) INCLUDE (county);
# 查询所有列 (索引未生效)
select * from dianxin where x=117.288 and y =31.822;
select * from DIANXIN where x=117.288 and y =31.822;
# 强制使用索引 (索引生效)
select /*+ INDEX(DIANXIN DIANXIN_INDEX_COVER) */ * from dianxin where x=117.288 and y =31.822;
# 查询索引中的列 (索引生效) mdn 是 DIANXIN 表的 RowKey 中的一部分
select x,y,county from dianxin where x=117.288 and y =31.822;
select mdn,x,y,county from dianxin where x=117.288 and y =31.822;
# 查询条件必须放在索引中 select 中的列可以放在 INCLUDE(将数据保存在索引中)select /*+ INDEX(DIANXIN DIANXIN_INDEX_COVER) */ x,y,count(*) from dianxin group by x,y;
4、Phoenix JDBC
# 导入依赖
org.apache.phoenix
phoenix-core
4.15.0-HBase-1.4
Connection conn = DriverManager.getConnection("jdbc:phoenix:master,node1,node2:2181");
PreparedStatement ps = conn.prepareStatement("select /*+ INDEX(DIANXIN DIANXIN_INDEX) */ * from DIANXIN where end_date=?");
ps.setString(1, "20180503212649");
ResultSet rs = ps.executeQuery();
while (rs.next()) {String mdn = rs.getString("mdn");
String start_date = rs.getString("start_date");
String end_date = rs.getString("end_date");
String x = rs.getString("x");
String y = rs.getString("y");
String county = rs.getString("county");
System.out.println(mdn + "t" + start_date + "t" + end_date + "t" + x + "t" + y + "t" + county);
}
ps.close();
conn.close();
文章来源: Phoenix 使用