bigquery 中的条件连接
Posted
技术标签:
【中文标题】bigquery 中的条件连接【英文标题】:conditional join in bigquery 【发布时间】:2015-07-30 08:28:06 【问题描述】:我有两张桌子。
表 1 是一列整数。
表 2 有三列:start_integer、end_integer、data
简单的查询是将整数列与数据相连接
integer >= start_integer AND integer <= end_integer
在许多 SQL 实现中,这可以通过左条件 JOIN ... ON BETWEEN 来完成
SELECT tbl1.integer, tbl2.data FROM tbl1
LEFT JOIN tbl2 ON tbl1.integer BETWEEN tbl2.start_integer AND
tbl2.end_integer;
但 BigQuery 似乎只支持只有一个 = 条件的 JOIN ON。
这可以通过交叉连接来完成,但 BigQuery 抱怨我的表太大。 CROSS JOIN EACH 无效。
如何在 BigQuery 的 SQL 限制下完成这个连接任务?
下面是我的 BigQuery SQL:
SELECT tbl1.integer, tbl2.data
FROM bq:data.tbl1
CROSS JOIN bq:data.tbl2
WHERE tbl1.integer BETWEEN tbl2.start_integer AND tbl2.end_integer;
返回错误:
错误:4.1 - 4.132:JOIN 运算符的右侧表必须是小表。如果左侧表较小,则切换表,如果两个表都大于http://goo.gl/wXqgHs 中描述的最大值,则使用 JOIN EACH。
【问题讨论】:
你的 between 需要移动到 WHERE,并使用 CROSS JOIN。根据文档,CROSS JOIN 操作可以返回大量数据。如果不起作用,请发布交叉查询。没有 EACH 交叉。 CROSS JOIN 查询和错误发布。 数据的性质是什么?可能有解决此问题的好方法,具体取决于问题的性质。 IP 地址列表和与 IP 地址范围相关的数据。 我也有这个问题。是否可以使用 UDF 将每个 ip 映射到右表中的范围? 【参考方案1】:好消息(2016 年)! BigQuery 现在确实支持不等式连接 - 请务必取消选中“使用旧版 SQL 选项”。
查询示例:
SELECT *
FROM (
SELECT 1 x
) a JOIN (
SELECT 2 y
) b
ON a.x<b.y
使用旧版 SQL:
Error: ON clause must be AND of = comparisons of one field name from each table, ...
使用标准 SQL:
1 2
文档:https://cloud.google.com/bigquery/sql-reference/enabling-standard-sql
讨论:https://code.google.com/p/google-bigquery/issues/detail?id=448#c31
【讨论】:
哦,太好了,刚刚花了一天时间试图用 R 中的数据表解决这个问题。迫不及待地想看看。【参考方案2】:BigQuery 不支持右侧表的交叉联接。
【讨论】:
【参考方案3】:只是添加我如何解决这个问题的概述 - 有点 hacky,但我发现这是最快的方法,可以很好地扩展。
输入表如下:
"ip": "130.211.149.140",
"ip_int": "2194904460",
"ip_part1": "130",
"ip_part2": "211",
"ip_part3": "149",
"ip_part4": "140",
"num_requests": "6811"
查找表是这样的:
"de_ip_key": "DE18_92.66.156.93_92.66.156.112",
"ip_key": "92.66.156.93_92.66.156.112",
"ip_from_int": "1547869277",
"ip_to_int": "1547869296",
"ip_from": "92.66.156.93",
"ip_to": "92.66.156.112",
"naics_code": "518210",
"ip_from_part1": "92",
"ip_from_part2": "66",
"ip_from_part3": "156",
"ip_from_part4": "93",
"ip_to_part1": "92",
"ip_to_part2": "66",
"ip_to_part3": "156",
"ip_to_part4": "112"
因此,使用 ip 地址的第 1 部分和第 2 部分来加入作为减少搜索空间的一种方式(我的查找表中的 from 和 to 范围往往不会像第 1 部分和第 2 部分一样宽- 如果是这样,这种方法失败了)。
select
ip,
ip_int,
-- pick first info from de
first(ip_key) as ip_key,
first(de_ip_key) as de_ip_key,
first(naics_code) as naics_code
from
(
select
ip as ip,
ip_int as ip_int,
ip_key as ip_key,
de_ip_key as de_ip_key,
naics_code as naics_code,
from
-- join based on part 1 and 2 of ip from range
(
select
input.ip as ip,
input.ip_int as ip_int,
if(input.ip_int between de.ip_from_int and de.ip_to_int,de.ip_key,null) as ip_key,
if(input.ip_int between de.ip_from_int and de.ip_to_int,de.de_ip_key,null) as de_ip_key,
if(input.ip_int between de.ip_from_int and de.ip_to_int,de.naics_code,null) as naics_code,
from
[ip.lookup_input_tbl] input
left outer join each
[digital_element.data_naics_code] de
on
input.ip_part1=de.ip_from_part1
and
input.ip_part2=de.ip_from_part2
group by 1,2,3,4,5
),
-- join based on part 1 and 2 of ip to range
(
select
input.ip as ip,
input.ip_int as ip_int,
if(input.ip_int between de.ip_from_int and de.ip_to_int,de.ip_key,null) as ip_key,
if(input.ip_int between de.ip_from_int and de.ip_to_int,de.de_ip_key,null) as de_ip_key,
if(input.ip_int between de.ip_from_int and de.ip_to_int,de.naics_code,null) as naics_code,
from
[ip.lookup_input_tbl] input
left outer join each
[digital_element.data_naics_code] de
on
input.ip_part1=de.ip_to_part1
and
input.ip_part2=de.ip_to_part2
group by 1,2,3,4,5
),
group by 1,2,3,4,5
-- order so null records from either join go to bottom and get left behind on the first group by
order by ip_int,ip_key desc
)
group by 1,2
所以它基本上会吹出数据(通过在 ip 地址的第 1 部分和第 2 部分以及 ip_from 和 ip_to 地址上进行相等连接),然后使用 if between 语句在组上减少它(这样做而不是 where 条件确保您获得正确的左外连接,因此您还可以查看您处理了哪些记录但在查找表中没有信息)。
Defo 不是最漂亮的,可能还有一两种优化它的方法,但现在对我有用,并在 10-20 秒内根据 16M 记录的查找表查找 500K 输入 IP 地址。
【讨论】:
【参考方案4】:您是否尝试过以下查询:
SELECT tbl1.integer, tbl2.data
FROM bq:data.tbl1
JOIN EACH bq:data.tbl2
ON tbl1.integer >= tbl2.start_integer AND tbl1.integer <= tbl2.end_integer;
【讨论】:
BigQuery 不支持 JOIN 上的不等式。 2016 年更新:新的 BigQuery SQL 确实支持 JOIN 上的不等式 - 取消选中“旧版 SQL”。 :)以上是关于bigquery 中的条件连接的主要内容,如果未能解决你的问题,请参考以下文章