加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

hive row_number() 函数详解

(2012-06-02 19:03:00)
标签:

杂谈

分类: 学习生涯

由于row_number()每行都需要返回一个行号值,所以一般的思路是通过实现最简单udf,继承org.apache.hadoop.hive.ql.exec.UDF即可。

昨天读了下row_number()的实现函数,和大家共享下。代码并不长,所以直接贴出

packagecom.alibaba.hive.udf.UDFRow_number;

importorg.apache.hadoop.hive.ql.exec.UDF;

public classRow_number extends UDF 

{

        private static int MAX_VALUE = 50;

private static String comparedColumn[] = newString[MAX_VALUE]; 

private static int rowNum = 1;

        public int evaluate (Object ...args)

        {

                

                String columnValue[] = newString[args.length];

                for(inti=0;i<args.length;i++)

                        columnValue[i] =args[i].toString();

                if (rowNum == 1)

                {

                        for(inti=0;i<columnValue.length;i++)

                               comparedColumn[i] = columnValue[i];

                }

                for(inti=0;i<columnValue.length;i++)

                {

                        if (!comparedColumn[i].equals(columnValue[i]) )

                        {

                                for (intj=0;j<columnValue.length;j++)

                                {

                                       comparedColumn[j] = columnValue[j];

                                }

                                rowNum = 1;

                                returnrowNum++;

                        }

                }

                returnrowNum++;

        }

}

通过static静态变量rowNum来控制行号的生成,的确是个好主意,那么如果想用这个函数来实现类似序列号生成器似乎也是一个好主意。

比如这么写

select ROW_NUMBER(1) rn, keyword from 

idl_ae_kw_search_fdt0 wherehp_stat_date='2012-05-29'  

limit 10;

我心中想,列rn的值永远是1,那么这个计数器永远++,rn肯定返回相应的序号。

最初的结果似乎验证了我的想法,

结果如下:

      !2' to14"  peacock feathers

      !2' to14" blue peacock feathers

      !2012 newmen's leisure trousers/men's casual pant

      !3pieces/lotscolourful wine bottle umbrella

     !efe-504rbsp-1av

      "

      " 3inch" 800 480

      " 3inch" 800px

      " 3inch" tft

10      " 3inch" tft 640x480

Perfect!

但是我这么写,结果就不对了,

create table xxxx asselect row_number(1) rn,keyword from (select keyword from 

idl_ae_kw_search_fdt0a where hp_stat_date='2012-05-29') a;

-- 306601Rows loaded tohdfs://hdpnn:9000/group/alibaba-dw-icbu/tmp/hive-dwapp/hive_2012-06-02_16-55-34_552_3638084487215847155/-ext-10000

有306601条数据,按我的想法,最大的rn应该是306601才是对的,

select max(rn) from xxxx;

结果才153362,震惊啊!这究竟是怎么一回事,

我再写了这么一条sql,

select * from xxxx awhere a.rn=1;

结果如下:

      !2' to14"  peacock feathers

                      john cena cap

计数器生成了两个1,这究竟是怎么一回事??明明列值都是相等的,rownum参数怎么可能变强制回归1呢?

我发现到这么一个事情,hive告诉我,任务被拆成了两个map,一个reduce执行,那么合理的解释只能是这样,在以上语句里,row_number() 函数在map端直接执行了。因为有两个map, 所以被扔到了两台机器中去执行,无论你变量是否是static,人家也根本不理你,因为两个map根本没有共享rownum变量。

我们在来验证是否的确如此,我强制将map个数设置为4个(set mapred.map.tasks=4;),再跑下上面的语句,结果如下:

select max(rn) from xxxx;

82988

select * from xxxx awhere a.rn=1;

1       rs232 lcd

      !2' to14"  peacock feathers

      definitionmascara

                      john cena cap

以上的结果验证了row_number() 函数在map端直接执行了的想法,有什么办法让它在reduce端执行呢?

最初的想法是:可以直接设置map个数为1吗?

如果直接在代码里显性设置set mapred.map.tasks=1; 可行吗?

答案:不一定行。因为如果原表本身的文件个数是两个,那么无论你怎么设置map个数,hive还是会至少生成两个map,hive会操作多个input文件,所以hive默认会把map的任务数设置成输入的文件数目,即使你通过set设置了数目,也不起作用。

答案只有一个:设置reduce格式为1,在reduce处跑这个udf

1.       createtable smxxx as select row_number(1) rownum, keyword from (select 1 myrow,keyword from idl_ae_kw_search_fdt0 a where hp_stat_date='2012-05-29' distributeby myrow) a;

Yes

 

2.       createtable smxxx as select row_number (1) rownum, keyword from (select 1 myrow,keyword from idl_ae_kw_search_fdt0 a where hp_stat_date='2012-05-29' order bymyrow) a;

Yes

上面两句都可以获得不重复的rownum, 第一句用了distribute by myrow,由于myrow都是1,所以全部被塞到了一个reduce去执行,即使你设置了两个reduce,答案还是一样。第二句用了order by,order by是全局排序,所以自然你怎么设置reduce个数都是没有用的,结果还是正确的。

那么下面这条语句肯定行不行呢?

create table smxxx as select row_number(1)rownum,a.keyword from (select keyword from 

idl_ae_kw_search_fdt0 a wherehp_stat_date='2012-05-29') a;

回答是:NO

为啥呢?你能告诉我吗?


 

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有