第一章.整合Phoenix

1.Phoenix介绍

Phoenix定义:

  • Phoenix是HBase的开源SQL皮肤,可以使用标准JDBC API代替HBase客户端API来创建表,插入数据和查询HBase数据

Phoenix特点:

  • 容易集成,如Spark,Hive,Pig,Flume,和MAP Reduce
  • 操作简单,DML命令以及通过DDL命令创建和操作表和版本化增量更改
  • 支持HBase二级索引创建

Phoenix架构

$03[HBase-Phoenix] - 图1

2.Phoenix安装

  1. 官网地址: http://phoenix.apache.org/
  2. 上传并解压tar包
  1. tar -zxvf apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz -C /opt/module/
  2. mv apache-phoenix-5.0.0-HBase-2.0-bin phoenix-5.0.0
  1. 复制server包并拷贝到各个节点的hbase-2.0.5/lib
  1. cp /opt/module/phoenix-5.0.0/phoenix-5.0.0-HBase-2.0-server.jar /opt/module/hbase-2.0.5/lib
  2. xsync /opt/module/hbase-2.0.5/lib/phoenix-5.0.0-HBase-2.0-server.jar
  1. 配置环境变量
  1. #phoenix
  2. export PHOENIX_HOME=/opt/module/phoenix-5.0.0
  3. export PHOENIX_CLASSPATH=$PHOENIX_HOME
  4. export PATH=$PATH:$PHOENIX_HOME/bin
  1. 启动HBase(应先启动Zookeeper和Hadoop)
  1. start-hbase.sh
  1. 连接Phoenix
  1. /opt/module/phoenix-5.0.0/bin/sqlline.py hadoop102,hadoop103,hadoop104:2181

3.Phoenix Shell操作

1.schema的操作

  1. 创建schema
  1. 默认情况下,在Phoenix中不能直接创建schema,需要将如下的参数添加到Hbase中conf目录下的hbase-site.xml和Phoenix中bin目录的hbase-site.xml,更改完之后记得分发到其他节点
  1. <property>
  2. <name>phoenix.schema.isNamespaceMappingEnabled</name>
  3. <value>true</value>
  4. </property>
  1. 重新启动Hbase和连接Phoenix客户端
  1. start-hbase.sh
  2. sqlline.py hadoop102,hadoop103,hadoop104:2181
  1. 创建schema
  1. create schema bigdata;
  1. 注意在Phoenix中,schema名表名,字段名等会自动转换为大写,若要小写,使用双引号,如"student"

2. 表的操作

  1. 显示所有表
  1. ! table 或 ! tables

$03[HBase-Phoenix] - 图2

  1. 创建表
  1. # 直接指定单个列作为RowKey
  2. create table if not exists student(
  3. id varchar primary key,
  4. name varchar,
  5. addr varchar);
  6. # 指定多个列的联合作为RowKey
  7. create table if not exists us_population(
  8. state char(2) not null,
  9. city varchar not null,
  10. Population bigint
  11. constraint my_pk primary key (state,city));
  1. 插入数据
  1. upsert into student values('1001','zhangsan','beijing');
  1. 查询记录
  1. select * from student;
  2. select * from student where id = '1001';
  1. 删除记录
  1. delete from student where id = '1001';
  1. 删除表
  1. drop table student;
  1. 退出命令行
  1. !quit

3.表的映射

  1. 表的关系

默认情况下,直接在Hbase中创建的表,通过Phoenix是查看不到的,如果要在Phoenix中操作在Hbase中创建的表,则需要在Phoenix中进行表的映射,映射方式有两种: 视图映射和表映射

  1. 命令行中创建表test

Hbase中test表结构如下,两个列族info1,info2

Rowkey info1 info2
id name address

启动Hbase Shell

  1. hbase shell

创建HBase表test

  1. create 'test','info1','info2'
  1. 视图映射

