GDELT的Kalev Leetaru遇到了这个问题 - 在分析整整一个月时,以下查询将在BigQuery中运行,但是在整整一年中它不会运行。
SELECT Source, Target, count, RATIO_TO_REPORT(count) OVER() Weight
FROM (
SELECT a.name Source, b.name Target, COUNT(*) AS COUNT
FROM (FLATTEN(
SELECT
GKGRECORDID, CONCAT( STRING(ROUND(FLOAT(IFNULL(REGEXP_EXTRACT(SPLIT(V2Locations,';'),r'^[2-5]#.*?#.*?#.*?#.*?#(.*?)#'), '0')), 3)), '#', STRING(ROUND(FLOAT(IFNULL(REGEXP_EXTRACT(SPLIT(V2Locations,';'),r'^[2-5]#.*?#.*?#.*?#.*?#.*?#(.*?)#'), '0')), 3)) ) AS name
FROM [gdelt-bq:gdeltv2.gkg]
WHERE DATE>20150100000000 and DATE<20151299999999, name)) a
JOIN EACH (
SELECT
GKGRECORDID, CONCAT( STRING(ROUND(FLOAT(IFNULL(REGEXP_EXTRACT(SPLIT(V2Locations,';'),r'^[2-5]#.*?#.*?#.*?#.*?#(.*?)#'), '0')), 3)), '#', STRING(ROUND(FLOAT(IFNULL(REGEXP_EXTRACT(SPLIT(V2Locations,';'),r'^[2-5]#.*?#.*?#.*?#.*?#.*?#(.*?)#'), '0')), 3)) ) AS name
FROM [gdelt-bq:gdeltv2.gkg]
WHERE DATE>20150100000000 and DATE<20151299999999 ) b
ON a.GKGRECORDID=b.GKGRECORDID
WHERE a.name<b.name
AND a.name != '0.000000#0.000000'
AND b.name != '0.000000#0.000000'
GROUP EACH BY 1, 2
ORDER BY 3 DESC )
WHERE count > 50
LIMIT 500000
&#34;查询执行期间超出资源。&#34;
我们如何解决这个问题?
答案 0 :(得分:1)
首先是关于成本优化的说明:每列扫描的BigQuery费用,此查询将超过72GB。 GDELT gkg表将其整个故事存储在一个表中 - 我们可以通过创建年度表而不是单个表来优化成本。
现在,我们如何修复此查询以使其运行一整年? “在查询执行期间超出资源”通常来自不可扩展的功能。例如:
RATIO_TO_REPORT(COUNT) OVER()
将无法扩展:OVER()函数在整个结果集上运行,允许我们计算总数以及每行总贡献的数量 - 但为此要运行,我们需要整个结果集适合一个VM。好消息是OVER()能够在分区数据时进行扩展,例如通过具有OVER(PARTITION BY月) - 然后我们只需要每个分区都适合VM。对于此查询,我们将删除此结果列,以简化。
ORDER BY不会缩放:要对结果进行排序,我们还需要将所有结果都放在一个VM上。这就是' - allow-large-results'不允许运行ORDER BY步骤的原因,因为每个VM将并行处理和输出结果。
在此查询中,我们有一种简单的方法来处理ORDER BY可伸缩性 - 我们将更早的过滤器“WHERE COUNT&gt; 50”移到流程中。我们将移动它并将其更改为HAVING,而不是对所有结果进行排序,并过滤那些COUNT> 50的结果,因此它在ORDER BY之前运行:
SELECT Source, Target, count
FROM (
SELECT a.name Source, b.name Target, COUNT(*) AS COUNT
FROM (FLATTEN(
SELECT
GKGRECORDID, CONCAT( STRING(ROUND(FLOAT(IFNULL(REGEXP_EXTRACT(SPLIT(V2Locations,';'),r'^[2-5]#.*?#.*?#.*?#.*?#(.*?)#'), '0')), 3)), '#', STRING(ROUND(FLOAT(IFNULL(REGEXP_EXTRACT(SPLIT(V2Locations,';'),r'^[2-5]#.*?#.*?#.*?#.*?#.*?#(.*?)#'), '0')), 3)) ) AS name
FROM [gdelt-bq:gdeltv2.gkg]
WHERE DATE>20150100000000 and DATE<20151299999999,name)) a
JOIN EACH (
SELECT
GKGRECORDID, CONCAT( STRING(ROUND(FLOAT(IFNULL(REGEXP_EXTRACT(SPLIT(V2Locations,';'),r'^[2-5]#.*?#.*?#.*?#.*?#(.*?)#'), '0')), 3)), '#', STRING(ROUND(FLOAT(IFNULL(REGEXP_EXTRACT(SPLIT(V2Locations,';'),r'^[2-5]#.*?#.*?#.*?#.*?#.*?#(.*?)#'), '0')), 3)) ) AS name
FROM [gdelt-bq:gdeltv2.gkg]
WHERE DATE>20150100000000 and DATE<20151299999999 ) b
ON a.GKGRECORDID=b.GKGRECORDID
WHERE a.name<b.name
AND a.name != '0.000000#0.000000'
AND b.name != '0.000000#0.000000'
GROUP EACH BY 1, 2
HAVING count>50
ORDER BY 3 DESC )
LIMIT 500000
现在查询运行了整整一年的数据!
让我们看一下解释统计数据:
我们可以看到188万行表被读了两次:第一个子查询产生了15亿行(给定“FLATTEN”),第二个子查询过滤掉了不在2015年的行(注意这个表开始存储数据在2015年初。)
第3阶段很有趣:加入两个子查询产生了30亿行!使用FILTER和AGGREGATE步骤将这些减少到5亿:
我们可以做得更好吗?
是的!让我们将2 WHERE a.name != '....'
移到更早的“HAVING”:
SELECT Source, Target, count
FROM (
SELECT a.name Source, b.name Target, COUNT(*) AS COUNT
FROM (FLATTEN(
SELECT
GKGRECORDID, CONCAT( STRING(ROUND(FLOAT(IFNULL(REGEXP_EXTRACT(SPLIT(V2Locations,';'),r'^[2-5]#.*?#.*?#.*?#.*?#(.*?)#'), '0')), 3)), '#', STRING(ROUND(FLOAT(IFNULL(REGEXP_EXTRACT(SPLIT(V2Locations,';'),r'^[2-5]#.*?#.*?#.*?#.*?#.*?#(.*?)#'), '0')), 3)) ) AS name
FROM [gdelt-bq:gdeltv2.gkg]
WHERE DATE>20150100000000 and DATE<20151299999999
HAVING name != '0.000000#0.000000',name)) a
JOIN EACH (
SELECT
GKGRECORDID, CONCAT( STRING(ROUND(FLOAT(IFNULL(REGEXP_EXTRACT(SPLIT(V2Locations,';'),r'^[2-5]#.*?#.*?#.*?#.*?#(.*?)#'), '0')), 3)), '#', STRING(ROUND(FLOAT(IFNULL(REGEXP_EXTRACT(SPLIT(V2Locations,';'),r'^[2-5]#.*?#.*?#.*?#.*?#.*?#(.*?)#'), '0')), 3)) ) AS name
FROM [gdelt-bq:gdeltv2.gkg]
WHERE DATE>20150100000000 and DATE<20151299999999
HAVING name != '0.000000#0.000000') b
ON a.GKGRECORDID=b.GKGRECORDID
WHERE a.name<b.name
GROUP EACH BY 1, 2
HAVING count>50
ORDER BY 3 DESC )
LIMIT 500000
运行得更快!
让我们看一下解释统计数据:
请参阅?通过在加入之前将过滤移动到一个步骤,阶段3只需要经过10亿行,而不是30亿行。更快(即使对于BigQuery,你可以自己检查,在短时间内能够超过30亿行加入)。
这个查询是什么?
在这里查看美丽的结果:http://blog.gdeltproject.org/a-city-level-network-diagram-of-2015-in-one-line-of-sql/