HIVE User Guide 总结之四

7.HIVE 的MAP/REDUCE

7.1 jion

    对于 JOIN 操作:

INSERT OVERWRITE TABLE pv_users 
SELECT pv.pageid, u.age FROM page_view pv JOIN user u ON (pv.userid = u.userid);

   实现过程为:

  • Map

    • JOIN ON 条件中的列作为 Key,如果有多个列,则 Key 是这些列的组合

    • JOIN 之后所关心的列作为 Value,当有多个列时,Value 是这些列的组合。在 Value 中还会包含表的 Tag 信息,用于标明此 Value 对应于哪个表。

    • 按照 Key 进行排序。

  • Shuffle

    • 根据 Key 的值进行 Hash,并将 Key/Value 对按照 Hash 值推至不同对 Reduce 中。

  • Reduce

    • Reducer 根据 Key 值进行 Join 操作,并且通过 Tag 来识别不同的表中的数据。

    具体实现过程如图:

    

7.2 GROUP BY

SELECT pageid, age, count(1) FROM pv_users GROUP BY pageid, age;

7.3 DISTINCT

SELECT age, count(distinct pageid) FROM pv_users GROUP BY age;

  实现过程如图:

8.使用HIVE注意点

8.1字符集

    Hadoop和Hive都是用UTF-8编码的,所以, 所有中文必须是UTF-8编码, 才能正常使用。

    备注:中文数据load到表里面, 如果字符集不同,很有可能全是乱码需要做转码的, 但是hive本身没有函数来做这个

      8.2 压缩

          hive.exec.compress.output 这个参数, 默认是 false,但是很多时候貌似要单独显式设置一遍,否则会对结果做压缩的,如果你的这个文件后面还要在hadoop下直接操作, 那么就不能压缩了

      8.3 count(distinct)

         当前的 Hive 不支持在一条查询语句中有多 Distinct。如果要在 Hive 查询语句中实现多Distinct,需要使用至少 n+1 条查询语句(ndistinct的数目),前 n 条查询分 别对 n 个列去重,最后一条查询语句对 n 个去重之后的列做 Join 操作,得到最终结果。

      8.4 Join

         只支持等值连接

      8.5  DML操作

      只支持INSERT/LOAD操作,无UPDATEDELTE

      8.6 HAVING

         不支持HAVING操作。如果需要这个功能要嵌套一个子查询用where限制

      8.7 子查询

         Hive不支持where子句中的子查询

      8.8 Join中处理null值的语义区别

         SQL标准中,任何对null的操作(数值比较,字符串操作等)结果都为nullHivenull值处理的逻辑和标准基本一致,除了Join时的特殊逻辑。

    这里的特殊逻辑指的是,HiveJoin中,作为Join key的字段比较,null=null是有意义的,且返回值为true。检查以下查询

select u.uid, count(u.uid) 
from t_weblog l join t_user u on (l.uid = u.uid) group by u.uid;

        查询中,t_weblog表中uid为空的记录将和t_user表中uid为空的记录做连接,即l.uid = u.uid=null成立。

如果需要与标准一致的语义,我们需要改写查询手动过滤null值的情况:

select u.uid, count(u.uid) 
from t_weblog l join t_user u 
    on (l.uid = u.uid and l.uid is not null and u.uid is not null)
group by u.uid;

        实践中,这一语义区别也是经常导致数据倾斜的原因之一。

      8.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码来转义。

      8.10 Insert

         1. 新增数据

            根据语法Insert必须加“OVERWRITE”关键字,也就是说每一次插入都是一次重写。那如何实现表中新增数据呢?

      假设Hive中有表xiaojun1,

hive> DESCRIBE xiaojun1;
OK
id int
value int
hive> SELECT * FROM xiaojun1;
OK
3 4
1 2
2 3

             现增加一条记录:

hive> INSERT OVERWRITE TABLE xiaojun1 
SELECT id, value FROM (
    SELECT id, value FROM xiaojun1 
    UNION ALL 
    SELECT 4 AS id, 5 AS value FROM xiaojun1 limit 1
) u;
结果是: 
hive>SELECT * FROM p1; 
OK
3 4
4 5
2 3
1 2

            其中的关键在于, 关键字UNION ALL的应用, 即将原有数据集和新增数据集进行结合, 然后重写表

         2.插入次序

            INSERT OVERWRITE TABLE在插入数据时,是按照后面的SELECT语句中的字段顺序插入的. 也就说, id value 的位置互换, 那么value将被写入id, id被写入value.

         3. 初始值

            INSERT OVERWRITE TABLE在插入数据时, 后面的字段的初始值应注意与表定义中的一致性. 例如, 当为一个STRING类型字段初始为NULL:

NULL AS field_name // 这可能会被提示定义类型为STRING, 但这里是void 
CAST(NULL AS STRING) AS field_name // 这样是正确的

     又如, 为一个BIGINT类型的字段初始为0:

CAST(0 AS BIGINT) AS field_name



jiewei

你可能感兴趣的:(HIVE User Guide 总结之四)