0

0

Hive.分组排序和TOP

php中文网

php中文网

发布时间:2016-06-07 15:55:24

|

1805人浏览过

|

来源于php中文网

原创

HQL作为类SQL的查询分析语言,到目前为止,应该也还未能达到其它流行的SQL(如Transact-SQL, MySQL)实现那样完善。而在公司的生产环境中,我想应该也不会紧贴Hive版本更新的步伐,始终部署最新版的Hive;可能会滞后一两个大版本神马的;毕竟,虽然开源工具

hql作为类sql的查询分析语言,到目前为止,应该也还未能达到其它流行的sql(如transact-sql, mysql)实现那样完善。而在公司的生产环境中,我想应该也不会紧贴hive版本更新的步伐,始终部署最新版的hive;可能会滞后一两个大版本神马的;毕竟,虽然开源工具的透明性是一大利好,但与闭源的商业工具相比,在可用性等问题上的保障性还是略弱。

使用HQL进行离线分析用户数据时,就算已经过聚合处理,但我们也可能只对那些突出的量化指标或者这些指标的增量变化感兴趣,所以对聚合数据排序(按某列降序?增序?)成为很基本的需要,这在HQL这样尚未成熟的语言中,结合orderby, limit子句可以毫无鸭梨地完成。

然而,即使我们可以把多个字段放入order by子句中,并指定各个字段的升降顺序,如:

order by fieldA desc, fieldB [asc], fieldC desc
但排序操作始终是全局的,我们有时候想要的却是分组排序,即按fieldA排序以后,然后针对fieldA的每个值所对应的fieldB和(或)fieldC排序,而不是像order by那样,针对所有fieldA的值对fieldB和(或)fieldC排序。

为了满足这个需要,Transact-SQL提供了over, partition by句和 row_number()函数,而Hive也在0.11中引入over, partition by子句和rank函数,以此提供方便的窗口分析(分组分析)功能。

那对于0.11版之前的Hive,我们可以实现分组排序吗?答案是肯定的,只是看起来没那么直接。

要实现这个需求,就需要请出distribute by, sort by这两个重要角色了,distribute by能够执行我们需要的分组功能,再结合Hive查询的MapReduce Job特性,sort by又可以在分组内进行局部排序。

当然,如果只有它们,我们只能得到排序后的一堆数据,但是无法知道每一条数据的名次,这就要自己编写UDF函数,来确定和返回名次了,这个函数貌似在网络上流传甚广:

public final class Rank extends UDF {
      private int counter;
      private String last_key ="";
 
      public int evaluate(final String key) {
             if (key == null) {
                    this.last_key= "";
                    this.counter= 0;
                    return counter;
             }
             if(!key.equalsIgnoreCase(this.last_key)) {
                    this.counter= 0;
                    this.last_key= key;
             }
             return this.counter++;
      }
}

在这里我们忽略了自定义UDF的注册的环节。。。在分组之后,应用Rank函数,这个函数始终跟踪最新的参数值,在参数值连续相同的情况下,就将字段counter作自增操作并返回这个计数值;而如果出现和上一次函数调用不同的参数值,Rank函数会重置其计数值字段和key字段(对应参数值)使我们得到一个int类型的名次值。

Hive里称这个为自定义函数,实际上每个自定义函数是一个实现了evaluate方法的类,这个叫法略不福啊。

有了distribute by, sort by和这个Rank函数,我们就能够实现分组排序了,编写HQL查询脚本之前,我们还需要明确:

1. 分组字段:distribute by的字段是哪个(些)?

2. 排序依据:sort by的字段是哪个(些)?

Pliny
Pliny

创建、分享和重新组合AI应用程序

下载

3. 函数参数:Rank函数需要String参数,我们应该给Rank函数传递什么东西作为实参?

不晓得是因为以上这3个问题确实像我们在教科书上偶尔会看到的“容易证得”,还是因为博主们只是想了这个问题,并没有实践,反正我看到的网络上讲分组排序(TOP)的博文都没有明确地提出这3个问题。而按我的实践经历来看,初次实现这种需求的童鞋,就算看了这些博文,在得到正确结果之前,应该都会经历各种困惑,下面我们从实际的场景来看看。

比如,我们需要查询得到这样的数据:每日使用应用myAPP的UV量TOP 30的设备,和这TOP 10的设备中每个设备的流量(VV)最高的10项版块内容(以内容ID来区分);

假定查询所需的Hive表为:hiveTab_useraction

思路梗概:先用一个子查询查出来每台设备的访问内容,同时,用一个子查询查出来TOP30的设备,然后两个表做内连接(join),然后在外层查询中提取所需字段列和数据列。

在这个流程里面:

1)找出TOP10的设备这个环节看起来没有涉及分组排序,但还是需要考虑上面3个问题,因为我们要得到名次,而order by貌似不能同Rank函数友好协作(也有可能是我使用的方式不科学呢),而且,在以下呈现的脚本中,我们还生成了一个常量字符串的distribute_key;

2)然后在外层循环中更需要考虑上面3个问题。

请见HQL脚本:

select
	device_rank,
	device_info,
	vv_rank,
	pageID,	
	act_vv
from
(
	select
		device_rank,
		device_info,
		(Rank(device_rank) + 1) as vv_rank,
		pageID,
		act_vv
	from
	(	
		select
			t2.device_rank,
			t2.device_info,
			t1.pageID,
			t1.act_vv
		from
		(
			select
				fieldA as device_info,
				pageID,
				count(1) as act_vv
			from hiveTab_useraction
			where `date` >= dateStart and `date` <= dateEnd
			group by fieldA, pageID
		) t1
		join
		(
			select
				(Rank(distribute_key) + 1) as device_rank,
				device_info,
				act_uv
			from
			(
				select
					distribute_key,
					device_info,
					act_uv
				from
				(
					select
						'topdevice' as distribute_key,
						device_info,
						act_uv
					from
					(
						select
							fieldA as device_info,
							count(distinct uid) as act_uv
						from hiveTab_useraction
						where `date` >= dateStart and `date` <= dateEnd
						group by fieldA
					) t
					order by act_uv desc
					limit 10
				) t
				distribute by distribute_key 
				sort by act_uv desc
			) t
		) t2 on (t1.device_info = t2.device_info)
		distribute by t2.device_rank
		sort by t2.device_rank, t1.act_vv desc
	) t
) t
where vv_rank <= 10
从脚本实测来看,上面提到的需要明确的3个问题,真的很重要。另外,Rank函数返回的名次是从0开始,所以我们需要作+1处理。

Hive向普通用户也开放了自行编写、注册和使用自定义函数的功能,这一点确实带来了很大的扩展性。

相关专题

更多
Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

37

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

37

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

16

2026.01.13

PHP缓存策略教程大全
PHP缓存策略教程大全

本专题整合了PHP缓存相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.13

jQuery 正则表达式相关教程
jQuery 正则表达式相关教程

本专题整合了jQuery正则表达式相关教程大全,阅读专题下面的文章了解更多详细内容。

3

2026.01.13

交互式图表和动态图表教程汇总
交互式图表和动态图表教程汇总

本专题整合了交互式图表和动态图表的相关内容,阅读专题下面的文章了解更多详细内容。

45

2026.01.13

nginx配置文件详细教程
nginx配置文件详细教程

本专题整合了nginx配置文件相关教程详细汇总,阅读专题下面的文章了解更多详细内容。

9

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 4.5万人学习

Git 教程
Git 教程

共21课时 | 2.7万人学习

Django 教程
Django 教程

共28课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号