文章目录
Hbase二级索引_Hive on Hbase 及phoenix详解
知识点02:课程目标
知识点03:SQL on Hbase
知识点04:Hive on Hbase 介绍
知识点05:Hive on Hbase 配置
知识点06:Hive on Hbase 实现
知识点07:二级索引问题
知识点08:Phoenix的介绍
知识点09:Phoenix的安装配置
知识点10:Phoenix的语法:DDL:NS
知识点11:Phoenix的语法:DDL:Table
知识点12:Phoenix的语法:DML:upsert
知识点13:Phoenix的语法:DML:delete
知识点14:Phoenix的语法:DQL:select
知识点15:Phoenix的使用:预分区
知识点16:Phoenix的使用:加盐salt
知识点17:Phoenix的使用:视图
知识点18:Phoenix的使用:JDBC
Hbase二级索引_Hive on Hbase 及phoenix详解
知识点02:课程目标
SQL on Hbase
Hive on Hbase【了解】
使用Hive中的SQL语句来实现对Hbase数据的操作
本质:通过MapReduce来实现读写Hbase
Phoenix【重点】
专门为Hbase所设计的一个工具
本质:直接封装Hbase的JavaAPI来实现的
功能、应用场景、基本原理、特点
基本使用:语法【upsert、delete、select】
知识点03:SQL on Hbase
问题
Hbase是列存储NoSQL,不支持SQL,开发接口不方便大部分用户使用,怎么办?
分析
应用场景:应用系统或者大数据存储系统
大数据存储系统:大数据工程师
利用Hbase来存储大量要分析处理的数据
使用JavaAPI通过MapReduce或者通过Spark来实现数据的读写
应用系统:Java工程师、数据分析师
利用Hbase来存储大量的商品数据、订单数据,来提供高性能的查询
问题:Java人员不会Hbase Java API,对于数据库会JDBC
解决:需要一个工具能让Hbase支持SQL,支持JDBC方式对Hbase进行处理
Hbase的结构是否能实现基于SQL的查询操作?
普通表数据:按行操作idnameagesexaddr
001zhangsan18nullshanghai
002lisi20femalenull
003wangwunullmalebeijing
……
Hbase数据:按列操作rowkeycf1:idcf1:namecf1:agecf2:sexcf2:addr
zhangsan_001001zhangsan18nullshanghai
lisi_002002lisi20femalenull
wangwu_003003wangwunullmalebeijing
……
可以基于Hbase数据构建结构化的数据形式
可以用SQL来实现处理
实现
将Hbase表中每一行对应的所有列构建一张完整的结构化表
如果这一行没有这一列,就补null
Hive:通过MapReduce来实现
Phoenix:通过Hbase API封装实现的
总结
原因:满足各种应用场景下,对于Hbase使用的方式,基于SQL方式会更加通用
实现:将整张表的数据构建结构化形式,每一行没有列就补null
原理:将SQL转换成了Hbase的客户端操作来实现的
知识点04:Hive on Hbase 介绍
功能 :实现Hive与Hbase集成,使用Hive SQL对Hbase的数据进行处理
原理
Hive的功能:使用HQL对表的数据进行处理
本质:通过MapReduce对HDFS中的文件进行处理
原理
TextInputFormat:读文件
TextOutputFormat:写文件
MapReduce的功能:读取数据进行分布式计算
InputFormat:输入类
TextInputFormat:默认的输入类,用于读取文件系统
DBInputFormat:用于读取JDBC数据库
实现Sqoop导入的:将MySQL数据导入到Hive或者HDFS
TableInputFormat:用于读取Hbase数据
OutputFormat:输出类
TextOutputFormat:默认的输出类,用于将结果写入文件系统
DBOutputFormat:用于写入JDBC数据库
实现Sqoop导出的:将HDFS数据写入MySQL
TableOutputFormat:用于写入HBase数据库
原理 :Hive可以通过MapReduce来实现映射读写Hbase表的数据
特点
优点 :支持完善的SQL语句,可以实现各种复杂SQL的数据处理及计算,通过分布式计算程序实现,对大数据量的数据处理比较友好
缺点 :不支持二级索引,数据量不是特别大的情况下,性能一般
应用
知识点05:Hive on Hbase 配置
需求
配置Hive与Hbase集成,实现Hive中可以读写Hbase表
分析
step1:修改Hive配置文件,指定Hbase的Zookeeper地址
step2:按顺序启动HDFS、ZK、Hbase、Hive
实现
全部操作在第三台机器
修改hive-site.xml:Hive通过SQL访问Hbase,就是Hbase的客户端,就要连接zookeepercd /export/server/hive-2.1.0-bin/
vim conf/hive-site.xml
<property>
<name>hive.zookeeper.quorum</name>
<value>node1,node2,node3</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>node1,node2,node3</value>
</property>
<property>
<name>hive.server2.enable.doAs</name>
<value>false</value>
</property>
修改hive-env.shexport HBASE_HOME=/export/server/hbase-2.1.0
启动HDFS、ZK、Hbase:第一台机器start-dfs.sh
/export/server/zookeeper-3.4.6/bin/start-zk-all.sh
start-hbase.sh
启动Hive和YARN:第三台机器#启动YARN
start-yarn.sh
#先启动metastore服务
start-metastore.sh
#然后启动hiveserver
start-hiveserver2.sh
#然后启动beeline
start-beeline.sh
总结
先配置Hive的配置文件:添加Hbase的地址
然后按照先后顺序启动即可
知识点06:Hive on Hbase 实现
需求
分析
step1:如果表在Hbase中没有,Hive中没有,在Hive中创建表,指定在Hbase中创建关联表
场景比较少
在Hive中建一张表,自动在Hbase中也创建一张对应的表
step2:如果表在Hbase中有,但是Hive中没有,Hive中创建一张外部表,关联Hbase表
主要应用的方式
Hbase中的表已经存在,已经有数据,构建一张Hive关联表,使用SQL进行查询
实现
第三台机器测试
如果Hbase中表不存在:【用的比较少】
创建测试数据文件vim /export/data/hive-hbase.txt
1,zhangsan,80
2,lisi,60
3,wangwu,30
4,zhaoliu,70
创建测试表--创建测试数据库
create database course;
--切换数据库
use course;
--创建原始数据表
create external table if not exists course.score(
id int,
cname string,
score int
) row format delimited fields terminated by ',' stored as textfile ;
--加载数据文件
load data local inpath '/export/data/hive-hbase.txt' into table score;
创建一张Hive与HBASE的映射表create table course.hbase_score(
id int,
cname string,
score int
)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties("hbase.columns.mapping" = "cf:name,cf:score")
tblproperties("hbase.table.name" = "hbase_score");
将测试表的数据写入映射表set hive.exec.mode.local.auto=true;
insert overwrite table course.hbase_score select id,cname,score from course.score;
如果Hbase中表已存在,只能创建外部表 create external table course.t1(
key string,
name string,
age string,
addr string,
phone string
)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties("hbase.columns.mapping" = ":key,basic:name,basic:age,other:addr,other:phone")
tblproperties("hbase.table.name" = "itcast:t1");
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gNcVCpdb-1616545523608)(20210323_分布式NoSQL列存储数据库Hbase(六).assets/image-20210323160741636.png)]
总结
Hive中的只是关联表,并没有数据,数据存储在Hbase表中
在Hive中创建Hbase的关联表,关联成功后,使用SQL处理关联表
如果Hbase中表不存在,默认使用Hive的第一列作为rowkey
如果Hbase中表已存在,只能建外部表,使用:key来表示rowkey
HIve中与Hbase关联的表,不能使用load加载,只能使用insert,通过MR读写数据
知识点07:二级索引问题
问题
Hbase使用Rowkey作为唯一索引,需要构建二级索引来解决查询问题,如何构建二级索引以及维护索引表?
分析
step1:基于存储和常用查询需求,构建数据表
step2:基于其他查询需求,构建索引表
step3:先查询索引表,再查询数据表
step4:自动维护索引表与原始数据表的数据一致性
实现
构建数据表rowkey:name_ididnameagesexaddr
zhangsan_001001zhangsan18maleshanghai
lisi_002002lisi18femalebeijing
zhangsan_003003zhangsan20male
……
构建索引表rowkey:id_namecol:原始数据表的rowkey
001_zhangsanzhangsan_001
002_lisilisi_002
003_zhangsanzhangsan_003
……
查询:根据id查询
先查询索引表,获取原表的Rowkey
再根据原表Rowkey查询原表的数据
维护
当原表数据需要进行增删改时,索引表自动进行同步增删改对应的数据,保持一致性
解决方案
总结
需求:必须根据不同的查询条件,创建不同的索引表,并且维护所有索引表与原始数据表的同步
解决:通过Phoenix自带的协处理器来实现
知识点08:Phoenix的介绍
功能
专门基于Hbase所设计的SQL on Hbase 工具
使用Phoenix实现基于SQL操作Hbase
使用Phoenix自动构建二级索引并维护二级索引
原理
上层提供了SQL接口
底层全部通过Hbase Java API来实现,通过构建一系列的Scan和Put来实现数据的读写
功能非常丰富
底层封装了大量的内置的协处理器,可以实现各种复杂的处理需求,例如二级索引等
特点
优点
缺点
Hive on Hbase对比
Hive:SQL更加全面,但是不支持二级索引,底层通过分布式计算工具来实现
Phoenix:SQL相对支持不全面,但是性能比较好,直接使用HbaseAPI,支持索引实现
应用
Phoenix适用于任何需要使用SQL或者JDBC来快速的读写Hbase的场景
或者需要构建及维护二级索引场景
知识点09:Phoenix的安装配置
需求
http://phoenix.apache.org/
安装部署配置Phoenix,集成Hbase
分析
step1:上传解压安装
step2:修改配置,指定Hbase连接地址
step3:启动Phoenix,连接Hbase
实现
下载:http://phoenix.apache.org/download.html
第一台机器上传cd /export/software/
rz
第一台机器解压tar -zxvf apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz -C /export/server/
cd /export/server/
mv apache-phoenix-5.0.0-HBase-2.0-bin phoenix-5.0.0-HBase-2.0-bin
修改三台Linux文件句柄数vim /etc/security/limits.conf
#在文件的末尾添加以下内容,*号不能去掉
* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096
将Phoenix所有jar包分发到Hbase的lib目录下#拷贝到第一台机器
cd /export/server/phoenix-5.0.0-HBase-2.0-bin/
cp phoenix-* /export/server/hbase-2.1.0/lib/
cd /export/server/hbase-2.1.0/lib/
#分发给第二台和第三台
scp phoenix-* node2:$PWD
scp phoenix-* node3:$PWD
修改hbase-site.xml,添加一下属性cd /export/server/hbase-2.1.0/conf/
vim hbase-site.xml
<!-- 关闭流检查,从2.x开始使用async -->
<property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>false</value>
</property>
<!-- 支持HBase命名空间映射 -->
<property>
<name>phoenix.schema.isNamespaceMappingEnabled</name>
<value>true</value>
</property>
<!-- 支持索引预写日志编码 -->
<property>
<name>hbase.regionserver.wal.codec</name>
<value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
</property>
<!-- 配置NS映射 -->
<property>
<name>phoenix.schema.isNamespaceMappingEnabled</name>
<value>true</value>
</property>
同步给其他两台机器scp hbase-site.xml node2:$PWD
scp hbase-site.xml node3:$PWD
同步给Phoenixcp hbase-site.xml /export/server/phoenix-5.0.0-HBase-2.0-bin/bin/
重启Hbasestop-hbase.sh
start-hbase.sh
启动Phoenixcd /export/server/phoenix-5.0.0-HBase-2.0-bin/
bin/sqlline.py node1:2181
测试!tables
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KuMfWPJo-1616545523612)(20210323_分布式NoSQL列存储数据库Hbase(六).assets/image-20210323170434725.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nqVKRbLI-1616545523613)(20210323_分布式NoSQL列存储数据库Hbase(六).assets/image-20210323170543556.png)]
总结
知识点10:Phoenix的语法:DDL:NS
http://phoenix.apache.org/language/index.html
需求
分析
step1:创建Namespace
step2:切换Namespace
step3:删除Namespace
实现
总结
基本与SQL语法一致
注意:Phoenix中默认会将所有字符转换为大写,如果想要使用小写字母,必须加上双引号
知识点11:Phoenix的语法:DDL:Table
需求
实现基于SQL的数据表管理:创建、列举、查看、删除
分析
step1:列举当前所有的表
step2:创建表
step3:查询表信息
step4:删除表
实现
列举!tables
创建
语法:http://phoenix.apache.org/language/index.html#create_tableCREATE TABLE my_schema.my_table (
id BIGINT not null primary key,
date Date
);
CREATE TABLE my_table (
id INTEGER not null primary key desc,
m.date DATE not null,
m.db_utilization DECIMAL,
i.db_utilization
) m.VERSIONS='3';
CREATE TABLE stats.prod_metrics (
host char(50) not null,
created_date date not null,
txn_count bigint
CONSTRAINT pk PRIMARY KEY (host, created_date)
);
CREATE TABLE IF NOT EXISTS "my_case_sensitive_table"(
"id" char(10) not null primary key,
"value" integer
) DATA_BLOCK_ENCODING='NONE',VERSIONS=5,MAX_FILESIZE=2000000
split on (?, ?, ?);
CREATE TABLE IF NOT EXISTS my_schema.my_table (
org_id CHAR(15),
entity_id CHAR(15),
payload binary(1000),
CONSTRAINT pk PRIMARY KEY (org_id, entity_id)
) TTL=86400
如果Hbase中没有这个表use default;
create table if not exists ORDER_DTL(
ID varchar primary key,
C1.STATUS varchar,
C1.PAY_MONEY float,
C1.PAYWAY integer,
C1.USER_ID varchar,
C1.OPERATION_DATE varchar,
C1.CATEGORY varchar
);
如果Hbase中已存在会自动关联create table if not exists ORDER_INFO(
"ROW" varchar primary key,
"C1"."USER_ID" varchar,
"C1"."OPERATION_DATE" varchar,
"C1"."PAYWAY" varchar,
"C1"."PAY_MONEY" varchar,
"C1"."STATUS" varchar,
"C1"."CATEGORY" varchar
) column_encoded_bytes=0 ;
总结
创建表时,必须指定主键作为Rowkey,主键列不能加列族[/list] create table if not exists ORDER_INFO(
–不能这么写
“C1”.“ROW” varchar primary key,
“C1”.“USER_ID” varchar,
“C1”.“OPERATION_DATE” varchar,
“C1”.“PAYWAY” varchar,
“C1”.“PAY_MONEY” varchar,
“C1”.“STATUS” varchar,
“C1”.“CATEGORY” varchar
) column_encoded_bytes=0 ;
- Phoenix 4.8版本之前只要创建同名的Hbase表,会自动关联数据
- Phoenix 4.8版本以后,不推荐关联表的方式
- 推荐使用视图关联的方式来实现,如果你要使用关联表的方式,必须加上以下参数
```
column_encoded_bytes=0 ;
```
- 如果关联已存在的表,Rowkey字段叫做ROW,使用时必须加上双引号
select “ROW”,“C1”.USER_ID,“C1”.“PAYWAY” from ORDER_INFO;
知识点12:Phoenix的语法:DML:upsert
列名数值描述Rowkey02602f66-adc7-40d4-8485-76b5632b5b53行健,编码生成USER_ID4944191用户idOPERATION_DATE2020-04-25 12:09:16操作时间PAYWAY1支付方式PAY_MONEY4070支付金额STATUS已提交提交状态CATEGORY手机;分类
需求
基于order_info订单数据实现DML插入数据
分析
Phoenix中插入更新的命令为:upsert
功能:insert + update
MySQL:replace
如果存在就更新,如果不存在就插入
语法及示例UPSERT INTO TEST VALUES('foo','bar',3);
UPSERT INTO TEST(NAME,ID) VALUES('foo',123);
UPSERT INTO TEST(ID, COUNTER) VALUES(123, 0) ON DUPLICATE KEY UPDATE COUNTER = COUNTER + 1;
UPSERT INTO TEST(ID, MY_COL) VALUES(123, 0) ON DUPLICATE KEY IGNORE;
实现
插入一条数据upsert into order_info values('z8f3ca6f-2f5c-44fd-9755-1792de183845','4944191','2020-04-25 12:09:16','1','4070','未提交','电脑');
更新USERID为123456upsert into order_info("ROW","USER_ID") values('z8f3ca6f-2f5c-44fd-9755-1792de183845','123456');
总结
语法类似于insert语法
功能:insert + update
知识点13:Phoenix的语法:DML:delete
需求
基于order_info订单数据实现DML删除数据
分析
实现
总结
知识点14:Phoenix的语法:DQL:select
需求
基于order_info订单数据实现DQL查询数据
分析
实现
查询支付方式为1的数据select "ROW",payway,pay_money,category from order_info where payway = '1';
查询每种支付方式对应的用户人数,并且按照用户人数降序排序
select
payway,
count(distinct user_id) as numb
from order_info
group by payway
order by numb desc;
查询数据的第60行到66行--以前的写法:limit M,N
--M:开始位置
--N:显示的条数
--Phoenix的写法:limit N offset M
select * from order_info limit 6 offset 60;//总共66行,显示最后6行
函数支持
http://phoenix.apache.org/language/functions.html
总结
基本查询与MySQL也是一致的
写的时候注意数据类型以及大小写的问题即可
如果遇到SQL报错,检查语法是否支持
知识点15:Phoenix的使用:预分区
知识点16:Phoenix的使用:加盐salt
知识点17:Phoenix的使用:视图
需求
直接关联Hbase中的表,会导致误删除,对数据的权限会有影响,容易出现问题,如何避免?
分析
Phoenix中建议使用视图的方式来关联Hbase中已有的表
通过构建关联视图,可以解决大部分数据查询的数据,不影响数据
视图:理解为只读的表
实现
创建视图,关联Hbase中已经存在的表create view if not exists "MOMO_CHAT"."MSG" (
"pk" varchar primary key, -- 指定ROWKEY映射到主键
"C1"."msg_time" varchar,
"C1"."sender_nickyname" varchar,
"C1"."sender_account" varchar,
"C1"."sender_sex" varchar,
"C1"."sender_ip" varchar,
"C1"."sender_os" varchar,
"C1"."sender_phone_type" varchar,
"C1"."sender_network" varchar,
"C1"."sender_gps" varchar,
"C1"."receiver_nickyname" varchar,
"C1"."receiver_ip" varchar,
"C1"."receiver_account" varchar,
"C1"."receiver_os" varchar,
"C1"."receiver_phone_type" varchar,
"C1"."receiver_network" varchar,
"C1"."receiver_gps" varchar,
"C1"."receiver_sex" varchar,
"C1"."msg_type" varchar,
"C1"."distance" varchar
);
查询数据select
"pk",
"C1"."msg_time",
"C1"."sender_account",
"C1"."receiver_account"
from "MOMO_CHAT"."MSG"
limit 10;
总结
知识点18:Phoenix的使用:JDBC
需求
工作中实际使用SQL,会基于程序中使用JDBC的方式来提交SQL语句,在Phoenix中如何实现?
分析
实现
构建JDBC连接Phoenixpackage cn.itcast.momo_chat.service.impl;
import cn.itcast.momo_chat.entity.Msg;
import cn.itcast.momo_chat.service.ChatMessageService;
import org.apache.phoenix.jdbc.PhoenixDriver;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName PhoenixChatMessageService
* @Description TODO JDBC连接Phoenix实现数据查询
* @Create By Frank
*/
public class PhoenixChatMessageService implements ChatMessageService {
private Connection connection;
public PhoenixChatMessageService() throws ClassNotFoundException, SQLException {
try {
//申明驱动类
Class.forName(PhoenixDriver.class.getName());
// System.out.println(PhoenixDriver.class.getName());
//构建连接
connection = DriverManager.getConnection("jdbc:phoenix:node1,node2,node3:2181");
} catch (ClassNotFoundException e) {
throw new RuntimeException("加载Phoenix驱动失败!");
} catch (SQLException e) {
throw new RuntimeException("获取Phoenix JDBC连接失败!");
}
}
@Override
public List<Msg> getMessage(String date, String sender, String receiver) throws Exception {
PreparedStatement ps = connection.prepareStatement(
"SELECT * FROM MOMO_CHAT.MSG T WHERE substr("msg_time", 0, 10) = ? "
+ "AND T."sender_account" = ? "
+ "AND T."receiver_account" = ? ");
ps.setString(1, date);
ps.setString(2, sender);
ps.setString(3, receiver);
ResultSet rs = ps.executeQuery();
List<Msg> msgList = new ArrayList<>();
while(rs.next()) {
Msg msg = new Msg();
msg.setMsg_time(rs.getString("msg_time"));
msg.setSender_nickyname(rs.getString("sender_nickyname"));
msg.setSender_account(rs.getString("sender_account"));
msg.setSender_sex(rs.getString("sender_sex"));
msg.setSender_ip(rs.getString("sender_ip"));
msg.setSender_os(rs.getString("sender_os"));
msg.setSender_phone_type(rs.getString("sender_phone_type"));
msg.setSender_network(rs.getString("sender_network"));
msg.setSender_gps(rs.getString("sender_gps"));
msg.setReceiver_nickyname(rs.getString("receiver_nickyname"));
msg.setReceiver_ip(rs.getString("receiver_ip"));
msg.setReceiver_account(rs.getString("receiver_account"));
msg.setReceiver_os(rs.getString("receiver_os"));
msg.setReceiver_phone_type(rs.getString("receiver_phone_type"));
msg.setReceiver_network(rs.getString("receiver_network"));
msg.setReceiver_gps(rs.getString("receiver_gps"));
msg.setReceiver_sex(rs.getString("receiver_sex"));
msg.setMsg_type(rs.getString("msg_type"));
msg.setDistance(rs.getString("distance"));
msgList.add(msg);
}
return msgList;
}
@Override
public void close() {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
ChatMessageService chatMessageService = new PhoenixChatMessageService();
List<Msg> message = chatMessageService.getMessage("2021-03-22", "17351912952", "17742251415");
for (Msg msg : message) {
System.out.println(msg);
}
chatMessageService.close();
}
}
运行查看结果
总结
Phoenix支持SQL
支持JDBC方式提交SQL语句实现数据处理
免责声明:
1. 本站所有资源来自网络搜集或用户上传,仅作为参考不担保其准确性!
2. 本站内容仅供学习和交流使用,版权归原作者所有!© 查看更多
3. 如有内容侵害到您,请联系我们尽快删除,邮箱:kf@codeae.com