Hive中collect_list全局保持顺序

我用部署的是standalone模式,local单节点计算的时候,结果没问题,当集群计算的时候因为是分布式的,因此结果是乱序的。解决方法如下:

有以下Hive表的定义:

create table topic_recommend_score (
  category_id int,
  topic_id bigint,
  score double,
  rank int
);

这张表是我们业务里话题推荐分值表的简化版本。category_id代表分类ID,topic_id是话题ID,score是评分值。rank代表每个分类下话题分值的排名,用开窗函数计算出来的:
row_number() over(partition by t.category_id order by t.score desc)

在对外提供推荐结果时,我们会将每个小组下排名前1000的话题ID取出,拼成一个逗号分隔的字符串,处理之后送入HBase供调用方查询。拼合的SQL语句如下:

select category_id,
       concat_ws(',',collect_list(cast(topic_id as string)))
from topic_recommend_score
where rank >= 1 and rank <= 1000
group by category_id;

看起来没什么问题?但实际上是错误的。输出结果中总会有一些category_id对应的列表顺序异常,比如本来排名正数与排名倒数的两批ID调换了位置,即rank变成了n-3, n-2, n-1, n, 5, 6, 7, ..., n-4, 1, 2, 3, 4

产生这个问题的根本原因自然在MapReduce,如果启动了多于一个mapper/reducer来处理数据,select出来的数据顺序就几乎肯定与原始顺序不同了。考虑把mapper数固定成1比较麻烦(见我之前写的那篇Hive调优文章),也不现实,所以要迂回地解决问题:把rank加进来再进行一次排序,拼接完之后把rank去掉。如下:

select category_id,
       regexp_replace(
         concat_ws(',',
           sort_array(
             collect_list(
               concat_ws(':',lpad(cast(rank as string),5,'0'),cast(topic_id as string))
             )
           )
         ),
       '\\d+\:','')
from topic_recommend_score
where rank >= 1 and rank <= 1000
group by category_id;

这里将rank放在了topic_id之前,用冒号分隔,然后用sort_array函数对collect_list之后的结果进行排序(只支持升序)。特别注意,rank必须要在高位补足够的0对齐,因为排序的是字符串而不是数字,如果不补0的话,按字典序排序就会变成1, 10, 11, 12, 13, 2, 3, 4...,又不对了。
将排序的结果拼起来之后,用regexp_replace函数替换掉冒号及其前面的数字,大功告成

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hivecollect_list是一个聚合函数,用于将同一分组内的值收集到一个列表。它将每个分组内的数值或表达式的结果收集到一个数组,并返回一个包含这些值的数组作为结果。 这个函数可以在SELECT语句使用,通过GROUP BY子句将数据按照指定的列进行分组,然后使用collect_list函数来收集每个分组内的数值并生成一个列表。例如,在给定的表sales,我们可以按照name列进行分组,并使用collect_list函数将每个分组内的sale列的值收集到一个列表。 此外,collect_list函数还可以与滑窗函数over一起使用,用于在不分区的窗口将所有的数据合并成一个列表。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [hivecollect_list函数](https://blog.csdn.net/Matthew93/article/details/130705632)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [图解HIVE开窗函数(Windowing functions小白进)](https://blog.csdn.net/Yellow_python/article/details/116151366)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值