Phoenix创建的视图是只读的,所以只能用来做查询,无法通过视图对原数据进行修改等操作,在Phoenix中创建关联test表的视图

  1. create view "test"(
  2. id varchar primary key,
  3. "info1"."name" varchar,
  4. "info2"."address" varchar
  5. );

删除视图

  1. drop view "test";
  1. 表映射

使用Apache Phoenix创建对Hbase的表映射,有两种方法

  1. # HBase中不存在表时
  2. 可以直接使用create table指令创建需要的表,系统将会自动在Phoenix和Hbase中创建person_infomation的表,并且根据指令内的参数对表结构进行初始化
  3. # 当HBase中已经存在表时
  4. 可以以类似创建视图的方式,创建关联表,只需要将create view 改为create table即可
  5. create table "test"(id varchar primary key,"info1"."name" varchar, "info2"."address" varchar) column_encoded_bytes=0;

4.表映射中数值类型的问题

  1. - Hbase中存储数值类型的值(如int,long等)会按照正常数字的补码进行存储. 而phoenix对数字的存储做了特殊的处理. phoenix 为了解决遇到正负数同时存在时,导致负数排到了正数的后面(负数高位为1,正数高位为0,字典序0 < 1)的问题。 phoenix在存储数字时会对高位进行转换.原来为1,转换为0, 原来为0,转换为1.
  2. - 因此,如果hbase表中的数据的写是由phoenix写入的,不会出现问题,因为对数字的编解码都是phoenix来负责。如果hbase表中的数据不是由phoenix写入的,数字的编码由hbase负责. 而phoenix读数据时要对数字进行解码。 因为编解码方式不一致。导致数字出错.
  1. 在hbase中创建表,并插入数值类型的数据
  1. create 'person','info'
  2. put 'person','1001','info:salary',Bytes.toBytes(123456)
  3. # 注意:如果要插入数字类型,需要通过Bytes.toBytes(123456)来实现
  1. 在Phoenix创建映射表并查询数据
  1. create table "person"(
  2. id varchar primary key,
  3. "info"."salary" integer
  4. )
  5. column_encoded_bytes=0;

$03[HBase-Phoenix] - 图3

可以看出: 数字显示有问题

  1. 解决方法

在Phoenix中创建表时使用无符号的数值类型unsigned_long

  1. create table "person"(
  2. id varchar primary key,
  3. "info"."salary" unsigned_long)
  4. column_encoded_bytes=0;

$03[HBase-Phoenix] - 图4

5.Phoenix JDBC操作

  1. Thin Client

启动query server

  1. queryserver.py startqu

创建项目并导入依赖

  1. <dependency>
  2. <groupId>org.apache.phoenix</groupId>
  3. <artifactId>phoenix-queryserver-client</artifactId>
  4. <version>5.0.0-HBase-2.0</version>
  5. </dependency>

编写代码

  1. package com.atguigu.hbaseapi;
  2. import org.apache.phoenix.queryserver.client.ThinClientUtil;
  3. import java.sql.Connection;
  4. import java.sql.DriverManager;
  5. import java.sql.PreparedStatement;
  6. import java.sql.ResultSet;
  7. public class PhoenixThin {
  8. public static void main(String[] args) throws Exception {
  9. // 1. 获取连接对象
  10. String url = ThinClientUtil.getConnectionUrl("hadoop102", 8765);
  11. Connection connection = DriverManager.getConnection(url);
  12. // 2. 编写SQL
  13. String sql = "select * from student";
  14. // 3. 预编译
  15. PreparedStatement preparedStatement = connection.prepareStatement(sql);
  16. // 4. 执行
  17. ResultSet resultSet = preparedStatement.executeQuery();
  18. // 5. 解析Result
  19. while (resultSet.next()){
  20. String id = resultSet.getString("id");
  21. String name = resultSet.getString("name");
  22. String addr = resultSet.getString("addr");
  23. System.out.println("id: "+id+", name: "+name+", addr: " +addr);
  24. }
  25. // 6. 关闭资源
  26. connection.close();
  27. }
  28. }
  1. Thick Client

