如何在 Hive/SQL 的 where/have 子句中使用 min()(以避免子查询)
Posted
技术标签:
【中文标题】如何在 Hive/SQL 的 where/have 子句中使用 min()(以避免子查询)【英文标题】:How to use min() in where/having clause (to avoid subquery) in Hive/SQL 【发布时间】:2012-10-31 20:10:14 【问题描述】:我有一个很大的事件表。每个用户我想在最早的 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 代替。
请帮我指出正确的方向。
【问题讨论】:
【参考方案1】:第一次更新:
针对 Cilvic 对此答案的第一条评论,我已根据 https://issues.apache.org/jira/browse/HIVE-556 的 cmets 中建议的解决方法将我的查询调整为以下内容:
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 语法。如果您有任何问题,请告诉我。我想知道您为什么希望/需要避免子查询。
【讨论】:
我发现hive(可惜不支持一般来说,我 +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]
不过,有几点需要注意:
当没有 B 事件时会发生什么?假设您想要计算每个用户的所有 A 事件,在这种情况下,解决方案中指定的内部联接将不起作用,因为子表中没有该用户的条目。为此,您需要更改为左外连接。
该解决方案还执行 2 次数据传递 - 一次填充子表,另一次将子表与主表连接。根据您对性能和效率的概念,您可以通过单次数据传递来完成此操作。您可以使用 Hive 的 distribute by 功能按用户分发数据,并编写一个自定义减速器,使用 Hive's transform functionality 以您喜欢的语言进行计数计算。
【讨论】:
@Cilvic ,上面的第二点是你为什么试图避免子查询(根据你的问题的标题)? @coge.soft 不确定我明白你的意思。我认为您提出的解决方案有效。但与此同时,它有点难以理解/阅读。我希望找到更优雅/更容易阅读的东西。我需要先更好地理解分发方式。以上是关于如何在 Hive/SQL 的 where/have 子句中使用 min()(以避免子查询)的主要内容,如果未能解决你的问题,请参考以下文章
T-SQL 过于昂贵的查询,在 where/have 条件和复合主键中选择