学习目标
- 了解什么是Hive
- 了解为什么使用Hive
####1.1 什么是 Hive
直接使用 Hadoop MapReduce 处理数据所面临的问题:
使用 Hive
操作接口采用类 SQL 语法,提供快速开发的能力
避免了去写 MapReduce,减少开发人员的学习成本
功能扩展很方便
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FNHmoo05-1594524836598)(/img/hive2.jpg)]
Hive 利用 HDFS 存储数据,利用 MapReduce 查询分析数据。
Hive是数据仓库工具,没有集群的概念,如果想提交Hive作业只需要在hadoop集群 Master节点上装Hive就可以了
Hive | 关系型数据库 | |
---|---|---|
ANSI SQL | 不完全支持 | 支持 |
更新 | INSERT OVERWRITE\INTO TABLE(默认) | UPDATE\INSERT\DELETE |
事务 | 不支持(默认) | 支持 |
模式 | 读模式 | 写模式 |
查询语言 | HQL | SQL |
数据存储 | HDFS | Raw Device or Local FS |
执行 | MapReduce | Executor |
执行延迟 | 高 | 低 |
子查询 | 只能用在From子句中 | 完全支持 |
处理数据规模 | 大 | 小 |
可扩展性 | 高 | 低 |
索引 | 0.8版本后加入位图索引 | 有复杂的索引 |
Hive 安装前需要安装好 JDK 和 Hadoop。配置好环境变量。
下载Hive的安装包 http://archive.cloudera.com/cdh5/cdh/5/ 并解压
tar -zxvf hive-1.1.0-cdh5.7.0.tar.gz -C ~/app/
进入到 解压后的hive目录 找到 conf目录, 修改配置文件
cp hive-env.sh.template hive-env.sh
vi hive-env.sh
在hive-env.sh中指定hadoop的路径
HADOOP_HOME=/home/hadoop/app/hadoop-2.6.0-cdh5.7.0
配置环境变量
vi ~/.bash_profile
export HIVE_HOME=/home/hadoop/app/hive-1.1.0-cdh5.7.0
export PATH=$HIVE_HOME/bin:$PATH
source ~/.bash_profile
根据元数据存储的介质不同,分为下面两个版本,其中 derby 属于内嵌模式。实际生产环境中则使用 mysql 来进行元数据的存储。
内置 derby 版:
bin/hive 启动即可使用
缺点:不同路径启动 hive,每一个 hive 拥有一套自己的元数据,无法共享
mysql 版:
上传 mysql驱动到 hive安装目录的lib目录下
mysql-connector-java-5.*.jar
vi conf/hive-site.xml 配置 Mysql 元数据库信息(MySql安装见文档)
<configuration>
<property>
<name>javax.jdo.option.ConnectionUserNamename>
<value>hivevalue>
property>
<property>
<name>javax.jdo.option.ConnectionPasswordname>
<value>hivevalue>
property>
<property>
<name>javax.jdo.option.ConnectionURLname>mysql
<value>jdbc:mysql://127.0.0.1:3306/hivevalue>
property>
<property>
<name>javax.jdo.option.ConnectionDriverNamename>
<value>com.mysql.jdbc.Drivervalue>
property>
<property>
<name>hive.exec.script.wrappername>
<value/>
<description/>
property>
configuration>
hive启动
启动docker
service docker start
通过docker 启动mysql
docker start mysql
启动 hive的metastore元数据服务
hive --service metastore
启动hive
hive
MySQL root 密码 password hive用户 密码 hive
创建数据库
CREATE DATABASE test;
显示所有数据库
SHOW DATABASES;
创建表
CREATE TABLE student(classNo string, stuNo string, score int) row format delimited fields terminated by ',';
将数据load到表中
在本地文件系统创建一个如下的文本文件:/home/hadoop/tmp/student.txt
C01,N0101,82
C01,N0102,59
C01,N0103,65
C02,N0201,81
C02,N0202,82
C02,N0203,79
C03,N0301,56
C03,N0302,92
C03,N0306,72
load data local inpath '/home/hadoop/tmp/student.txt'overwrite into table student;
这个命令将student.txt文件复制到hive的warehouse目录中,这个目录由hive.metastore.warehouse.dir配置项设置,默认值为/user/hive/warehouse。Overwrite选项将导致Hive事先删除student目录下所有的文件, 并将文件内容映射到表中。
Hive不会对student.txt做任何格式处理,因为Hive本身并不强调数据的存储格式。
查询表中的数据 跟SQL类似
hive>select * from student;
分组查询group by和统计 count
hive>select classNo,count(score) from student where score>=60 group by classNo;
从执行结果可以看出 hive把查询的结果变成了MapReduce作业通过hadoop执行
内部表(managed table) | 外部表(external table) | |
---|---|---|
概念 | 创建表时无external修饰 | 创建表时被external修饰 |
数据管理 | 由Hive自身管理 | 由HDFS管理 |
数据保存位置 | hive.metastore.warehouse.dir (默认:/user/hive/warehouse) | hdfs中任意位置 |
删除时影响 | 直接删除元数据(metadata)及存储数据 | 仅会删除元数据,HDFS上的文件并不会被删除 |
表结构修改时影响 | 修改会将修改直接同步给元数据 | 表结构和分区进行修改,则需要修复(MSCK REPAIR TABLE table_name;) |
案例
CREATE EXTERNAL TABLE student2 (classNo string, stuNo string, score int) row format delimited fields terminated by ',' location '/tmp/student';
装载数据
load data local inpath '/home/hadoop/tmp/student.txt' overwrite into table student2;
显示表信息
desc formatted table_name;
删除表查看结果
drop table student;
再次创建外部表 student2
不插入数据直接查询查看结果
select * from student2;
什么是分区表
创建分区表
tom,4300
jerry,12000
mike,13000
jake,11000
rob,10000
create table employee (name string,salary bigint) partitioned by (date1 string) row format delimited fields terminated by ',' lines terminated by '\n' stored as textfile;
查看表的分区
show partitions employee;
添加分区
alter table employee add if not exists partition(date1='2018-12-01');
加载数据到分区
load data local inpath '/home/hadoop/tmp/employee.txt' into table employee partition(date1='2018-12-01');
如果重复加载同名文件,不会报错,会自动创建一个*_copy_1.txt
外部分区表即使有分区的目录结构, 也必须要通过hql添加分区, 才能看到相应的数据
hadoop fs -mkdir /user/hive/warehouse/emp/dt=2018-12-04
hadoop fs -copyFromLocal /tmp/employee.txt /user/hive/warehouse/test.db/emp/dt=2018-12-04/employee.txt
此时查看表中数据发现数据并没有变化, 需要通过hql添加分区
alter table emp add if not exists partition(dt='2018-12-04');
此时再次查看才能看到新加入的数据
总结
在写入数据时自动创建分区(包括目录结构)
创建表
create table employee2 (name string,salary bigint) partitioned by (date1 string) row format delimited fields terminated by ',' lines terminated by '\n' stored as textfile;
导入数据
insert into table employee2 partition(date1) select name,salary,date1 from employee;
使用动态分区需要设置参数
set hive.exec.dynamic.partition.mode=nonstrict;
在 Hive 有四种类型的运算符:
关系运算符
算术运算符
逻辑运算符
复杂运算
(内容较多,见《Hive 官方文档》》)
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
UDF
当 Hive 提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数(UDF:user-defined function)。
TRANSFORM,and UDF and UDAF
it is possible to plug in your own custom mappers and reducers
A UDF is basically only a transformation done by a mapper meaning that each row should be mapped to exactly one row. A UDAF on the other hand allows us to transform a group of rows into one or more rows, meaning that we can reduce the number of input rows to a single output row by some custom aggregation.
UDF:就是做一个mapper,对每一条输入数据,映射为一条输出数据。
UDAF:就是一个reducer,把一组输入数据映射为一条(或多条)输出数据。
一个脚本至于是做mapper还是做reducer,又或者是做udf还是做udaf,取决于我们把它放在什么样的hive操作符中。放在select中的基本就是udf,放在distribute by和cluster by中的就是reducer。
We can control if the script is run in a mapper or reducer step by the way we formulate our HiveQL query.
The statements DISTRIBUTE BY and CLUSTER BY allow us to indicate that we want to actually perform an aggregation.
User-Defined Functions (UDFs) for transformations and even aggregations which are therefore called User-Defined Aggregation Functions (UDAFs)
UDF示例(运行java已经编写好的UDF)
在hdfs中创建 /user/hive/lib目录
hadoop fs -mkdir /user/hive/lib
把 hive目录下 lib/hive-contrib-hive-contrib-1.1.0-cdh5.7.0.jar 放到hdfs中
hadoop fs -put hive-contrib-1.1.0-cdh5.7.0.jar /user/hive/lib/
把集群中jar包的位置添加到hive中
hive> add jar hdfs:///user/hive/lib/hive-contrib-1.1.0-cdh5.7.0.jar;
在hive中创建临时UDF
hive> CREATE TEMPORARY FUNCTION row_sequence as 'org.apache.hadoop.hive.contrib.udf.UDFRowSequence'
在之前的案例中使用临时自定义函数(函数功能: 添加自增长的行号)
Select row_sequence(),* from employee;
创建非临时自定义函数
CREATE FUNCTION row_sequence as 'org.apache.hadoop.hive.contrib.udf.UDFRowSequence' using jar 'hdfs:///user/hive/lib/hive-contrib-1.1.0-cdh5.7.0.jar';
Python UDF
准备案例环境
创建表
CREATE table u(fname STRING,lname STRING);
向表中插入数据
insert into table u2 values('George','washington');
insert into table u2 values('George','bush');
insert into table u2 values('Bill','clinton');
insert into table u2 values('Bill','gates');
编写map风格脚本
import sys
for line in sys.stdin:
line = line.strip()
fname , lname = line.split('\t')
l_name = lname.upper()
print '\t'.join([fname, str(l_name)])
通过hdfs向hive中ADD file
加载文件到hdfs
hadoop fs -put udf.py /user/hive/lib/
hive从hdfs中加载python脚本
ADD FILE hdfs:///user/hive/lib/udf.py;
ADD FILE /root/tmp/udf1.py;
Transform
SELECT TRANSFORM(fname, lname) USING 'python udf1.py' AS (fname, l_name) FROM u;
Python UDAF
内容推荐数据处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-itsa8sLT-1594524836600)(/img/hive3.png)]
相关数据
user_id article_id event_time
11,101,2018-12-01 06:01:10
22,102,2018-12-01 07:28:12
33,103,2018-12-01 07:50:14
11,104,2018-12-01 09:08:12
22,103,2018-12-01 13:37:12
33,102,2018-12-02 07:09:12
11,101,2018-12-02 18:42:12
35,105,2018-12-03 09:21:12
22,104,2018-12-03 16:42:12
77,103,2018-12-03 18:31:12
99,102,2018-12-04 00:04:12
33,101,2018-12-04 19:10:12
11,101,2018-12-05 09:07:12
35,102,2018-12-05 11:00:12
22,103,2018-12-05 12:11:12
77,104,2018-12-05 18:02:02
99,105,2018-12-05 20:09:11
artical_id,artical_url,artical_keywords
101,http://www.itcast.cn/1.html,kw8|kw1
102,http://www.itcast.cn/2.html,kw6|kw3
103,http://www.itcast.cn/3.html,kw7
104,http://www.itcast.cn/4.html,kw5|kw1|kw4|kw9
105,http://www.itcast.cn/5.html,
数据上传hdfs
hadoop fs -mkdir /tmp/demo
hadoop fs -mkdir /tmp/demo/user_action
创建外部表
drop table if exists user_actions;
CREATE EXTERNAL TABLE user_actions(
user_id STRING,
article_id STRING,
time_stamp STRING
)
ROW FORMAT delimited fields terminated by ','
LOCATION '/tmp/demo/user_action';
drop table if exists articles;
CREATE EXTERNAL TABLE articles(
article_id STRING,
url STRING,
key_words array<STRING>
)
ROW FORMAT delimited fields terminated by ','
COLLECTION ITEMS terminated BY '|'
LOCATION '/tmp/demo/article_keywords';
/*
key_words array 数组的数据类型
COLLECTION ITEMS terminated BY '|' 数组的元素之间用'|'分割
*/
select * from user_actions;
select * from articles;
分组查询每个用户的浏览记录
select user_id,collect_set(article_id)
from user_actions group by user_id;
11 ["101","104"]
22 ["102","103","104"]
33 ["103","102","101"]
35 ["105","102"]
77 ["103","104"]
99 ["102","105"]
select user_id,collect_list(article_id)
from user_actions group by user_id;
11 ["101","104","101","101"]
22 ["102","103","104","103"]
33 ["103","102","101"]
35 ["105","102"]
77 ["103","104"]
99 ["102","105"]
select user_id,sort_array(collect_list(article_id)) as contents
from user_actions group by user_id;
11 ["101","101","101","104"]
22 ["102","103","103","104"]
33 ["101","102","103"]
35 ["102","105"]
77 ["103","104"]
99 ["102","105"]
查看每一篇文章的关键字 lateral view explode
select explode(key_words) from articles;
select article_id,kw from articles lateral view explode(key_words) t as kw;
101 kw8
101 kw1
102 kw6
102 kw3
103 kw7
104 kw5
104 kw1
104 kw4
104 kw9
select article_id,kw from articles lateral view outer explode(key_words) t as kw;
101 kw8
101 kw1
102 kw6
102 kw3
103 kw7
104 kw5
104 kw1
104 kw4
104 kw9
105 NULL
#含有outer
根据文章id找到用户查看文章的关键字
101 http://www.itcast.cn/1.html ["kw8","kw1"]
102 http://www.itcast.cn/2.html ["kw6","kw3"]
103 http://www.itcast.cn/3.html ["kw7"]
104 http://www.itcast.cn/4.html ["kw5","kw1","kw4","kw9"]
105 http://www.itcast.cn/5.html []
select a.user_id, b.kw from user_actions
as a left outer JOIN (select article_id,kw from articles
lateral view outer explode(key_words) t as kw) b
on (a.article_id = b.article_id)
order by a.user_id;
11 kw1
11 kw8
11 kw5
11 kw1
11 kw4
11 kw1
11 kw9
11 kw8
11 kw1
11 kw8
22 kw1
22 kw7
22 kw9
22 kw4
22 kw5
22 kw7
22 kw3
22 kw6
33 kw8
33 kw1
33 kw3
33 kw6
33 kw7
35 NULL
35 kw6
35 kw3
77 kw9
77 kw1
77 kw7
77 kw4
77 kw5
99 kw3
99 kw6
99 NULL
根据文章id找到用户查看文章的关键字并统计频率
select a.user_id, b.kw,count(1) as weight
from user_actions as a
left outer JOIN (select article_id,kw from articles
lateral view outer explode(key_words) t as kw) b
on (a.article_id = b.article_id)
group by a.user_id,b.kw
order by a.user_id,weight desc;
11 kw1 4
11 kw8 3
11 kw5 1
11 kw9 1
11 kw4 1
22 kw7 2
22 kw9 1
22 kw1 1
22 kw3 1
22 kw4 1
22 kw5 1
22 kw6 1
33 kw3 1
33 kw8 1
33 kw7 1
33 kw6 1
33 kw1 1
35 NULL 1
35 kw3 1
35 kw6 1
77 kw1 1
77 kw4 1
77 kw5 1
77 kw7 1
77 kw9 1
99 NULL 1
99 kw3 1
99 kw6 1
CONCAT:
CONCAT(str1,str2,…)
返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。
select concat(user_id,article_id) from user_actions;
CONCAT_WS:
使用语法为:CONCAT_WS(separator,str1,str2,…)
CONCAT_WS() 代表 CONCAT With Separator ,是CONCAT()的特殊形式。第一个参数是其它参数的分隔符。分隔符的位置放在要连接的两个字符串之间。分隔符可以是一个字符串,也可以是其它参数。如果分隔符为 NULL,则结果为 NULL。
select concat_ws(':',user_id,article_id) from user_actions;
将用户查看的关键字和频率合并成 key:value形式
select a.user_id, concat_ws(':',b.kw,cast (count(1) as string)) as kw_w
from user_actions as a
left outer JOIN (select article_id,kw from articles
lateral view outer explode(key_words) t as kw) b
on (a.article_id = b.article_id)
group by a.user_id,b.kw;
11 kw1:4
11 kw4:1
11 kw5:1
11 kw8:3
11 kw9:1
22 kw1:1
22 kw3:1
22 kw4:1
22 kw5:1
22 kw6:1
22 kw7:2
22 kw9:1
33 kw1:1
33 kw3:1
33 kw6:1
33 kw7:1
33 kw8:1
35 1
35 kw3:1
35 kw6:1
77 kw1:1
77 kw4:1
77 kw5:1
77 kw7:1
77 kw9:1
99 1
99 kw3:1
99 kw6:1
将用户查看的关键字和频率合并成 key:value形式并按用户聚合
select cc.user_id,concat_ws(',',collect_set(cc.kw_w))
from(
select a.user_id, concat_ws(':',b.kw,cast (count(1) as string)) as kw_w
from user_actions as a
left outer JOIN (select article_id,kw from articles
lateral view outer explode(key_words) t as kw) b
on (a.article_id = b.article_id)
group by a.user_id,b.kw
) as cc
group by cc.user_id;
11 kw1:4,kw4:1,kw5:1,kw8:3,kw9:1
22 kw1:1,kw3:1,kw4:1,kw5:1,kw6:1,kw7:2,kw9:1
33 kw1:1,kw3:1,kw6:1,kw7:1,kw8:1
35 1,kw3:1,kw6:1
77 kw1:1,kw4:1,kw5:1,kw7:1,kw9:1
99 1,kw3:1,kw6:1
将上面聚合结果转换成map
select cc.user_id,str_to_map(concat_ws(',',collect_set(cc.kw_w))) as wm
from(
select a.user_id, concat_ws(':',b.kw,cast (count(1) as string)) as kw_w
from user_actions as a
left outer JOIN (select article_id,kw from articles
lateral view outer explode(key_words) t as kw) b
on (a.article_id = b.article_id)
group by a.user_id,b.kw
) as cc
group by cc.user_id;
11 {"kw1":"4","kw4":"1","kw5":"1","kw8":"3","kw9":"1"}
22 {"kw1":"1","kw3":"1","kw4":"1","kw5":"1","kw6":"1","kw7":"2","kw9":"1"}
33 {"kw1":"1","kw3":"1","kw6":"1","kw7":"1","kw8":"1"}
35 {"1":null,"kw3":"1","kw6":"1"}
77 {"kw1":"1","kw4":"1","kw5":"1","kw7":"1","kw9":"1"}
99 {"1":null,"kw3":"1","kw6":"1"}
将用户的阅读偏好结果保存到表中
create table user_kws as
select cc.user_id,str_to_map(concat_ws(',',collect_set(cc.kw_w))) as wm
from(
select a.user_id, concat_ws(':',b.kw,cast (count(1) as string)) as kw_w
from user_actions as a
left outer JOIN (select article_id,kw from articles
lateral view outer explode(key_words) t as kw) b
on (a.article_id = b.article_id)
group by a.user_id,b.kw
) as cc
group by cc.user_id;
从表中通过key查询map中的值
select user_id, wm['kw1'] from user_kws;
11 4
22 1
33 1
35 NULL
77 1
99 NULL
从表中获取map中所有的key 和 所有的value
select user_id,map_keys(wm),map_values(wm) from user_kws;
11 ["kw1","kw4","kw5","kw8","kw9"] ["4","1","1","3","1"]
22 ["kw1","kw3","kw4","kw5","kw6","kw7","kw9"] ["1","1","1","1","1","2","1"]
33 ["kw1","kw3","kw6","kw7","kw8"] ["1","1","1","1","1"]
35 ["1","kw3","kw6"] [null,"1","1"]
77 ["kw1","kw4","kw5","kw7","kw9"] ["1","1","1","1","1"]
99 ["1","kw3","kw6"] [null,"1","1"]
用lateral view explode把map中的数据转换成多列
select user_id,keyword,weight from user_kws lateral view explode(wm) t as keyword,weight;
11 kw1 4
11 kw4 1
11 kw5 1
11 kw8 3
11 kw9 1
22 kw1 1
22 kw3 1
22 kw4 1
22 kw5 1
22 kw6 1
22 kw7 2
22 kw9 1
33 kw1 1
33 kw3 1
33 kw6 1
33 kw7 1
33 kw8 1
35 1 NULL
35 kw3 1
35 kw6 1
77 kw1 1
77 kw4 1
77 kw5 1
77 kw7 1
77 kw9 1
99 1 NULL
99 kw3 1
99 kw6 1
HBase 与 传统关系数据库的区别
HBase | 关系型数据库 | |
---|---|---|
数据库大小 | PB级别 | GB TB |
数据类型 | Bytes | 丰富的数据类型 |
事务支持 | ACID只支持单个Row级别 | 全面的ACID支持, 对Row和表 |
索引 | 只支持Row-key | 支持 |
吞吐量 | 百万写入/秒 | 数千写入/秒 |
ID | FILE NAME | FILE PATH | FILE TYPE | FILE SIZE | CREATOR |
---|---|---|---|---|---|
1 | file1.txt | /home | txt | 1024 | tom |
2 | file2.txt | /home/pics | jpg | 5032 | jerry |
RowKey | FILE INFO | SAVE INFO |
---|---|---|
1 | name:file1.txt type:txt size:1024 | path:/home/pics creator:Jerry |
2 | name:file2.jpg type:jpg size:5032 | path:/home creator:Tom |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4iY66aAV-1594524836603)(C:/Users/beibei/Desktop/%E8%AE%B2%E4%B9%89/day04_hive&hbase/img/hbase4.png)]
HBase是Apache基金会顶级项目
HBase基于HDFS进行数据存储
HBase可以存储超大数据并适合用来进行大数据的实时查询
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bpBUNc9c-1594524836605)(C:/Users/beibei/Desktop/%E8%AE%B2%E4%B9%89/day04_hive&hbase/img/hbase&hive.png)]
##六 HBase的数据模型
NameSpace: 关系型数据库的"数据库"(database)
表(table):用于存储管理数据,具有稀疏的、面向列的特点。HBase中的每一张表,就是所谓的大表(Bigtable),可以有上亿行,上百万列。对于为值为空的列,并不占用存储空间,因此表可以设计的非常稀疏。
行(Row):在表里面,每一行代表着一个数据对象,每一行都是以一个行键(Row Key)来进行唯一标识的, 行键并没有什么特定的数据类型, 以二进制的字节来存储
列(Column): HBase的列由 Column family 和 Column qualifier 组成, 由冒号: 进行行间隔, 如 family: qualifier
行键(RowKey):类似于MySQL中的主键,HBase根据行键来快速检索数据,一个行键对应一条记录。与MySQL主键不同的是,HBase的行键是天然固有的,每一行数据都存在行键。
列族(ColumnFamily):是列的集合。列族在表定义时需要指定,而列在插入数据时动态指定。列中的数据都是以二进制形式存在,没有数据类型。在物理存储结构上,每个表中的每个列族单独以一个文件存储。一个表可以有多个列簇。
列修饰符(Column Qualifier) : 列族中的数据通过列标识来进行映射, 可以理解为一个键值对(key-value), 列修饰符(Column Qualifier) 就是key 对应关系型数据库的列
时间戳(TimeStamp):是列的一个属性,是一个64位整数。由行键和列确定的单元格,可以存储多个数据,每个数据含有时间戳属性,数据具有版本特性。可根据版本(VERSIONS)或时间戳来指定查询历史版本数据,如果都不指定,则默认返回最新版本的数据。
区域(Region):HBase自动把表水平划分成的多个区域,划分的区域随着数据的增大而增多。
HBase 支持特定场景下的 ACID,即对行级别的 操作保证完全的 ACID
分布式系统的最大难点,就是各个节点的状态如何同步。CAP 定理是这方面的基本定理,也是理解分布式系统的起点。
一致性(所有节点在同一时间具有相同的数据)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0CdfZRhJ-1594524836606)(img/Consistency.png)]
可用性(保证每个请求不管成功或失败都有响应,但不保证获取的数据的正确性)
分区容错性(系统中任意信息的丢失或失败不会影响系统的运行,系统如果不能在某个时限内达成数据一致性,就必须在上面两个操作之间做出选择)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YNoianZt-1594524836607)(img/cap.jpg)]
hbase是CAP中的CP系统,即hbase是强一致性的
下载安装包 http://archive.cloudera.com/cdh5/cdh/5/hbase-1.2.0-cdh5.7.0.tar.gz
配置伪分布式环境
环境变量配置
export HBASE_HOME=/usr/local/development/hbase-1.2.4
export PATH=$HBASE_HOME/bin:$PATH
配置hbase-env.sh
export JAVA_HOME=/usr/local/development/jdk1.7.0_15
export HBASE_MANAGES_ZK=false --如果你是使用hbase自带的zk就是true,如果使用自己的zk就是false
配置hbase-site.xml
<property>
<name>hbase.rootdirname> --hbase持久保存的目录
<value>hdfs://hadoop001:8020/opt/hbasevalue>
property>
<property>
<name>hbase.cluster.distributedname> --是否是分布式
<value>truevalue>
property>
<property>
<name>hbase.zookeeper.property.clientPortname> --指定要连接zk的端口
<value>2181value>
property>
<property>
<name>hbase.zookeeper.property.dataDirname> <value>/home/hadoop/app/hbase/zkDatavalue>
property>
启动hbase(启动的hbase的时候要保证hadoop集群已经启动)
/hbase/bin/start-hbase.sh
输入hbase shell(进入shell命令行)
名称 | 命令表达式 |
---|---|
创建表 | create '表名', '列族名1','列族名2','列族名n' |
添加记录 | put '表名','行名','列名:','值 |
查看记录 | get '表名','行名' |
查看表中的记录总数 | count '表名' |
删除记录 | delete '表名', '行名','列名' |
删除一张表 | 第一步 disable '表名' 第二步 drop '表名' |
查看所有记录 | scan "表名称" |
查看指定表指定列所有数据 | scan '表名' ,{COLUMNS=>'列族名:列名'} |
更新记录 | 重写覆盖 |
hbase shell
create 'user','base_info'
disable 'user'
drop 'user'
create_namespace 'test'
list_namespace
create 'test:user','base_info'
list_namespace_tables 'test'
插入数据
put ‘表名’,‘rowkey的值’,’列族:列标识符‘,’值‘
put 'user','rowkey_10','base_info:username','Tom'
put 'user','rowkey_10','base_info:birthday','2014-07-10'
put 'user','rowkey_10','base_info:sex','1'
put 'user','rowkey_10','base_info:address','Tokyo'
put 'user','rowkey_16','base_info:username','Mike'
put 'user','rowkey_16','base_info:birthday','2014-07-10'
put 'user','rowkey_16','base_info:sex','1'
put 'user','rowkey_16','base_info:address','beijing'
put 'user','rowkey_22','base_info:username','Jerry'
put 'user','rowkey_22','base_info:birthday','2014-07-10'
put 'user','rowkey_22','base_info:sex','1'
put 'user','rowkey_22','base_info:address','Newyork'
put 'user','rowkey_24','base_info:username','Nico'
put 'user','rowkey_24','base_info:birthday','2014-07-10'
put 'user','rowkey_24','base_info:sex','1'
put 'user','rowkey_24','base_info:address','shanghai'
put 'user','rowkey_25','base_info:username','Rose'
put 'user','rowkey_25','base_info:birthday','2014-07-10'
put 'user','rowkey_25','base_info:sex','1'
put 'user','rowkey_25','base_info:address','Soul'
scan 'user'
get 'user','rowkey_16'
get 'user','rowkey_16','base_info'
get 'user','rowkey_16','base_info:username'
get 'user', 'rowkey_16', {COLUMN => ['base_info:username','base_info:sex']}
delete 'user', 'rowkey_16', 'base_info:username'
truncate 'user'
alter 'user', NAME => 'f2'
alter 'user', 'delete' => 'f2'
HBase 追加型数据库 会保留多个版本数据
desc 'user'
Table user is ENABLED
user
COLUMN FAMILIES DESCRIPTION
{NAME => 'base_info', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_B
HE_DATA_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MI
ER => 'NONE', CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOM
se', COMPRESSION => 'NONE', BLOCKCACHE => 'false', BLOCKSIZE => '65536'}
put 'user','rowkey_10','base_info:username','Tom'
get 'user','rowkey_10',{COLUMN=>'base_info:username',VERSIONS=>2}
alter 'user',NAME=>'base_info',VERSIONS=>10
命令表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ElQHKki7-1594524836608)(img/2017-12-27_230420.jpg)]
可以通过HbaseUi界面查看表的信息
端口60010打不开的情况,是因为hbase 1.0 以后的版本,需要自己手动配置,在文件 hbase-site
hbase.master.info.port
60010
什么是HappyBase
HappyBase 是FaceBook员工开发的操作HBase的python库, 其基于Python Thrift, 但使用方式比Thrift简单, 已被广泛应用
启动hbase thrift server : hbase-daemon.sh start thrift
安装happy base
使用happy base时可能出现的问题(windows系统)
如何使用HappyBase
import happybase
connection = happybase.Connection('somehost')
Connection.open()
:connection = happybase.Connection('somehost', autoconnect=False)
# before first use:
connection.open()
Connection
这个类提供了一个与HBase交互的入口, 比如获取HBase中所有的表: Connection.tables()
:print(connection.tables())
connection.create_table('users',{'cf1': dict()})
创建表之后可以传入表名获取到Table类的实例:
table = connection.table('mytable')
查询操作
# api
table.scan() #全表查询
table.row(row_keys[0]) # 查询一行
table.rows(row_keys) # 查询多行
#封装函数
def show_rows(table, row_keys=None):
if row_keys:
print('show value of row named %s' % row_keys)
if len(row_keys) == 1:
print(table.row(row_keys[0]))
else:
print(table.rows(row_keys))
else:
print('show all row values of table named %s' % table.name)
for key, value in table.scan():
print(key, value)
#api
table.put(row_key, {cf:cq:value})
def put_row(table, column_family, row_key, value):
print('insert one row to hbase')
#put 'user','rowkey_10','base_info:username','Tom'
#{'cf:cq':’数据‘}
table.put(row_key, {'%s:name' % column_family:'name_%s' % value})
def put_rows(table, column_family, row_lines=30):
print('insert rows to hbase now')
for i in range(row_lines):
put_row(table, column_family, 'row_%s' % i, i)
#api
table.delete(row_key, cf_list)
#函数封装
def delete_row(table, row_key, column_family=None, keys=None):
if keys:
print('delete keys:%s from row_key:%s' % (keys, row_key))
key_list = ['%s:%s' % (column_family, key) for key in keys]
table.delete(row_key, key_list)
else:
print('delete row(column_family:) from hbase')
table.delete(row_key)
#api
conn.delete_table(table_name, True)
#函数封装
def delete_table(table_name):
pretty_print('delete table %s now.' % table_name)
conn.delete_table(table_name, True)
完整代码
import happybase
hostname = '192.168.199.188'
table_name = 'users'
column_family = 'cf'
row_key = 'row_1'
conn = happybase.Connection(hostname)
def show_tables():
print('show all tables now')
tables = conn.tables()
for t in tables:
print t
def create_table(table_name, column_family):
print('create table %s' % table_name)
conn.create_table(table_name, {column_family:dict()})
def show_rows(table, row_keys=None):
if row_keys:
print('show value of row named %s' % row_keys)
if len(row_keys) == 1:
print table.row(row_keys[0])
else:
print table.rows(row_keys)
else:
print('show all row values of table named %s' % table.name)
for key, value in table.scan():
print key, value
def put_row(table, column_family, row_key, value):
print('insert one row to hbase')
table.put(row_key, {'%s:name' % column_family:'name_%s' % value})
def put_rows(table, column_family, row_lines=30):
print('insert rows to hbase now')
for i in range(row_lines):
put_row(table, column_family, 'row_%s' % i, i)
def delete_row(table, row_key, column_family=None, keys=None):
if keys:
print('delete keys:%s from row_key:%s' % (keys, row_key))
key_list = ['%s:%s' % (column_family, key) for key in keys]
table.delete(row_key, key_list)
else:
print('delete row(column_family:) from hbase')
table.delete(row_key)
def delete_table(table_name):
pretty_print('delete table %s now.' % table_name)
conn.delete_table(table_name, True)
def pool():
pretty_print('test pool connection now.')
pool = happybase.ConnectionPool(size=3, host=hostname)
with pool.connection() as connection:
print connection.tables()
def main():
# show_tables()
# create_table(table_name, column_family)
# show_tables()
table = conn.table(table_name)
show_rows(table)
put_rows(table, column_family)
show_rows(table)
#
# # 更新操作
# put_row(table, column_family, row_key, 'xiaoh.me')
# show_rows(table, [row_key])
#
# # 删除数据
# delete_row(table, row_key)
# show_rows(table, [row_key])
#
# delete_row(table, row_key, column_family, ['name'])
# show_rows(table, [row_key])
#
# counter(table, row_key, column_family)
#
# delete_table(table_name)
if __name__ == "__main__":
main()
设计表保存应用中用户互粉的信息
设计1:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jOJ49Qxj-1594524836609)(img/table1.png)]
设计2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GtuEIsB5-1594524836610)(img/table2.png)]
设计3
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6pQJBdjR-1594524836611)(img/table3.png)]
最终设计(DDI)
案例总结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VpaysLJn-1594524836612)(img/structure.jpg)]
Client
Zookeeper
HMaster
可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master运行。
角色功能:
HRegionServer
HBase中最核心的模块,主要负责响应用户I/O请求,向HDFS文件系统中读写数据。
作用:
HStore
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4BmuQiT1-1594524836613)(img/2.png)]
HRegion
HLog
,无需考虑数据类型
[外链图片转存中…(img-VpaysLJn-1594524836612)]
Client
Zookeeper
HMaster
可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master运行。
角色功能:
HRegionServer
HBase中最核心的模块,主要负责响应用户I/O请求,向HDFS文件系统中读写数据。
作用:
HStore
[外链图片转存中…(img-4BmuQiT1-1594524836613)]
HRegion
HLog