在pom中添加依赖

  1. <dependency>
  2. <groupId>org.apache.phoenix</groupId>
  3. <artifactId>phoenix-core</artifactId>
  4. <version>5.0.0-HBase-2.0</version>
  5. <exclusions>
  6. <exclusion>
  7. <groupId>org.glassfish</groupId>
  8. <artifactId>javax.el</artifactId>
  9. </exclusion>
  10. </exclusions>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.glassfish</groupId>
  14. <artifactId>javax.el</artifactId>
  15. <version>3.0.1-b06</version>
  16. </dependency>

编写代码

  1. package com.atguigu.hbaseapi;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.util.Properties;
  7. public class PhoenixThink {
  8. public static void main(String[] args) throws Exception{
  9. // 1. 获取连接对象
  10. Properties properties = new Properties();
  11. properties.put("phoenix.schema.isNamespaceMappingEnabled", "true");
  12. Connection connection = DriverManager.getConnection("jdbc:phoenix:hadoop102:2181",properties);
  13. // 2. 编写SQL
  14. String sql = "select * from student";
  15. // 3. 预编译
  16. PreparedStatement preparedStatement = connection.prepareStatement(sql);
  17. // 4. 执行
  18. ResultSet resultSet = preparedStatement.executeQuery();
  19. // 5. 解析Result
  20. while (resultSet.next()){
  21. String id = resultSet.getString("id");
  22. String name = resultSet.getString("name");
  23. String addr = resultSet.getString("addr");
  24. System.out.println("id: "+id+", name: "+name+", addr: " +addr);
  25. }
  26. // 6. 关闭资源
  27. connection.close();
  28. }
  29. }

6.Phoenix二级索引

1.二级索引配置文件

添加如下配置到hbase的hbase-site.xml

  1. <!-- phoenix regionserver 配置参数-->
  2. <property>
  3. <name>hbase.regionserver.wal.codec</name>
  4. <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
  5. </property>

2.全局二级索引

  1. Global Index是默认的索引格式,创建全局索引时,会在Hbase中建立一张新表,也就是说索引数据和数据表是存放在不同的表中的,因此全局索引适用于多读少写的业务场景
  2. 写数据的时候,会消耗大量开销,因为索引表也要更新,而索引表是分布在不同的数据节点上的,跨节点的数据传输带来了较大的性能消耗
  3. 在读数据的时候Phoenix会选择索引表来降低查询消耗的时间

创建单个字段的全局索引

  1. CREATE INDEX my_index ON my_table (my_col);

$03[HBase-Phoenix] - 图5

  1. 在没有索引的情况下

$03[HBase-Phoenix] - 图6

$03[HBase-Phoenix] - 图7

$03[HBase-Phoenix] - 图8

  1. 在name字段上创建索引
  1. create index "index_student_name" on student (name);

查看Phoenix上索引表

$03[HBase-Phoenix] - 图9

$03[HBase-Phoenix] - 图10

$03[HBase-Phoenix] - 图11

$03[HBase-Phoenix] - 图12

创建携带其他字段的全局索引

  1. CREATE INDEX my_index ON my_table (v1) INCLUDE (v2);
  1. # 删除索引"index_student_name"
  2. drop index "index_student_name" on student;
  3. # 创建包含索引"index_student_name_include_addr"(是将数据打包进索引行中,查询时无需查询原表)
  4. create index "index_student_name_include_addr" on student (name) include (addr);
  1. 查看Phoenix上的索引表

$03[HBase-Phoenix] - 图13

$03[HBase-Phoenix] - 图14

$03[HBase-Phoenix] - 图15

$03[HBase-Phoenix] - 图16

3.本地二级索引

  1. Local Index使用于写操作频繁的场景

索引数据和数据表的数据时存放在同一张表中(且是同一个Region),避免了在写操作的时候往不同的服务器的索引表中写索引带来的额外开销

  1. 创建本地二级索引在name字段上
  1. create local index "local_index_student_name" on student (name);
  1. 查看Phoenix上的索引表

