【问题标题】:Hive getting top n records in group by queryHive 通过查询获取组中的前 n 条记录
【发布时间】:2012-03-12 12:56:08
【问题描述】:

我在 hive 中有下表

用户 ID、用户名、用户地址、点击次数、展示次数、页面 ID、页面名称

我需要通过点击每个页面 [page-id,page-name] 找出前 5 个用户 [user-id,user-name,user-address]

我知道我们需要首先按 [page-id,page-name] 分组,在每个组中我想按 [clicks,impressions] desc 排序,然后只发出前 5 个用户 [user-id, user-name , user-address],但我发现很难构造查询。

我们如何使用 HIve UDF 做到这一点?

【问题讨论】:

    标签: user-defined-functions hive rank


    【解决方案1】:

    修改答案,修复@Himanshu Gahlot 提到的错误

    SELECT page-id, user-id, clicks
    FROM (
        SELECT page-id, user-id, rank(page-id) as rank, clicks FROM (
            SELECT page-id, user-id, clicks FROM mytable
            DISTRIBUTE BY page-id
            SORT BY page-id, clicks desc
    ) a ) b
    WHERE rank < 5
    ORDER BY page-id, rank
    

    请注意,rank() UDAF 应用于 page-id 列,其新值用于重置或增加排名计数器(例如,为每个 page-id 分区重置计数器)

    【讨论】:

    • 酷.. 它保存了我的搜索 :)
    • 最后一个按等级排序不起作用,因为没有在最外层选择等级。
    【解决方案2】:

    从 Hive 0.11 开始,您可以使用 Hive 的内置 rank() 函数并使用 Hive's built-in Analytics and Windowing functions 使用更简单的语义来执行此操作。可悲的是,我找不到我想要的那么多例子,但它们真的非常有用。使用这些,rank() 和 WhereWithRankCond 都是内置的,所以你可以这样做:

    SELECT page-id, user-id, clicks
    FROM (
        SELECT page-id, user-id, rank() 
               over (PARTITION BY page-id ORDER BY clicks DESC) as rank, clicks 
        FROM my table
    ) ranked_mytable
    WHERE ranked_mytable.rank < 5
    ORDER BY page-id, rank
    

    不需要UDF,只有一个子查询!此外,所有排名逻辑都是本地化的。

    您可以在in this Jirathis guy's blog 上找到更多(尽管我不喜欢)这些函数的示例。

    【讨论】:

      【解决方案3】:

      您可以使用此处描述的 rank() UDF 来做到这一点:http://ragrawal.wordpress.com/2011/11/18/extract-top-n-records-in-each-group-in-hadoophive/

      SELECT page-id, user-id, clicks
      FROM (
          SELECT page-id, user-id, rank(user-id) as rank, clicks
          FROM mytable
          DISTRIBUTE BY page-id, user-id
          SORT BY page-id, user-id, clicks desc
      ) a 
      WHERE rank < 5
      ORDER BY page-id, rank
      

      【讨论】:

      • 嗨马克西姆,很抱歉这样打扰你。我也有类似的问题。我已经在 SO 上发帖,但由于我正在使用 Hive 并且 HiveQL 对我来说是新的,所以没有得到任何好的回应。 http://stackoverflow.com/questions/11405446/find-10-latest-record-for-each-buyer-id-for-yesterdays-date。对我有很大的帮助。
      • 我只是花了几个小时来完成这项工作,但没有成功。错误是您首先排名,然后执行 DISTRIBUTE BY 和 SORT BY。相反,您应该在外部查询中应用排名,并在内部查询中使用 DISTRIBUTE BY 和 SORT BY。例如 SELECT page-id, user-id, clicks FROM (SELECT page-id, user-id, rank(user-id) as rank, clicks FROM (SELECT * FROM mytable DISTRIBUTE BY page-id, user-id SORT BY page-id, user-id, clicks DESC)a )b WHERE rank
      • 确认@HimanshuGahlot 是正确的。答案有一个BUG!您必须在外部查询中使用 rank() 并在内部查询中使用 DISTRIBUTE/SORT BY!
      【解决方案4】:

      您可以使用 each_top_k functionhivemall 在 Apache Hive 上进行高效的 top-k 计算。

      选择 页面 ID, 用户身份, 点击次数 从 ( 选择 each_top_k(5, page-id, clicks, page-id, user-id) 作为(排名、点击次数、页面 ID、用户 ID) 从 ( 选择 页面 ID、用户 ID、点击次数 从 我的表 按页面 ID 分发 按页面 ID 排序 ) t1 ) t2 按 page-id ASC 排序,点击 DESC

      与在 Hive 中运行 top-k 查询(例如,distributed by/rank)的其他方法相比,each_top_k UDTF 非常快,因为它不包含中间结果的整个排名。

      【讨论】:

        【解决方案5】:

        假设您的数据如下所示:

        page-id   user-id   clicks
        page1     user1     10
        page1     user2     10
        page1     user3     9
        page1     user4     8
        page1     user5     7
        page1     user6     7
        page1     user7     6
        page1     user8     5
        page2     user1     20
        page2     user2     19
        page2     user3     18
        

        下面的查询会给你:

        SELECT page-id, user-id, clicks, rank
        FROM (
            SELECT page-id, user-id, rank() 
                   over (PARTITION BY page-id ORDER BY clicks DESC) as rank, clicks 
            FROM your_table
        ) ranked_table
        WHERE ranked_table.rank <= 5
        

        结果:

        page-id   user-id   clicks  rank
        page1     user1     10      1
        page1     user2     10      1 
        page1     user3     9       3 
        page1     user4     8       4
        page1     user5     7       5 
        page1     user6     7       5 
        page2     user1     20      1
        page2     user2     19      2  
        page2     user3     18      3
        

        因此,对于 page1,您将获得 6 个用户,因为具有相同点击次数的用户排名相同。

        但是,如果您正在寻找正好 5 个用户,并随机选择以防多个用户落入同一排名。您可以使用以下查询

        SELECT page-id, user-id, clicks, rank
        FROM (
            SELECT page-id, user-id, row_number() 
                   over (PARTITION BY page-id ORDER BY clicks DESC) as rank, clicks 
            FROM your_table
        ) ranked_table
        WHERE ranked_table.rank <= 5
        

        结果:

        page-id   user-id   clicks  rank
        page1     user1     10      1
        page1     user2     10      2 
        page1     user3     9       3 
        page1     user4     8       4
        page1     user5     7       5 
        page2     user1     20      1
        page2     user2     19      2  
        page2     user3     18      3
        

        【讨论】:

          【解决方案6】:

          select * from (select user_id,user-name,user-address,page,click,row_num() over (partition by page order by clicks desc) a where a.row_num

          选择列可能会有变化,但逻辑是正确的。

          【讨论】:

          猜你喜欢
          • 2016-07-15
          • 2021-03-27
          • 2021-06-25
          • 2013-12-31
          • 2021-09-01
          • 1970-01-01
          相关资源
          最近更新 更多