HiveQL и ранг ()

Я не могу понять HiveQL rank (). Я нашел пару реализаций UDF ранга в WWW, например прекрасный пример Эдварда < / а>. Я могу загружать функции и получать к ним доступ, но не могу заставить их делать то, что я хочу. Вот подробный пример:

Загрузка UDF в процесс CLI:

$ javac -classpath /home/hadoop/hadoop/hadoop-core-1.0.4.jar:/home/hadoop/hive/lib/hive-exec-0.10.0.jar com/m6d/hiveudf/Rank2.java 
$ jar -cvf Rank2.jar com/m6d/hiveudf/Rank2.class
hive> ADD JAR /home/hadoop/MyDemo/Rank2.jar;
hive> CREATE TEMPORARY FUNCTION Rank2 AS 'com.m6d.hiveudf.Rank2'; 

Создайте таблицу:

create table purchases (
  SalesRepId String, 
  PurchaseOrderId INT, 
  Amount INT
) 
ROW FORMAT DELIMITED
  FIELDS TERMINATED BY ','
  LINES TERMINATED BY '\n';

Загрузить данные из этого CSV:

Jana,1,100
Nadia,2,200
Nadia,3,600
Daniel,4,80
Jana,5,120
William,6,170
Daniel,7,140

С помощью этого из интерфейса командной строки:

LOAD DATA 
  LOCAL INPATH '/home/hadoop/MyDemo/purchases.csv'
  INTO TABLE purchases;

Теперь я вижу моих лучших торговых представителей:

select SalesRepId,sum(amount) as volume
from purchases
group by SalesRepId
ORDER BY volume DESC;

Надя продала вещей на 800 долларов, Даниэль и Яна продали по 220 долларов, а Уильям продал за 170 долларов.

SalesRep    Amount
--------    ------
Nadia       800
Daniel      220
Jana        220
William     170

Теперь все, что я хочу сделать, это пронумеровать их: Надя - №1, Даниэль и Яна - №2, а Уильям - №4 (а не №3).

select SalesRepId, V.volume,rank2(V.volume)
from 
(select SalesRepId,sum(amount) as volume
from purchases
group by SalesRepId
ORDER BY volume DESC) V;

Это то, что я получаю, но НЕ то, что хочу:

SalesRep   Amount  Rank
--------   ------  ----
Nadia       800      1
Daniel      220      1
Jana        220      2
William     170      1

Это то, что Я ХОЧУ, но не могу заставить улей сделать это за меня:

SalesRep   Amount  Rank
--------   ------  ----
Nadia       800      1
Daniel      220      2
Jana        220      2
William     170      4

Можете ли вы помочь мне с правильным HiveQL для ранжирования моих торговых представителей?

Спасибо JtheRocker за его ответ. Его изменение привело к этому списку:

SalesRep   Amount  Rank
--------   ------  ----
William     170     1
Daniel      220     2
Jana        220     2
Nadia       800     3

Небольшая модификация, чтобы Надя отображалась как 4-я (не 3-я):

private row_number;
@Override
public Object evaluate(DeferredObject[] currentKey) throws HiveException {
  row_number++;
  if (!sameAsPreviousKey(currentKey)) {
    this.counter = row_number;
    copyToPreviousKey(currentKey);
  }
return new Long(this.counter);
}

person Jeff Taylor    schedule 09.08.2013    source источник
comment
Могу ли я вам помочь? Пожалуйста, ответь. Меня очень интересует этот вариант использования. Спасибо!   -  person SSaikia_JtheRocker    schedule 10.08.2013


Ответы (2)


С помощью функций окон и аналитики, представленных в Hive 0.11, вы можете использовать:

select SalesRepId, volume as amount , rank() over (order by V.volume desc) as rank from 
(select SalesRepId,sum(amount) as volume from purchases group by SalesRepId) V;
person libjack    schedule 12.08.2013
comment
Спасибо, libjack. Я расширил пример для сортировки по категории на blogs.oracle.com/taylor22/entry/ hive_0_11_may_15 - person Jeff Taylor; 13.08.2013
comment
да, очень полезно и в этой форме. Хорошая запись в вашем блоге. - person libjack; 14.08.2013

Если у вас есть функция оценки, как показано ниже, при условии, что вы используете функцию непосредственно из упомянутого руководства,

private long counter;
@Override
  public Object evaluate(DeferredObject[] currentKey) throws HiveException {
    if (!sameAsPreviousKey(currentKey)) {
      this.counter = 0;
      copyToPreviousKey(currentKey);
    }

    return new Long(++this.counter);
  }

попробуйте изменить его на следующее, чтобы счетчик не сбрасывался при обнаружении нового тома; вместо этого вы не увеличиваете, если найдете тот же том, а увеличиваете только при обнаружении нового тома.

private long counter;
@Override
  public Object evaluate(DeferredObject[] currentKey) throws HiveException {
    //when not same as previous key you rather increment
    if (!sameAsPreviousKey(currentKey)) {
      this.counter ++;
      copyToPreviousKey(currentKey);
    }
    //else you keep the counter as it is
    return new Long(++this.counter);
 }

Подскажите, поможет ли это.

person SSaikia_JtheRocker    schedule 10.08.2013
comment
Спасибо JtheRocker за его ответ. Его изменение привело к ранжированию, аналогичному Oracle DENSE_RANK. См. Приведенную выше модификацию, чтобы эта UDF Hive оценивалась аналогично Oracle RANK. - person Jeff Taylor; 12.08.2013
comment
Я не обратил внимания на порядок «1,2,2,4», когда разместил ответ, и подумал, что вы хотите сделать это 1,2,2,3 вместо этого :). Большое спасибо за исправление и рад, что он помог вам найти нужное решение. :) - person SSaikia_JtheRocker; 12.08.2013