Apache hive详解
Hive是基于hadoop的一个数据仓库工具,可以将结构化数据文件映射为一张数据库表,并提供类SQL查询功能.
Hive的本质是将SQL装换为MapReduce程序;
主要用途:用来做离线数据分析,比直接使用MapReduce开发效率更高.
直接使用hadoop MapReduce处理数据所面临的问题:
1) 人员学习成本太高 2) MapReduce实现复杂查询逻辑开发难度太大
使用Hive:
1)操作接口采用类SQL语法,提供快速开发能力
2)避免了书写复杂的MapReduce,减少开发人员的学习成本
3)功能扩展很方便
1)用户接口:包括CLI 、JDBC/ODBC 、WebGUI。其中,CLI(comand line interface)是shell的命令行;JDBC/ODBC是hive的Java实现,与传统数据库JDBC类似;WebGUI是通过浏览器访问 Hive。
注意:我们主要的操作是shell命令行
2)元数据存储:通常是存储在关系型数据库中,hive自带数据库为derby,一般不适用;通常使用mysql数据库存储元数据;hive元数据中包括表的名字,表的列和分区及其属性,表的属性(是否为外部表等),表的数据目录等;
解析器、编译器、优化器、执行器:完成HQL查询语句从词法分析、语法分析、编译、优化以及查询计划的生成。生成的查询计划存储在HDFS中,并随后有MapReduce执行。
一句话解释:hive利用HDFS存储,利用MapReduce计算
hive用于海量数据的离线数据分析。
hive具有SQL数据库的外表,但是应用场景完全不同,hive只适合用来做批量数据统计分析
可以通过如下对比感受
Hive中所有的数据都存储在HDFS上,没有专门的数据存储格式;
在创建表时,指点数据中的分隔符,hive就可以映射成功,解析数据。
hive中包含以下数据模型:
db:在HDFS中表现为:/user/hive/metastore/warehouse/xxx.db 目录下的一个文件夹,其实相当于一个数据库。
table:在HDFS中表现为:/user/hive/metastore/warehouse/xxx.db/xxx目录下的一个文件夹,其实相当于一个数据库表。
external table:外部表,被映射的数据可以存放在HDFS中任意的位置(路径)
partition:分表,在HDFS中表现为table的下的子目录<分的是文件夹>(后详解)
bucket:分桶(分簇),在HDFS中表现为,同一个table目录下根据hash散列之后的多个文件<强调的是对文件的分解>(后详解)
5. Hive的安装部署
hive是用java语言编写,并且基于hadoop,因此安装前需要先安装好JDK和hadoop,并配置好环境变量,方便命令的使用。
根据元数据存储位置(存储介质)的不同,分为两个版本,其中derby属于内嵌模式,因为内嵌模式存在一定的致命缺陷,所以在实际的生产环境中,使用mysql数据库来进行元数据存储。
1)查看是否已经安装mysql
service mysqld / service mysql(非在线安装版本)(下图为已安装)
2)在线安装mysql
yum install mysql mysql-servermysql-devel
3)完成后启动mysql
/etc/init.d/mysqld start
4)设置mysql为开机自动启动
chkconfig mysqld on
5)检查一下是否已经设置成功(成功如下图)
chkconfig mysqld --list
6)启动mysql控制台
mysql
7)使用mysql基本数据库
mysql>; USEmysql;
8)设置用户及其密码(此处设置用户:root ,密码:1234)
mysql>; UPDATEuser SET Password=PASSWORD('1234') WHERE user='root';
9)刷新mysql
mysql>; FLUSHPRIVILEGES;
10)退出后使用新密码重新登录mysql
mysql -u root -p
Enter Password: 1234;
11)设置mysql允许远程连接(此处将远程密码设置为:123456)
GRANT ALL PRIVILEGES ON *.* TO'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
mysql安装完毕!
1)上传压缩包
2)解压缩
3)配置HIVE_HOME环境变量
vi conf/hive-env.sh
配置其中的:HADOOP_HOME=${hadoop_home}
4)配置元数据库信息,指定为mysql数据库
定位到配置文件目录
cd /export/servers/hive
创建hive-env.sh文件
vi conf/hive-env.sh
添加如下内容:
<configuration>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://node-1:3306/hive?createDatabaseIfNotExist=true</value>
<description>JDBCconnect string for a JDBC metastore</description>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
<description>Driverclass name for a JDBC metastore</description>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
<description>usernameto use against metastore database</description>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>1234</value>
<description>passwordto use against metastore database</description>
</property>
</configuration>
注意:修改用户名和密码!
5) 安装hive和mysq完成后,将mysql的连接jar包拷贝到$HIVE_HOME/lib目录下
如果出现没有权限的问题,在mysql授权(在安装mysql的机器上执行)
mysql -uroot -p
#(执行下面的语句 *.*:所有库下的所有表 %:任何IP地址或主机都可以连接)
grant all privileges on *.* to'root'@'%' identified by 'root' with grant option;
flush privileges;
1)方式一:hive交互shell
bin/hive
2)方式二:Hive JDBC服务(参考java jdbc连接mysql)
3)方式三:hive启动一个服务器,开放一个端口(port=10000)对外提供服务
a. 在提供服务的服务器(node-1)上启动hiveserver2
bin/hiveserver2
b. 启动成功后,可以在别的节点上用beeline去连接
bin/beeline -u jdbc:hive2://node-1:10000 -nroot
或者(推荐使用,简单)
bin/beeline
! connect jdbc:hive2://node-1:10000
注意:用户名为node-1上的用户名
密码为该用户用于登录的密码
4)方式四:Hive命令 (后面介绍,启动时还可以添加什么参数)
hive -e ‘sql’
eg: bin/hive -e 'select *from t_test'
create [external]table [if not exists] table_name
[(col_namedata_type [comment col_comment], ...)]
[commenttable_comment]
[partitioned by(col_name data_type [comment col_comment], ...)]
[clustered by(col_name, col_name, ...)
[sorted by(col_name [asc|desc], ...)] into num_buckets buckets]
[row formatrow_format]
[stored asfile_format]
[locationhdfs_path]
说明:
1、createtable +表名:创建一个指定名字的表,如果相同名字的
表已经存在,则会抛 出异常;用户可以通过加上关键字 IF NOT
EXISTS 选项来忽略这个异常;
例子:createtable t_t1(id int,...) row format delimited fields terminated by ',';
注意:设定字段分隔符为","
2、external关键字可以让用户创建一个外部表,在建表的同时指定
一个指向实际数据的路径(location);
例子:createexternal table t_t1(id int,...) row format delimited fields terminated by ',';
Hive创建内部表时,会将数据移动到数据仓库指定位置:/user/hive/warehouse/库/表;
Hive创建外部表时,仅记录数据所在路径,不对数据的位置坐任何改变;
Hive删除内部表时,内部表的元数据和结构化数据会一起被删除;
Hive删除外部表时,外部表仅会删除元数据,结构化数据不会被删除;
3、Like 关键字允许复制现有的表结构,但是不复制数据
create[external] table [if not exists] [db_name] table_name like existing_table;
4、创建表时需要根据结构化数据设置分隔符
设置分隔符语法目录树
row format delimited //开始设置分隔符
[fields terminated by char] //设置字段分隔符
[collection items terminated by char] //设置列表集合元素分隔符
[map keys terminated by char] //设置map的key的分隔符
[lines terminated by char] | serdeserde_name
[with serdeproperties
(property_name=property_value, property_name=property_value,...)]
例子:
>createtable t_map(id int,name string,hobby map<string,string>)(建表)
>rowformat delimited(指定分隔符)
>fieldsterminated by ',' (指定字段根据“,”分隔)
>collectionitems terminated by '-' (集合元素根据‘-’分隔)
>mapkeys terminated by ':' ;(map的key之间根据‘:’分隔)
hive建表时默认的分隔符是"\001",若在建表时没有指定分隔符,则装载(load)的结
构化数据必须是以"\001"来分隔的,如果数据的分隔符不是"\001",程序不会报错,但是
表查询结果都为"null";也就是说:表创建成功了但是数据没有映射成功。
注意:用 vi 编辑器 Ctrl+v 然后Ctrl+a 即可输入'\001' -----------> ^A
SerDe 是 Serialize/Deserilize 的简称,目的是用于序列化和反序列化。
Hive读取文件机制:首先调用InputFormat(默认 TextInputFormat),一行一行的读取
数据,然后调用SerDe (默认LazySimpleSerDe)的 Deserializer,将一条记录切分为
各个字段(默认'\001')。
Hive 写文件机制:将 Row 写入文件时,主要调用 OutputFormat、SerDe 的
Seriliazer,顺序与读取相反。
可通过descformatted + 表名;进行相关信息查看。
当我们的数据格式比较特殊的时候,可以自定义 SerDe。
5、partitionedby (分区语句)<重点>
在 hive Select 查询中一般会扫描整个表内容,会消耗很多时间做没必要的工
作。有时候只需要扫描表中关心的一部分数据,因此建表时引入了 partition 分区
念。
分区表指的是在创建表时指定的 partition 的分区空间。一个表可以拥有一个或者多
个分区,每个分区以文件夹的形式单独存在表文件夹的目录下。表和列名不区分大
小写。分区是以字 段的形式在表结构中存在,通过 edescribe table 命令可
以查看到字段存在,但是该字段不存放实际的数据内容,仅仅是分区的表示。
分区表的数据装载形式:
>直接fs put 结构化数据到 表目录已经不行了
>因为分区表建表的时候设置了分区的标识
>因此在导入数据的时候要指定具体的分区标识
使用下述的方式导入数据:
>load data //加载数据
>local inpath'/root/hivedata/china.txt' //本地资源路径
>into tablet_user2 //插入到表t_user2
>partition(country='China');//分区字段标识,必须不能是表中已有字段
正确的分区建表:
>create tablet_user2(id int,name string,age int)
>partitioned by(country string) //分区
>row format delimited
>fields terminated by",";
如下图,创建好的分区
分区表总结:
1、分区的字段(标识)不能是表中已经存在的字段
2、建立分区表语法顺序要注意符合语法树的规则
3、分区表的数据得使用load data方式加载数据 且指定具体分区字段值(分区标识值)
4、分区字段在select查询中可见,但是仅标识分区标识 该字段内容并不存在于数据中
因此把分区字段称为虚拟的字段
5、建立分区表且导入分区数据成功 就可以直接在select中通过where 分区字段==分区
字段值 ,过滤出你所需的数据且在底层减少了全表全数据的扫描大大提高了查询的
效率。
6、 当有了分区后,数据就不直接在表对应的文件夹下
而是在表下还有分区字段的文件夹(分区字段=分区值),对应的数据在对应的分区
文件夹下面。
也是从侧面反映是从文件夹来去更好管理数据。
6、storedas sequencefile|textfile|rcfile
如果文件数据是纯文本,可以使用 stored as textfile。如果数据需要压缩,使用 stored
as sequencefile。
7、clusteredby into num_buckets buckets(分桶)<重点>
对于每一个表(table)或者分区,Hive 可以进一步组织成桶,文件层面的分割,而不
是文件夹层面的分割,也就是说桶是更为细粒度的数据范围划分。Hive也是针对某一列
进行桶的组织。Hive 采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放
在哪个桶当中。
把表(或者分区)组织成桶(Bucket)有两个理由:
(1)获得更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询
时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,
可以使用 Map 端连接 (Map-side join)高效的实现。比如 JOIN 操作。对于 JOIN 操
作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶
进行 JOIN 操作就可以,可以大大较少 JOIN 的数据量。
(2)使取样(sampling)更高效。在处理大规模数据集时,在开发和修改查询的阶
段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便。
具体操作:
1、首先开启分桶的功能 指定分为几桶。
>sethive.enforce.bucketing; //可以查看是否开启
>sethive.enforce.bucketing = true; //开启分桶功能
>setmapreduce.job.reduces=4; //设置分桶个数
2、创建分桶表:
>create tablestu_buck(id int,name string)
>clustered by(Sno)
>into 4 buckets
>row format delimited
>fields terminated by',';
3、分桶表装载数据:insert+select
>insert overwrite tablestu_buck
>select * from studentcluster by(id);
插入表的数据来自于查询语句的返回结果
小结:分桶表能不能创建成功 取决于底层有没有执行mr程序因为mr最终输出
几个部分 就是桶表的几个部分
分桶表总结:
1、分桶表是在文件的层面把数据分开
2、按照谁分开
建表的时候指定clustered by,且分桶字段必须是表中已经存在的字段
3、分开几个部分(桶)
建表的时候指定into X buckets,且分桶的个数跟设置的reducetask一致
set mapreduce.job.reduces=X;
4、分桶表的数据装载 底层实质是mr程序的执行
insert+select;
5、分桶的规则:
hashfunc(分桶的字段) % 桶数
a.如果分桶字段是数字类型 hashfunc(分桶的字段)==字段本身
b.如果是非数字类型 hashfunc(分桶的字段)==字段.hashcode
增加分区:
>alter table t_name add partition (dt='20170101') location
>'/user/hadoop/warehouse/table_name/dt=20170101'; //一次添加一个分区
>alter table t_name add partition (dt='2008-08-08', country='us')location
>'/path/to/us/part080808' partition (dt='2008-08-09',country='us') location
>'/path/to/us/part080809'; //一次添加多个分区
删除分区:
>alter table t_name drop if exists partition (dt='2008-08-08');
>alter table t_name drop if exists partition (dt='2008-08-08', country='us');
修改分区:
>alter table t_name partition (dt='2008-08-08')
>rename to partition (dt='20080808');
添加列:
alter table t_name add|replace columns (col_name string);
注: add 是代表新增一个字段,新增字段位置在所有列后面 (partition 列前 )
replace 则是表示替换表中所有字段。
修改列:
test_change (a int, b int, c int);
ALTER TABLE test_change CHANGE a a1 INT; //修改 a 字段名
// will change column a's name to a1, a's data type to string, andput it after
column b. The new
table's structure is: b int, a1 string, c int
ALTER TABLE test_change CHANGE a a1 STRING AFTER b;
// will change column b's name to b1, and put it as the firstcolumn. The new
table's structure is:
b1 int, a ints, c int
ALTER TABLE test_change CHANGE b b1 INT FIRST;
表重命名
ALTER TABLE t_name RENAME TO new_table_name
1)显示当前数据库所有表
show tables;
2)显示所有数据库
show databases | show schemas
3)显示表分区信息,不是分区表执行报错
show partitions t_name;
4)显示当前版本 hive 支持的所有方法
show functions;
5)查看表信息
desc extended t_name;
6)查看表信息,格式美化
desc formatted t_name;
7)查看特定数据库详细信息
describe database DB_name;
在将数据加载到表中时,Hive 不会进行任何转换。加载操作是将数据文件移动到与
Hive,表对应的位置的纯复制/移动操作。
语法结构:
load data [local] inpath'filepath' [overwrite] into
table t_name [partition(partcol1=val1, partcol2=val2 ...)]
说明:
1、filepath:
相对路径,例如:project/data1
绝对路径,例如:/user/hive/project/data1
完整 URI,例如:hdfs://node-1:9000/user/hive/project/data1
filepath 可以引用一个文件(在这种情况下,Hive 将文件移动到表中),或
者它可以是一个目录(在这种情况下,Hive 将把该目录中的所有文件移动到表
中)。
2、local:
如果指定了 LOCAL, load 命令将在本地文件系统中查找文件路径。
load 命令会将 filepath 中的文件复制到目标文件系统中。目标文件系统由表
的位置属性决定。被复制的数据文件移动到表的数据对应的位置。
如果没有指定 LOCAL 关键字,如果 filepath 指向的是一个完整的 URI,hive
会直接使用这个 URI。否则:如果没有指定 schema 或者 authority,Hive 会
使用在 hadoop 配置文件中定义的 schema 和 authority,fs.default.name 指
定了Namenode 的 URI。
总结:
有local,如果数据在本地 本质上就是一个复制操作 从本地文件系统复制
到hdfs指定的路径下
无local , 表明数据来自于hdfs分布式文件系统 本质上是文件的移动操作
3、overwrite:(谨慎使用次关键字)
如果使用了 OVERWRITE 关键字,则目标表(或者分区)中的内容会被删
除,然后再将 filepath 指向的文件/目录中的内容添加到表/分区中。
如果目标表(分区)已经有一个文件,并且文件名和 filepath 中的文件名冲
突,那么现有的文件会被新文件所替代。
Hive 中 insert 主要是结合select 查询语句使用,将查询结果插入到表中,例如:
>insert overwrite table stu_buck
>select * from student cluster by(Sno);
需要保证查询结果列的数目、数据类型和需要插入数据表格的列数目、数据类型一致.
如果查询出来的数据类型和插入表格对应的列数据类型不一致,将会进行转换,但
是不能保证转换一定成功,转换失败的数据将会为 NULL。
可以将一个表查询出来的数据插入到原表中, 结果相当于自我复制了一份数据。
Multi Inserts 多重插入:(单次插入效率低,一次查询多重插入提高效率)
>from source_table
>insert overwrite tablet_name1 [partition (partcol1=val1,partclo2=val2)]
>select id
>insert overwrite tablet_name2 [partition (partcol1=val1,partclo2=val2)]
>select name;
上述SQL语句的含义:将source_table中的id和name字段分别插入到t_name1和
t_name2表中;可选项:在插入时进行分区
Dynamic partition inserts 动态分区插入:
(与静态分区相对,是通过insert+selecte实现)
sethive.exec.dynamic.partition=true; #是否开启动态分区功能,默认false关
闭。
sethive.exec.dynamic.partition.mode=nonstrict; #动态分区的模式,默认
strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分
区字段都可以使用动态分区。
举例说明动态分区实现过程:
1、原始表:
>create tabledynamic_partition_table(day string,ip string)
>row format delimitedfields terminated by ",";
2、装载数据
>load data
>local inpath'/root/hivedata/dynamic_partition_table.txt'
>into tabledynamic_partition_table;
再次假设结构化数据如下:
2015-05-10,ip1
2015-05-10,ip2
2015-06-14,ip3
2015-06-14,ip4
2015-06-15,ip1
2015-06-15,ip2
3、目标表:
>create table d_p_t(ipstring) partitioned by (month string,day string);
4、动态插入
>insert overwrite tabled_p_t partition (month,day)
>selectip,substr(day,1,7) as month,day from dynamic_partition_table;
注意:动态分区是通过位置来对应分区值的。原始表select 出来的值和输出
partition的值的关系仅仅是通过位置来确定的,和名字并没有关系。
导出表数据:
语法结构目录树
insert overwrite [local]directory directory1 select ... from ...
multiple inserts:
from from_statement
insert overwrite [local]directory directory1 select_statement1
[insert overwrite [local]directory directory2 select_statement2] ..
举例说明使用方法:
数据导出
1)导出到hive服务器本地
>insert overwrite local directory '/root/output'
>select * from t_name;
2)导出到hdfs指定目录
>insert overwritedirectory '/output'
>select * from t_name;
数据写入到文件系统时进行文本序列化,且每列用^A 来区分,\n 为换行符。
注意:overwrite!!!
语法目录树:
select [all | distinct] select_expr, select_expr, ...
from table_reference
join table_other on expr
[where where_condition]
[group by col_list [having condition]]
[cluster by col_list
| [distribute by col_list] [sort by| order by col_list]
]
[limit number]
说明:
1)orderby 会对输入做全局排序,因此只有一个reducetask,当数据较大时,花
费的时间会比较久;
2)sortby 不是全局排序,在数据进入reducetask之前完成排序。因此,如果使用
sort by排序。并且设置job.setNumReduceTask(N),N>1,则sort by只能保证每个
reducetask内部是排序的,无法保证全局;
注意:[distribute by col_list sort by ] 和[cluster by col_list]的区别;
3)distributeby col_list 根据指定字段将数据分到不同的reducetask,分发算法
是hash散列。
4)Clusterby(字段) 除了具有 Distribute by 的功能外,还会对该字段进行排序。
注意:如果 distribute 和 sort 的字段是同一个时,此时,cluster by = distribute by + sort by
Hive 中除了支持和传统数据库中一样的内关联、左关联、右关联、全关联,还支持 LEFT
SEMI JOIN 和 CROSS JOIN,但这两种 JOIN 类型也可以用前面的代替。
Hive 支持等值连接 (a.id = b.id ), , 不支持非等值( (a.id>b.id) ) 的连接,因为非等值连接
非常难转化到 map/reduce 任务。另外,Hive 支持多 2 个以上表之间的 join。
写 join 查询时,需要注意几个关键点:
1)join 时,每次map/reduce 任务的逻辑:(优化)
reducer 会缓存 join 序列中除了最后一个表的所有表的记录,再通过最后一个表将
结果序列化到文件系统。这一实现有助于在 reduce 端减少内存的使用量。实践中,应该
把最大的那个表写在最后(否则会因为缓存浪费大量内存)。
2)LEFT , RIGHT 和 FULL OUTER 关键字用于处理 join 中空记录的情况
left:以左表为主,显示左表全部内容,右表中未对应上的显示null
right:以右表为主,显示右表全部内容,左表中未对应上的显示null
full outer:左右全部显示,未能对应的显示null
3)Join 发生在 WHERE 子句之前
如果你想限制 join 的输出,应该在 WHERE 子句中写过滤条件——或是在 join 子句
中写。这里面一个容易混淆的问题是表分区的情况:
SELECT a.val, b.val FROM a
LEFT OUTER JOIN b ON(a.key=b.key)
WHERE a.ds='2009-07-07'AND b.ds='2009-07-07'
这会 join a 表到 b 表(OUTERJOIN),列出 a.val 和 b.val 的记录。WHERE 从句
中可以使用其他列作为过滤条件。但是,如前所述,如果 b 表中找不到对应 a 表的记
录,b 表的所有列都会列出 NULL,包括ds 列。也就是说,join 会过滤 b 表中不能找到
匹配 a 表 join key 的所有记录。这样的话,LEFT OUTER 就使得查询结果与 WHERE
子句无关了。解决的办法是在 OUTER JOIN 时使用以下语法:
SELECT a.val, b.val FROM aLEFT OUTER JOIN b
ON (a.key=b.key AND
b.ds='2009-07-07' AND
a.ds='2009-07-07');
这一查询的结果是预先在 join 阶段过滤过的,所以不会存在上述问题。这一逻辑也
可以应用于 RIGHT 和 FULL 类型的join 中。
4)Join 是不能交换位置的
无论是 LEFT 还是 RIGHT join,都是左连接的。
SELECT a.val1, a.val2,b.val, c.val
FROM a
JOIN b ON (a.key = b.key)
LEFT OUTER JOIN c ON(a.key = c.key)
先 join a 表到 b 表,丢弃掉所有join key 中不匹配的记录,然后用这一中间结果
和 c 表做 join
输入$HIVE_HOME/bin/hive –H 或者 –help 可以显示帮助选项:
说明:
1) -i 初始化 HQL 文件。
2) -e 从命令行执行指定的 HQL
3) -f 执行 HQL 脚本
4) -v 输出执行的 HQL 语句到控制台
5) -p <port> connect to Hive Server onport number
6) -hiveconf x=y Use this to set hive/hadoopconfiguration variables.
例如:
$HIVE_HOME/bin/hive -e'select * from tab1 a'
$HIVE_HOME/bin/hive -f/home/my/hive-script.sql
$HIVE_HOME/bin/hive -fhdfs://<namenode>:<port>/hive-script.sql
$HIVE_HOME/bin/hive -i /home/my/hive-init.sql
$HIVE_HOME/bin/hive -e 'select a.col from tab1 a'
--hiveconf hive.exec.compress.output=true
--hiveconf mapred.reduce.tasks=32
重点:关注-e 和 -f ,-e启动hive时执行一个SQL语句后退出;-f 启动hive时执行一个.sh脚本后退出
7.2 Hive 参数配置方式
Hive 参数大全:
https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties
开发 Hive 应用时,不可避免地需要设定 Hive 的参数。设定 Hive 的参数可以调优 HQL 代
码的执行效率,或帮助定位问题。然而实践中经常遇到的一个问题是,为什么设定的参数没
有起作用?这通常是错误的设定方式导致的。
1)对于一般参数,有以下三种设定方式:
配置文件 (全局有效)
命令行参数 (对 hive 启动实例有效)
参数声明 (对 hive 的连接 session 有效)
2)配置文件
用户自定义配置文件:$HIVE_CONF_DIR/hive-site.xml
默认配置文件:$HIVE_CONF_DIR/hive-default.xml
用户自定义配置会覆盖默认配置。
另外,Hive 也会读入 Hadoop 的配置,因为 Hive 是作为 Hadoop 的客户端启动的,
Hive 的配置会覆盖 Hadoop 的配置。
配置文件的设定对本机启动的所有 Hive 进程都有效。
3)命令行参数
启动 Hive(客户端或 Server 方式)时,可以在命令行添加-hiveconf 来设定参数
例如:bin/hive -hiveconfhive.root.logger=INFO,console
设定对本次启动的 Session(对于 Server 方式启动,则是所有请求的 Sessions)有效
4)参数声明
可以在 HQL 中使用 SET 关键字设定参数,这一设定的作用域也是 session 级的。
比如:
sethive.exec.reducers.bytes.per.reducer=<number> 每个reduce task 的平均负载数据量
sethive.exec.reducers.max=<number> 设置 reduce task 数量的上限
setmapreduce.job.reduces=<number> 指定固定的 reduce task 数量
但是,这个参数在必要时<业务逻辑决定只能用一个 reduce task> hive 会忽略
上述三种设定方式的优先级依次递增。即参数声明覆盖命令行参数,命令行参数覆盖配
置文件设定。注意某些系统级的参数,例如 log4j 相关的设定,必须用前两种方式设定,因
为那些参数的读取在 Session 建立以前已经完成了。
在 Hive 有四种类型的运算符:
1)关系运算符
2)算术运算符
3)逻辑运算符
4)复杂运算
内容较多,见《 Hive 官方文档》或者《 hive 常用运算和函数 .doc 》
内置函数官方说明:
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
测试各种内置函数的快捷方法:
创建一个 dual 表
create table dual(id string);
load 一个文件(只有一行内容:内容为一个空格)到 dual 表
select substr('angelababy',2,3)from dual;
内容较多,见《 Hive 官方文档》或者《 hive 常用运算和函数 .doc 》
. UDF 开发实例:
1)新建 JAVAmaven 项目
2)写一个 java 类,继承 UDF,并重载 evaluate 方法
3)打成 jar 包上传到服务器
4)将 jar 包添加到 hive 的 classpath:一定要使用hive提供的指令
>add JAR /home/hadoop/udf.jar;
5)创建临时函数与开发好的 java class 关联(仅当前session有效)
6)即可在 hql 中使用自定义的函数tolowercase ip
Hive 的 TRANSFORM 关键字 提供了在 SQL 中调用自写脚本的功能
适合实现 Hive 中没有的功能又不想写 UDF 的情况
<主要是针对那些懂SQL却不懂java,又想使用hive的程序员>
hive 读取数据的机制:
首先用 InputFormat< 默认是:org.apache.hadoop.mapred.TextInputFormat>的一
个具体实现类读入文件数据,返回一条一条的记录(可以是行,或者是你逻辑的“行”)
然后利用 SerDe< 默认:org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe>
的一个具体实现类,对上面返回的一条一条的记录进行字段切割。
Hive 对文件中字段的分隔符默认情况下只支持单字节分隔符,如果数据文件中的分
隔符是多字符的,如下所示:
01||zhangsan
02||lisi
可用使用 RegexSerDe 通过正则表达式来抽取字段(因数据的结构化形式一般是数据清洗工
程师来搞定,不适用复杂的分隔符,因此使用频率相对较低,不扩展)。
---------------转载注明出处!