Hive体系结构(四)注意事项与扩展特性

时间:2022-12-18 20:56:51

Hive体系结构(一)架构与基本组成
Hive体系结构(二)Hive的执行原理、与关系型数据库的比较
Hive体系结构(三)元数据库与基本操作
Hive体系结构(四)注意事项与扩展特性

1. 使用HIVE注意点

  1. 字符集
    Hadoop和Hive都是用UTF-8编码的,所以, 所有中文必须是UTF-8编码, 才能正常使用。
    备注:中文数据load到表里面,,如果字符集不同,很有可能全是乱码需要做转码的,但是hive本身没有函数来做这个。
  2. 压缩
    hive.exec.compress.output 这个参数,默认是false,但是很多时候貌似要单独显式设置一遍,否则会对结果做压缩的,如果你的这个文件后面还要在hadoop下直接操作,那么就不能压缩了。
  3. count(distinct)
    当前的Hive不支持在一条查询语句中有多Distinct。如果要在Hive查询语句中实现多Distinct,需要使用至少n+1条查询语句(n为distinct的数目),前n条查询分别对n个列去重,最后一条查询语句对n个去重之后的列做Join操作,得到最终结果。
  4. JOIN
    只支持等值连接
  5. DML操作
    只支持INSERT/LOAD操作,无UPDATE和DELTE
  6. HAVING
    不支持HAVING操作。如果需要这个功能要嵌套一个子查询用where限制
  7. 子查询
    Hive不支持where子句中的子查询
  8. Join中处理null值的语义区别
    SQL标准中,任何对null的操作(数值比较,字符串操作等)结果都为null。Hive对null值处理的逻辑和标准基本一致,除了Join时的特殊逻辑。这里的特殊逻辑指的是,Hive的Join中,作为Join key的字段比较,null=null是有意义的,且返回值为true。
  9. 分号字符
    分号是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;
}
}