Hive ROW_NUMBER TopN 性能优化

Posted @SmartSi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hive ROW_NUMBER TopN 性能优化相关的知识,希望对你有一定的参考价值。

1. 背景

假设我们要查看每个频道下第一次出现的用户,常用解决方案会使用 row_number

SELECT cid, cname, uid, server_tm
FROM (
    SELECT
        cid, cname, uid, server_tm,
        ROW_NUMBER() OVER(PARTITION BY cid ORDER BY server_tm) AS rk
    FROM behavior
    WHERE dt = '20230216'
) AS a
WHERE rk = 1;

row_number 会按照频道ID cid 进行分组,并在每个分组内根据时间进行排序。如果某一个或者某几个频道有大量的用户访问,那么就会极易发生数据倾斜。那么怎么才能避免数据倾斜快速实现 TopN 呢?

2. 优化

当发生数据倾斜时,可以通用以下几种方式解决:

序号方案说明
方案一SQL写法的两阶段聚合增加随机列或拼接随机数,将其作为分区(Partition)中一参数
方案二UDAF写法的两阶段聚合最小堆的队列优先的通过UDAF的方式进行调优

2.1 SQL 写法的两阶段聚合

为使 Map 阶段中 Partition 各分组数据尽可能均匀,增加随机列,将其作为 Partition 中一参数。可以理解为将频道分为 N 个分组,先在 N 个分组中取 TopN,然后在全局取 TopN:

SELECT cid, cname, uid, server_tm
FROM (
    -- 每个频道的 Top1
    SELECT
        cid, cname, uid, server_tm,
        ROW_NUMBER() OVER(PARTITION BY cid ORDER BY server_tm) AS rk
    FROM (
        -- 每个频道在不同分组中的 Top1
        SELECT
            cid, cname, uid, server_tm,
            ROW_NUMBER() OVER(PARTITION BY cid, random ORDER BY server_tm) AS rk
        FROM (
            -- 添加随机数 分组
            SELECT
                cid, cname, uid, server_tm,
                CEIL(110 * RAND()) % 15 AS random
            FROM behavior
            WHERE dt = '20230216'
        ) AS a
    ) AS b
    WHERE rk = 1
) AS c
WHERE rk = 1;

2.2 UDAF 写法的两阶段聚合

SQL 的方式会有较多代码,且可能不利于维护,可以利用最小堆的队列优先的通过 UDAF 的方式进行调优,即在 iterate 阶段仅取 TopN,merge 阶段则均仅对 N 个元素融合,过程如下:

  • iterate:将前K个元素进行push,K之后的元素通过不断与最小顶比较交换堆中元素。
  • merge:将两堆merge后,原地返回前K个元素。
  • terminate:数组形式返回堆。
  • SQL中将数组拆为各行。

以上是关于Hive ROW_NUMBER TopN 性能优化的主要内容,如果未能解决你的问题,请参考以下文章

hive 分组排序,topN

Hive分组取TOPN数据

hive 中row_number(),rank,dense_ran()的用法

hive分组取随机数

SQL Server-聚焦ROW_NUMBER VS TOP N性能

text Hive topN,分组topN问题解决方案