hive 的分隔符、orderby sort by distribute by的优化

标签: hive orderby sort | 发表时间:2014-08-28 21:06 | 作者:manburen01
出处:http://blog.csdn.net

一、Hive 分号字符

分号是SQL语句结束标记,在HiveQL中也是,但是在HiveQL中,对分号的识别没有那么智慧,例如:

select concat(cookie_id,concat(';',’zoo’)) fromc02_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')) fromc02_clickstat_fatdt1 limit 2;

为什么是八进制ASCII码?

我尝试用十六进制的ASCII码,但Hive会将其视为字符串处理并未转义,好像仅支持八进制,原因不详。这个规则也适用于其他非SELECT语句,如CREATE TABLE中需要定义分隔符,那么对不可见字符做分隔符就需要用八进制的ASCII码来转义。

二、insert 新增数据

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

假设Hive中有表manbu,

hive> DESCRIBE manbu;

id int

value int

hive> SELECT * FROM manbu;

3 4

1 2

2 3

现增加一条记录:

hive> INSERT OVERWRITE TABLE manbu

SELECT id, value FROM (

SELECT id, value FROM manbu

UNION ALL

SELECT 4 AS id, 5 AS value FROM manbu limit 1

) u;

结果是:

hive>SELECT * FROM p1;

3 4

4 5

2 3

1 2

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

三、初始值

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

四、orderby  sort by  distribute by的优化

Hive的排序关键字是SORT BY,它有意区别于传统数据库的ORDER BY也是为了强调两者的区别–SORT BY只能在单机范围内排序。

例如:

 set mapred.reduce.tasks=2;(设置reduce的数量为2 )

原值:

1.selectcookie_id,page_id,id from c02_clickstat_fatdt1

where cookie_idIN('1.193.131.218.1288611279693.0','1.193.148.164.1288609861509.2')

1.193.148.164.1288609861509.2  113181412886099008861288609901078194082403      684000005

1.193.148.164.1288609861509.2  127001128860563972141288609859828580660473      684000015

1.193.148.164.1288609861509.2   113181412886099165721288609915890452725326      684000018

1.193.131.218.1288611279693.0  01c183da6e4bc50712881288611540109914561053      684000114

1.193.131.218.1288611279693.0  01c183da6e4bc22412881288611414343558274174      684000118

1.193.131.218.1288611279693.0  01c183da6e4bc50712881288611511781996667988      684000121

1.193.131.218.1288611279693.0  01c183da6e4bc22412881288611523640691739999      684000126

1.193.131.218.1288611279693.0  01c183da6e4bc50712881288611540109914561053      684000128 

2. selectcookie_id,page_id,id from c02_clickstat_fatdt1 where

cookie_idIN('1.193.131.218.1288611279693.0','1.193.148.164.1288609861509.2')

SORT BYCOOKIE_ID,PAGE_ID;

SORT排序后的值

1.193.131.218.1288611279693.0           684000118       01c183da6e4bc22412881288611414343558274174      684000118

1.193.131.218.1288611279693.0           684000114      01c183da6e4bc50712881288611540109914561053      684000114

1.193.131.218.1288611279693.0           684000128      01c183da6e4bc50712881288611540109914561053      684000128

1.193.148.164.1288609861509.2           684000005      113181412886099008861288609901078194082403      684000005

1.193.148.164.1288609861509.2           684000018      113181412886099165721288609915890452725326      684000018

1.193.131.218.1288611279693.0           684000126      01c183da6e4bc22412881288611523640691739999      684000126

1.193.131.218.1288611279693.0           684000121      01c183da6e4bc50712881288611511781996667988      684000121

1.193.148.164.1288609861509.2           684000015       127001128860563972141288609859828580660473      684000015

selectcookie_id,page_id,id from c02_clickstat_fatdt1

where cookie_idIN('1.193.131.218.1288611279693.0','1.193.148.164.1288609861509.2')

ORDER BYPAGE_ID,COOKIE_ID;

1.193.131.218.1288611279693.0           684000118      01c183da6e4bc22412881288611414343558274174      684000118

1.193.131.218.1288611279693.0           684000126      01c183da6e4bc22412881288611523640691739999      684000126

1.193.131.218.1288611279693.0           684000121       01c183da6e4bc50712881288611511781996667988      684000121

1.193.131.218.1288611279693.0           684000114      01c183da6e4bc50712881288611540109914561053      684000114

1.193.131.218.1288611279693.0           684000128       01c183da6e4bc50712881288611540109914561053      684000128

1.193.148.164.1288609861509.2           684000005      113181412886099008861288609901078194082403      684000005

1.193.148.164.1288609861509.2           684000018      113181412886099165721288609915890452725326      684000018

