【问题标题】:HiveQL and rank()HiveQL 和 rank()
【发布时间】:2013-08-09 21:42:31
【问题描述】:

我无法理解 HiveQL rank()。我在 WWW 上找到了一些 rank UDF 的实现,例如 Edward's nice example。我可以加载和访问这些功能,但我不能让它们做我想做的事。下面是一个详细的例子:

将 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

通过 CLI 执行此操作:

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;

Nadia 卖出了 800 美元的东西,Daniel 和 Jana 都卖出了 220 美元,William 卖出了 170 美元

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

现在我要做的就是给他们编号:Nadia 是第一名,Daniel 和 Jana 并列第二名,William 是第四名(不是第三名)

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

这是我想要的,但我无法让 hive 为我做这件事:

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

稍作修改,将 Nadia 显示为第 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);
}

【问题讨论】:

  • 我的回答对你有帮助吗?请回答。我对这个用例很感兴趣。谢谢!

标签: hadoop hive hiveql


【解决方案1】:

随着 Hive 0.11 中引入的Windowing and Analytics functions,您可以使用:

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;

【讨论】:

【解决方案2】:

如果您有如下评估功能,假设您直接使用您提到的指南中的功能,

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);
 }

如果这有帮助,请告诉我。

【讨论】:

  • 感谢 JtheRocker 的回复。他的更改导致排名类似于 Oracle DENSE_RANK。请参阅上面的修改以使此 Hive UDF 以类似于 Oracle RANK 的方式进行评估。
  • 当我发布答案并认为您想改为 1,2,2,3 时,我没有注意顺序 '1,2,2,4' :)。非常感谢您纠正我,并很高兴它帮助您找到了您想要的解决方案。 :)
猜你喜欢
  • 1970-01-01
  • 2018-03-06
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
  • 2021-07-06
  • 2016-05-14
  • 1970-01-01
相关资源
最近更新 更多