Hive получать лучшие n записей в группе по запросу - PullRequest
22 голосов
/ 22 февраля 2012

У меня есть следующая таблица в улье

идентификатор пользователя, имя пользователя, адрес пользователя, клики, показы, идентификатор страницы, имя страницы

Мне нужно узнать верх5 пользователей [идентификатор пользователя, имя пользователя, адрес пользователя] по кликам для каждой страницы [идентификатор страницы, имя страницы]

Я понимаю, что нам нужно сначала сгруппировать по [идентификатор страницы, страница-name], и ​​в каждой группе я хочу упорядочить [щелчки, показы] desc, а затем выдавать только 5 лучших пользователей [идентификатор пользователя, имя пользователя, адрес пользователя] для каждой страницы, но мне трудно построить запрос.

Как мы можем сделать это, используя HIve UDF?

Ответы [ 5 ]

15 голосов
/ 04 апреля 2013

Исправленный ответ, исправляющий ошибку, упомянутую @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

Обратите внимание, что UDAF rank () применяется к столбцу идентификатора страницы, новое значение которого используется для сброса или увеличения счетчика рангов (например, счетчик сброса для каждого раздела идентификатора страницы)

11 голосов
/ 03 апреля 2014

Начиная с Hive 0.11, вы можете делать это, используя встроенную в Hive функцию rank () и используя более простую семантику, используя Встроенные функции Hive для аналитики и управления окнами .К сожалению, я не смог найти столько примеров с ними, сколько мне хотелось бы, но они действительно очень полезны.Используя их, можно использовать и 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 и только один подзапрос!Кроме того, вся логика ранга локализована.

Вы можете найти еще несколько (хотя мне не нравится) примеров этих функций в этом Jira и на блоге этого парня.

9 голосов
/ 01 марта 2012

Вы можете сделать это с помощью 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
2 голосов
/ 14 сентября 2015

Вы можете использовать each_top_k функцию из hivemall для эффективного вычисления top-k в Apache Hive.

select
  page-id, 
  user-id,
  clicks
from (
  select
    each_top_k(5, page-id, clicks, page-id, user-id)
      as (rank, clicks, page-id, user-id)
  from (
    select
      page-id, user-id, clicks
    from
      mytable
    DISTRIBUTE BY page-id SORT BY page-id
  ) t1
) t2
order by page-id ASC, clicks DESC

each_top_kUDTF очень быстрый по сравнению с другими методами, выполняющими запросы top-k (например, distributed by/rank) в Hive, потому что он не содержит всего ранжирования для промежуточного результата.

1 голос
/ 18 ноября 2016

Допустим, ваши данные выглядят следующим образом:

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

Ниже Query даст вам:

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

Итак, для страницы 1 вы получаете 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
...