1.193.148.164.1288609861509.2           684000015      127001128860563972141288609859828580660473      684000015

可以看到SORT和ORDER排序出来的值不一样。一开始我指定了2个reduce进行数据分发(各自进行排序)。结果不一样的主要原因是上述查询没有reduce key,hive会生成随机数作为reduce key。这样的话输入记录也随机地被分发到不同reducer机器上去了。为了保证reducer之间没有重复的cookie_id记录,可以使用DISTRIBUTE BY关键字指定分发key为cookie_id。

selectcookie_id,country,id,page_id,id from c02_clickstat_fatdt1 where cookie_idIN('1.193.131.218.1288611279693.0','1.193.148.164.1288609861509.2')  distribute by cookie_id SORT BY COOKIE_ID,page_id;

1.193.131.218.1288611279693.0           684000118      01c183da6e4bc22412881288611414343558274174      684000118

1.193.131.218.1288611279693.0           684000126      01c183da6e4bc22412881288611523640691739999      684000126

1.193.131.218.1288611279693.0           684000121      01c183da6e4bc50712881288611511781996667988      684000121

1.193.131.218.1288611279693.0           684000114      01c183da6e4bc50712881288611540109914561053      684000114

1.193.131.218.1288611279693.0           684000128      01c183da6e4bc50712881288611540109914561053      684000128

1.193.148.164.1288609861509.2           684000005      113181412886099008861288609901078194082403      684000005

1.193.148.164.1288609861509.2           684000018       113181412886099165721288609915890452725326      684000018

1.193.148.164.1288609861509.2           684000015      127001128860563972141288609859828580660473      684000015

例二:

CREATETABLE if not exists t_order(

id int,-- 编号

sale_idint, -- SID

customer_idint, -- CID

product_id int, -- PID

amountint -- 数量

)PARTITIONED BY (ds STRING);

在表中查询所有记录,并按照PID和数量排序:

setmapred.reduce.tasks=2;

Selectsale_id, amount from t_order

Sort bysale_id, amount;

这一查询可能得到非期望的排序。指定的2个reducer分发到的数据可能是(各自排序):

Reducer1:

Sale_id |amount

0 | 100

1 | 30

1 | 50

2 | 20

Reducer2:

Sale_id |amount

0 |110

0 | 120

3 | 50

4 | 20

使用DISTRIBUTE BY关键字指定分发key为sale_id。改造后的HQL如下:

setmapred.reduce.tasks=2;

Selectsale_id, amount from t_order

Distributeby sale_id

Sort bysale_id, amount;

这样能够保证查询的销售记录集合中,销售ID对应的数量是正确排序的,但是销售ID不能正确排序,原因是hive使用hadoop默认的HashPartitioner分发数据。

这就涉及到一个全排序的问题。解决的办法无外乎两种:

1.) 不分发数据,使用单个reducer:

setmapred.reduce.tasks=1;

这一方法的缺陷在于reduce端成为了性能瓶颈,而且在数据量大的情况下一般都无法得到结果。但是实践中这仍然是最常用的方法,原因是通常排序的查询是为了得到排名靠前的若干结果,因此可以用limit子句大大减少数据量。使用limit n后,传输到reduce端(单机)的数据记录数就减少到n* (map个数)。

2.) 修改Partitioner,这种方法可以做到全排序。这里可以使用Hadoop自带的TotalOrderPartitioner(来自于Yahoo!的TeraSort项目),这是一个为了支持跨reducer分发有序数据开发的Partitioner,它需要一个SequenceFile格式的文件指定分发的数据区间。如果我们已经生成了这一文件(存储在/tmp/range_key_list,分成100个reducer),可以将上述查询改写为

setmapred.reduce.tasks=100;

sethive.mapred.partitioner=org.apache.hadoop.mapred.lib.TotalOrderPartitioner;

settotal.order.partitioner.path=/tmp/ range_key_list;

Selectsale_id, amount from t_order

Clusterby sale_id

Sort byamount;

有很多种方法生成这一区间文件(例如hadoop自带的o.a.h.mapreduce.lib.partition.InputSampler工具)。这里介绍用Hive生成的方法,例如有一个按id有序的t_sale表:

CREATETABLE if not exists t_sale (

id int,

namestring,

locstring

);

则生成按sale_id分发的区间文件的方法是:

createexternal table range_keys(sale_id int)

rowformat serde

'org.apache.hadoop.hive.serde2.binarysortable.BinarySortableSerDe'

stored as

inputformat

'org.apache.hadoop.mapred.TextInputFormat'

outputformat

'org.apache.hadoop.hive.ql.io.HiveNullValueSequenceFileOutputFormat'

