Hive体系结构(一)架构与基本组成
Hive体系结构(二)Hive的执行原理、与关系型数据库的比较
Hive体系结构(三)元数据库与基本操作
Hive体系结构(四)注意事项与扩展特性
1. 使用HIVE注意点
- 字符集
Hadoop和Hive都是用UTF-8编码的,所以, 所有中文必须是UTF-8编码, 才能正常使用。
备注:中文数据load到表里面,,如果字符集不同,很有可能全是乱码需要做转码的,但是hive本身没有函数来做这个。 - 压缩
hive.exec.compress.output 这个参数,默认是false,但是很多时候貌似要单独显式设置一遍,否则会对结果做压缩的,如果你的这个文件后面还要在hadoop下直接操作,那么就不能压缩了。 - count(distinct)
当前的Hive不支持在一条查询语句中有多Distinct。如果要在Hive查询语句中实现多Distinct,需要使用至少n+1条查询语句(n为distinct的数目),前n条查询分别对n个列去重,最后一条查询语句对n个去重之后的列做Join操作,得到最终结果。 - JOIN
只支持等值连接 - DML操作
只支持INSERT/LOAD操作,无UPDATE和DELTE - HAVING
不支持HAVING操作。如果需要这个功能要嵌套一个子查询用where限制 - 子查询
Hive不支持where子句中的子查询 - Join中处理null值的语义区别
SQL标准中,任何对null的操作(数值比较,字符串操作等)结果都为null。Hive对null值处理的逻辑和标准基本一致,除了Join时的特殊逻辑。这里的特殊逻辑指的是,Hive的Join中,作为Join key的字段比较,null=null是有意义的,且返回值为true。 - 分号字符
分号是SQL语句结束标记,在HiveQL中也是,但是在HiveQL中,对分号的识别没有那么智慧,例如:
select concat(cookie_id,concat(';',’zoo’)) from c02_clickstat_fatdt1 limit 2;
FAILED: Parse Error: line 0:-1 cannot recognize input '<EOF>' in function specification
可以推断,Hive解析语句的时候,只要遇到分号就认为语句结束,而无论是否用引号包含起来。
解决的办法是,使用分号的八进制的ASCII码进行转义,那么上述语句应写成:
select concat(cookie_id,concat('\073','zoo')) from c02_clickstat_fatdt1 limit 2;
为什么是八进制ASCII码?我尝试用十六进制的ASCII码,但Hive会将其视为字符串处理并未转义,好像仅支持八进制,原因不详。这个规则也适用于其他非SELECT语句,如CREATE TABLE中需要定义分隔符,那么对不可见字符做分隔符就需要用八进制的ASCII码来转义。
10. Insert
根据语法Insert必须加“OVERWRITE”关键字,也就是说每一次插入都是一次重写。
2. Hive的扩展特性
Hive 是一个很开放的系统,很多内容都支持用户定制,包括:
* 文件格式:Text File,Sequence File
* 内存中的数据格式: Java Integer/String, Hadoop IntWritable/Text
* 用户提供的map/reduce脚本:不管什么语言,利用stdin/stdout传输数据
* 用户自定义函数:Substr, Trim, 1 – 1
* 用户自定义聚合函数:Sum, Average…… n – 1
2.1 数据文件格式
TextFile | SequenceFIle | RCFFile |
---|---|---|
Data type | Text Only | Text/Binary |
Internal Storage Order | Row-based | Row-based |
Compression | File Based | Block Based |
Splitable | YES | YES |
Splitable After Compression | No | YES |
例如使用文件文件格式存储创建的表:
CREATE TABLE mylog ( user_id BIGINT, page_url STRING, unix_time INT) STORED AS TEXTFILE;
当用户的数据文件格式不能被当前Hive所识别的时候,可以自定义文件格式。可以参考contrib/src/java/org/apache/hadoop/hive/contrib/fileformat/base64
中的例子。写完自定义的格式后,在创建表的时候指定相应的文件格式就可以:
CREATE TABLE base64_test(col1 STRING, col2 STRING)
STORED AS
INPUTFORMAT 'org.apache.hadoop.hive.contrib.fileformat.base64.Base64TextInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.contrib.fileformat.base64.Base64TextOutputFormat';
2.2 SerDe
SerDe是Serialize/Deserilize的简称,目的是用于序列化和反序列化。
序列化的格式包括:分隔符(tab、逗号、CTRL-A)、Thrift 协议。
反序列化(内存内):Java Integer/String/ArrayList/HashMap、Hadoop Writable类、用户自定义类。
其中,LazyObject只有在访问到列的时候才进行反序列化。 BinarySortable保留了排序的二进制格式。
当存在以下情况时,可以考虑增加新的SerDe:
* 用户的数据有特殊的序列化格式,当前的Hive不支持,而用户又不想在将数据加载至Hive前转换数据格式。
* 用户有更有效的序列化磁盘数据的方法。
用户如果想为Text数据增加自定义Serde,可以参照contrib/src/java/org/apache/hadoop/hive/contrib/serde2/RegexSerDe.java
中的例子。RegexSerDe利用用户提供的正则表倒是来反序列化数据,例如:
CREATE TABLE apache_log(
host STRING,
identity STRING,
user STRING,
time STRING,
request STRING,
status STRING,
size STRING,
referer STRING,
agent STRING)
ROW FORMAT
SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
WITH SERDEPROPERTIES
( "input.regex" = "([^ ]*) ([^ ]*) ([^ ]*) (-|\\[[^\\]]*\\])
([^ \"]*|\"[^\"]*\") (-|[0-9]*) (-|[0-9]*)(?: ([^ \"]*|\"[^\"]*\")
([^ \"]*|\"[^\"]*\"))?",
"output.format.string" = "%1$s %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s";)
STORED AS TEXTFILE;
用户如果想为Binary数据增加自定义的SerDe,可以参考例子serde/src/java/org/apache/hadoop/hive/serde2/binarysortable
,例如:
CREATE TABLE mythrift_table
ROW FORMAT SERDE
'org.apache.hadoop.hive.contrib.serde2.thrift.ThriftSerDe'
WITH SERDEPROPERTIES (
"serialization.class" = "com.facebook.serde.tprofiles.full",
"serialization.format" = "com.facebook.thrift.protocol.TBinaryProtocol";);
2.3 Map/Reduce脚本(Transform)
用户可以自定义Hive使用的Map/Reduce脚本,比如:
FROM (
SELECT TRANSFORM(user_id, page_url, unix_time)
USING 'page_url_to_id.py'
AS (user_id, page_id, unix_time)
FROM mylog
DISTRIBUTE BY user_id
SORT BY user_id, unix_time)
mylog2
SELECT TRANSFORM(user_id, page_id, unix_time)
USING 'my_python_session_cutter.py' AS (user_id, session_info);
Map/Reduce脚本通过stdin/stdout进行数据的读写,调试信息输出到stderr。
2.4 UDF(User-Defined-Function)
用户可以自定义函数对数据进行处理,例如:
add jar build/ql/test/test-udfs.jar;
CREATE TEMPORARY FUNCTION testlength
AS 'org.apache.hadoop.hive.ql.udf.UDFTestLength';
SELECT testlength(src.value) FROM src;
DROP TEMPORARY FUNCTION testlength;
UDFTestLength.java为:
package org.apache.hadoop.hive.ql.udf;
public class UDFTestLength extends UDF {
public Integer evaluate(String s) {
if (s == null) {
return null;
}
return s.length();
}
}
UDF 具有以下特性:
* 用java写UDF很容易。
* Hadoop的Writables/Text 具有较高性能。
* UDF可以被重载。
* Hive支持隐式类型转换。
* UDF支持变长的参数。
* genericUDF 提供了较好的性能(避免了反射)。
2.5 UDAF(User-Defined Aggregation Funcation)
例子:
SELECT page_url, count(1), count(DISTINCT user_id) FROM mylog;
UDAFCount.java代码如下:
public class UDAFCount extends UDAF {
public static class Evaluator implements UDAFEvaluator {
private int mCount;
public void init() {
mcount = 0;
}
public boolean iterate(Object o) {
if (o!=null)
mCount++;
return true;
}
public Integer terminatePartial() {
return mCount;
}
public boolean merge(Integer o) {
mCount += o;
return true;
}
public Integer terminate() {
return mCount;
}
}