如何在Hive / SQL中的where / having子句中使用min()(以避免子查询)

时间:2012-10-31 20:10:15

标签: sql hive hiveql

我有一大堆事件。每个用户我想在最早的B类事件之前计算A类事件的发生。

我正在寻找一个优雅的查询。使用Hive所以我不能做子查询

Timestamp Type User 
...        A    X
...        A    X
...        B    X
...        A    X
...        A    X

...        A    Y
...        A    Y
...        A    Y
...        B    Y
...        A    Y

通缉结果:

User Count_Type_A 
X    2
Y    3

我无法通过以下方式获得“截止”时间戳:

Select User, min(Timestamp) 
Where Type=B 
Group BY User;

但是,我如何在下一个查询中使用该信息,我想做的事情如下:

SELECT User, count(Timestamp) 
WHERE Type=A AND Timestamp<min(User.Timestamp_Type_B) 
GROUP BY User;

到目前为止,我唯一的想法是首先确定截止时间戳,然后对所有类型A事件进行连接,然后从结果表中选择,但这感觉不对,看起来很难看。

我也在考虑这是Hive问题/分析的错误类型的可能性,我应该考虑手写的map-reduce或pig。

请指出正确的方向帮助我。

2 个答案:

答案 0 :(得分:1)

第一次更新:

针对Cilvic对此答案的第一次评论,我根据https://issues.apache.org/jira/browse/HIVE-556上的评论中建议的解决方法将我的查询调整为以下内容:

SELECT [User], COUNT([Timestamp]) AS [Before_First_B_Count]
FROM [Dataset] main
CROSS JOIN (SELECT [User], min([Timestamp]) [First_B_TS] FROM [Dataset]
    WHERE [Type] = 'B'
    GROUP BY [User]) sub 
WHERE main.[Type] = 'A'
AND (sub.[User] = main.[User]) 
AND (main.[Timestamp] < sub.[First_B_TS])
GROUP BY main.[User]

<强>原始

试一试:

SELECT [User], COUNT([Timestamp]) AS [Before_First_B_Count]
FROM [Dataset] main
JOIN (SELECT [User], min([Timestamp]) [First_B_TS] FROM [Dataset]
    WHERE [Type] = 'B'
    GROUP BY [User]) sub 
        ON (sub.[User] = main.[User]) AND (main.[Timestamp] < sub.[First_B_TS])
WHERE main.[Type] = 'A'
GROUP BY main.[User]

我尽力遵循hive语法。如果您有任何疑问,请告诉我。我想知道为什么你希望/需要避免子查询。

答案 1 :(得分:1)

一般来说,我是+1 coge.soft的解决方案。这里再次供您参考:

SELECT [User], COUNT([Timestamp]) AS [Before_First_B_Count]
FROM [Dataset] main
JOIN (SELECT [User], min([Timestamp]) [First_B_TS] FROM [Dataset]
    WHERE [Type] = 'B'
    GROUP BY [User]) sub 
        ON (sub.[User] = main.[User]) AND (main.[Timestamp] < sub.[First_B_TS])
WHERE main.[Type] = 'A'
GROUP BY main.[User]

然而,有几点需要注意:

  1. 没有B事件时会发生什么?假设您希望在这种情况下计算每个用户的所有A事件,则解决方案中指定的内部联接将不起作用,因为子表中没有该用户的条目。您需要更改为左外连接。

  2. 该解决方案还对数据进行了2次传递 - 一次填充子表,另一次用于将子表与主表连接。根据您的性能和效率概念,您可以通过单次传递数据来实现此目的。您可以使用Hive的distribute by功能按用户分发数据,并编写一个自定义缩减器,使用Hive's transform functionality以您喜欢的语言进行计数计算。