location'/tmp/range_key_list'; 

insertoverwrite table range_keys

selectdistinct sale_id

fromsource t_sale sampletable(BUCKET 100 OUT OF 100 ON rand()) s

sort bysale_id;

生成的文件(/tmp/range_key_list目录下)可以让TotalOrderPartitioner按sale_id有序地分发reduce处理的数据。

区间文件需要考虑的主要问题是数据分发的均衡性,这有赖于对数据深入的理解。

作者:manburen01 发表于2014-8-28 13:06:38 原文链接
阅读:68 评论:0 查看评论

相关 [hive orderby sort] 推荐:

hive 的分隔符、orderby sort by distribute by的优化

- - CSDN博客云计算推荐文章
分号是SQL语句结束标记,在HiveQL中也是,但是在HiveQL中,对分号的识别没有那么智慧,例如:. 可以推断,Hive解析语句的时候,只要遇到分号就认为语句结束,而无论是否用引号包含起来. 解决的办法是,使用分号的八进制的ASCII码进行转义,那么上述语句应写成:. 为什么是八进制ASCII码.

排序算法 Sleep Sort

- Jeff - 酷壳 - CoolShell.cn
排序算法好像是程序员学习编程最多的算法,也可能是算法研究者们最喜欢研究的算法了. 排序有很多很多的算法,比如,冒泡,插入,选择,堆,快速,归并等等(你可以看看本站以前的那些文章:可视化的排序,排序算法比较,显示排序过程的python)这里向大家介绍一个“巨NB”的排序算法——Sleep Sort. 闲言少说,请看下面的代码(用Shell脚本写的).

[转]MapReduce:详解Shuffle(copy,sort,merge)过程

- - 芒果先生Mango的专栏
Shuffle过程是MapReduce的核心,也被称为奇迹发生的地方. 要想理解MapReduce, Shuffle是必须要了解的. 我看过很多相关的资料,但每次看完都云里雾里的绕着,很难理清大致的逻辑,反而越搅越混. 前段时间在做MapReduce job 性能调优的工作,需要深入代码研究MapReduce的运行机制,这才对Shuffle探了个究竟.

hive调优

- - 互联网 - ITeye博客
一、    控制hive任务中的map数: . 1.    通常情况下,作业会通过input的目录产生一个或者多个map任务. 主要的决定因素有: input的文件总个数,input的文件大小,集群设置的文件块大小(目前为128M, 可在hive中通过set dfs.block.size;命令查看到,该参数不能自定义修改);.

hive 优化 tips

- - CSDN博客推荐文章
一、     Hive join优化. 也可以显示声明进行map join:特别适用于小表join大表的时候,SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a join b on a.key = b.key. 2.     注意带表分区的join, 如:.

Hive中的join

- - CSDN博客云计算推荐文章
select a.* from a join b on a.id = b.id select a.* from a join b on (a.id = b.id and a.department = b.department). 在使用join写查询的时候有一个原则:应该将条目少的表或者子查询放在join操作符的左边.

hive优化(2)

- - 开源软件 - ITeye博客
Hive是将符合SQL语法的字符串解析生成可以在Hadoop上执行的MapReduce的工具. 使用Hive尽量按照分布式计算的一些特点来设计sql,和传统关系型数据库有区别,. 所以需要去掉原有关系型数据库下开发的一些固有思维. 1:尽量尽早地过滤数据,减少每个阶段的数据量,对于分区表要加分区,同时只选择需要使用到的字段.

hive优化

- - 开源软件 - ITeye博客
hive.optimize.cp=true:列裁剪. hive.optimize.prunner:分区裁剪. hive.limit.optimize.enable=true:优化LIMIT n语句. hive.limit.optimize.limit.file=10:最大文件数.   1.job的输入数据大小必须小于参数:hive.exec.mode.local.auto.inputbytes.max(默认128MB).

Hive优化

- - 互联网 - ITeye博客
     使用Hive有一段时间了,目前发现需要进行优化的较多出现在出现join、distinct的情况下,而且一般都是reduce过程较慢.      Reduce过程比较慢的现象又可以分为两类:. 情形一:map已经达到100%,而reduce阶段一直是99%,属于数据倾斜. 情形二:使用了count(distinct)或者group by的操作,现象是reduce有进度但是进度缓慢,31%-32%-34%...一个附带的提示是使用reduce个数很可能是1.

hive bucket 桶

- - CSDN博客推荐文章
对于每一个表(table)或者分区,Hive可以进一步组织成桶. Hive也是针对某一列进行桶的组织. Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中. 采用桶能够带来一些好处,比如JOIN操作. 对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作. 那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量.