$03[HBase-Phoenix] - 图17

$03[HBase-Phoenix] - 图18

$03[HBase-Phoenix] - 图19

$03[HBase-Phoenix] - 图20

$03[HBase-Phoenix] - 图21

第二章.与Hive的集成

1.HBase与Hive的对比

  1. # Hive
  2. (1) 数据分析工具,本质就相当于将HDFS中已将存储的文件在mysql上做了一个双射关系,以方便使用HQL去管理,查询
  3. (2) 用于数据分析,清洗,Hive适用于离线的数据分析和清洗,延迟较高
  4. (3) 基于HDFS,MapReduce,Hive存储的数据依旧在DataNode上,编写的HQL语句终将转换为MapReduce代码执行
  5. ------------------------------------------------------------------------------------
  6. # HBase
  7. (1) 数据库, 是一种面向列族存储的非关系型数据库
  8. (2) 用于存储结构化和非结构化的数据, 适用于单表非关系型数据的存储,不适合做关联查询,类似JOIN等操作
  9. (3) 基于HDFS, 数据持久化存储的体现形式是HFile,存放于DataNode上,被Resionserver以region的形式进行管理
  10. (4) 延迟较低,接入在线业务使用,面对大量的企业数据,Hbase可以直接单表大量数据的存储,同时提供了高效的数据访问速度

2.HBase与Hive的集成使用

在hive-site.xml中添加zookeeper的属性

  1. <property>
  2. <name>hive.zookeeper.quorum</name>
  3. <value>hadoop102,hadoop103,hadoop104</value>
  4. </property>
  5. <property>
  6. <name>hive.zookeeper.client.port</name>
  7. <value>2181</value>
  8. </property>

案例一

建立Hive表,关联Hbase表,插入数据到Hive表的时候能够影响HBase表

  1. 在Hive表中创建表的同时关联HBase
  1. CREATE TABLE hive_hbase_emp_table(
  2. empno int,
  3. ename string,
  4. job string,
  5. mgr int,
  6. hiredate string,
  7. sal double,
  8. comm double,
  9. deptno int)
  10. STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
  11. WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
  12. TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");

提示: 完成之后,可以分别进入Hive和HBase中查看,都生成了对应的表

  1. 在hive中创建临时中间表,用于load文件中的数据
  1. CREATE TABLE emp(
  2. empno int,
  3. ename string,
  4. job string,
  5. mgr int,
  6. hiredate string,
  7. sal double,
  8. comm double,
  9. deptno int)
  10. row format delimited fields terminated by '\t';

提示: 不能将数据直接load进Hive所关联Hbase的那张表中

  1. 向HIve中间表load数据
  1. load data local inpath '/home/atguigu/emp.txt' into table emp;
  1. 通过insert指令将中间表的数据导入到Hive关联Hbase的那张表中
  1. insert into table hive_hbase_emp_table select * from emp;
  1. 查看Hive以及关联的Hbase表中是否已经同步插入了数据
  1. # Hive
  2. select * from hive_hbase_emp_table;
  3. # HBase
  4. scan 'hbase_emp_table'

案例二

在Hbase表中已经存储了某一张表hbase_emp_table,然后在hive中创建一个外部表来关联Hbase中的hbase_emp_table这张表,使之可以借助Hive来分析HBase这张表中的数据(在案例一的基础上)

  1. 在Hive中创建外部表
  1. CREATE EXTERNAL TABLE relevance_hbase_emp(
  2. empno int,
  3. ename string,
  4. job string,
  5. mgr int,
  6. hiredate string,
  7. sal double,
  8. comm double,
  9. deptno int)
  10. STORED BY
  11. 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
  12. WITH SERDEPROPERTIES ("hbase.columns.mapping" =
  13. ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
  14. TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
  1. 关联后就可以使用Hive函数进行一些分析操作
  1. select * from relevance_hbase_emp;