相对于hadoop复杂的job(MapReduce)编写过程,Hive提供了HQL(类似于SQL的)语言来高效的生成查询job,方便数据工程师在不会编程的情况下,进行并专注于数据分析。从本质上讲,Hive同Pig一样,都是一种简化批处理任务编程复杂度的工具,下面我们就来总体认识一下。
服务端组件
Driver组件
:该组件包括:Compiler
、Optimizer
、Executor
,它可以将Hive的HQL进行编译、解析、优化后,最终转化为MapReduce任务提交给Hadoop 1中的JobTracker,或者Hadoop 2中的ResourceManager来执行实际的任务。MetaStore组件
:存储着Hive的元数据信息,Hive将自己的元数据存储到了关系型数据库当中,支持的数据库主要有:Mysql、Derby、支持把metastore独立出来放在远程的集群上面,使得hive更加健壮。元数据主要包括了表的名称、表的列、分区和属性、表的属性(是不是外部表等等)、表的数据所在的目录。用户接口
:CLI(常用的接口:命令行模式)、Client:Hive的客户端用户连接至Hive Server, 在启动Client的时候,需要指定Hive Server所在的节点,并且在该节点上启动Hive Server、Web UI:通过浏览器的方式访问Hive。
任务执行流程
- 用户提交查询等任务给
Driver
;Compiler
获得该用户的任务Plan;- Compiler根据用户任务去
MetaStore
中获取需要的Hive的元数据信息; - Compiler得到元数据信息,对任务进行编译
- 先将
HiveQL
转换为抽象语法树
, - 然后将抽象语法树转换成
查询块
, - 将查询块转化为逻辑的
查询计划
, - 重写逻辑查询计划,将逻辑计划转化为
物理的计划
- 最后选择
最佳的策略
;
- 先将
- 将最终的计划提交给
Driver
;
- Driver将计划Plan转交给
ExecutionEngine
去执行,获取元数据信息,提交给JobTracker或者ResourceManager执行该任务,任务会直接读取HDFS中文件进行相应的操作; - 获取执行的结果;
- 取得并返回执行结果。
数据模型
Table
类似于传统数据库中的Table,每一个Table在Hive中都有一个相应的目录来存储数据。例如:一个表t,它在HDFS中的路径为:/user/hive/warehouse/t
。内部表做删除表,就删除了目录及数据
。External Table
指向已存在HDFS中的数据,可创建Partition
。数据是存储在Location后面指定的HDFS路径中的,并不会移动到数据仓库中。删除外部表,只是删除了元数据的信息,该外部表所指向的数据是不会被删除
。Partition
在Hive中,表中的一个Partition对应于表下的一个目录,所有的Partition数据都存储在对应的目录中。例如:t表中包含ds和city两个Partition,则对应于ds=2014,city=beijing的HDFS子目录为:
/user/hive/warehouse/t/ds=2014/city=Beijing
;需要注意的是,分区列是表的伪列,表数据文件中并不存在这个分区列的数据。一个表可以拥有一个或者多个分区,每个分区以文件夹的形式单独存在表文件夹的目录下。分区避免 Hive Select查询中扫描整个表内容,防止消耗很多时间做没必要的工作(相当于只查询了子表<子目录>
)。Buckets
对指定列计算的hash,根据hash值切分数据,目的是为了便于并行,每一个Buckets对应一个文件。将user列分至32个Bucket上,首先对user列的值计算hash,比如,对应hash=0的HDFS目录为:
/user/hive/warehouse/t/ds=2014/city=Beijing/part-00000
;对应hash=20的目录为:/user/hive/warehouse/t/ds=2014/city=Beijing/part-00020
。buckets是对partition的一种补充,具体见以下例子:
假设我们有一张日志表,我们需要按照日期和用户id来分区,目的是为了加快查询谁哪天干了什么。但是这里面用user_id去切分的话,就会产生很多很多的分区了,这些分区可大可小,这个数量是文件系统所不能承受的。
在这种情况下,我们既想加快查询速度,又避免出现如此多的小分区,篮子(bucket)就出现了。1
2
3CREATE TABLE weblog (user_id INT, url STRING, source_ip STRING)
> PARTITIONED BY (dt STRING)
> CLUSTERED BY (user_id) INTO 96 BUCKETS;首先按照日期分区,分区结束之后再按照user_id把日志放在96个篮子,这样同一个用户的所有日志都会在同一个篮子里面,并且一个篮子里面有好多用户的日志。
操作实践
安装包
1 | wget https://mirrors.sonic.net/apache/hive/hive-3.1.2/apache-hive-3.1.2-bin.tar.gz |
配置
hive-default.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15cd $HIVE_HOME/conf
cp hive-default.xml.template hive-default.xml
#注意修改thrift账号密码
#写入xml
<property>
<name>hive.server2.thrift.client.user</name>
<value>hive</value>
<description>Username to use against thrift client</description>
</property>
<property>
<name>hive.server2.thrift.client.password</name>
<value>hive</value>
<description>Password to use against thrift client</description>
</property>
hive-env.sh
1
2
3
4
5cd $HIVE_HOME/conf
cp hive-env.sh.template hive-env.sh
#追加内容
HADOOP_HOME=/root/bigData/hadoop-3.3.0hive-site.xml
需要在$HIVE_HOME/conf/下创建
hive-site.xml
,并写入以下值:1
2
3
4
5
6
7
8
9
10
11
12
13<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:derby:${HIVE_HOME}/metastore_db;databaseName=metastore_db;create=true</value>
</property>
<property>
<name>hive.metastore.schema.verification</name>
<value>false</value>
</property>
</configuration>
初始化与启动
初始化metastore
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23$HIVE_HOME/bin/schematool -initSchema -dbType derby
# 遇到以下报错
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/root/bigData/hive-3.1.2/lib/log4j-slf4j-impl-2.10.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/root/bigData/hadoop-3.3.0/share/hadoop/common/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
Exception in thread "main" java.lang.NoSuchMethodError: com.google.common.base.Preconditions.checkArgument(ZLjava/lang/String;Ljava/lang/Object;)
at org.apache.hadoop.conf.Configuration.set(Configuration.java:1380)
at org.apache.hadoop.conf.Configuration.set(Configuration.java:1361)
at org.apache.hadoop.mapred.JobConf.setJar(JobConf.java:536)
at org.apache.hadoop.mapred.JobConf.setJarByClass(JobConf.java:554)
at org.apache.hadoop.mapred.JobConf.<init>(JobConf.java:448)
at org.apache.hadoop.hive.conf.HiveConf.initialize(HiveConf.java:5141)
at org.apache.hadoop.hive.conf.HiveConf.<init>(HiveConf.java:5104)
at org.apache.hive.beeline.HiveSchemaTool.<init>(HiveSchemaTool.java:96)
at org.apache.hive.beeline.HiveSchemaTool.main(HiveSchemaTool.java:1473)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.hadoop.util.RunJar.run(RunJar.java:323)
at org.apache.hadoop.util.RunJar.main(RunJar.java:236)
解决方案
为:比较hadoop安装目录下share/hadoop/common/lib内guava.jar版本,与hive安装目录下lib内guava.jar的版本 如果两者不一致,删除版本低的,并拷贝高版本的。
hive命令行启动
1
2
3
4
5
6
7
8
9
10
11$HIVE_HOME/bin/hive
# 启动后,会发现多了一个RunJar进程
[root@aliyun-vm ~]# jps
6882 NodeManager
6754 ResourceManager
4164 SecondaryNameNode
3814 NameNode
3946 DataNode
8236 RunJar
8430 Jpsmetastore启动
1
$HIVE_HOME/bin/hive --service metastore
hiveserver2启动
1
2
3
4
5
6$HIVE_HOME/bin/hiveserver2 --hiveconf hive.root.logger=DEBUG,console
# 使用客户端连接
$HIVE_HOME/bin/beeline
beeline> !connect jdbc:hive2://127.0.0.1:10000/default #账号密码为前面设置的hive/hive
beeline> !close
访问HiveServer2 web-ui
HSQL配置
创建一个库表,表名为 cwqsolo, 含有2个字段 id, name,并且记录中各个字段的分割符为 ‘,’,在ascii中表示为 ‘\054’;
1
CREATE TABLE cwqsolo(id INT, name STRING)ROW FORMAT DELIMITED FIELDS TERMINATED BY '\054’;
修改字段名为ID的字段,修改后名称为 myid, string类型
1
ALTER TABLE cwqsolo CHANGE id myid String;
1 | CREATE TABLE `employees` |
增加一个字段,字段名为 sex,性别
1
ALTER TABLE cwqsolo ADD COLUMNS (sex STRING COMMENT 'sex type');
加载文件
1
2
3
4[root@archive studydata]# vi test1.txt
1001,cwq,male
1101,lxj,female
hive> LOAD DATA LOCAL INPATH '/home/hadoop/hive/studydata/test1.txt' INTO TABLE cwqsolo;
导入employees数据到表
1
LOAD DATA LOCAL INPATH './classicmodels_employees.csv' OVERWRITE into table employees PARTITION (reportsto='1002');
插入条目
1
2insert into table cwqsolo values ( '1005', 'ddd','male' ); # 追加
insert overwrite table test_insert select * from test_table; # 覆盖
执行SQL文本
1
hive -f /home/hadoop/hive/sql/creat_table_biss.sql
导出文本到本地
1
2
3insert overwrite local directory '/home/data/cwq/' select * from zc_bicc_isup_bdr where calling= '13003097698';
insert overwrite local directory '/home/data/cwq/output1’ row format delimited fields terminated by ',' select * from zc_bicc_isup_bdr where calling= '13003097698’; # 指定分隔符