基本上我正在测试NTILE函数,将维基百科表的总字数分成100个桶。我使用Web控制台收到“响应太大错误”。所以我尝试了带有--destination_table和--allow_large_results选项的bq CLI工具,没有运气。
以下是查询:
SELECT id, num_characters, NTILE(100) OVER (ORDER BY num_characters) percentile
FROM [publicdata:samples.wikipedia]
如何正确检索结果?
答案 0 :(得分:4)
BigQuery获得惊人性能的秘诀:分配工作量。无论何时发出查询,大量计算机都会开始并行读取所有数据,处理数据并将其传递给链中的其他计算机。
但是,有些操作非常难以并行化 - 通常是在其他所有操作完成后运行的函数。这些操作不是分发的,而是限制在适合一台计算机的所有数据中。 ORDER BY和OVER()是这些函数中的一部分 - 因为最终单个机器需要对整个结果集进行排序。
好消息是我们有其他选择。 QUANTILES能够遍历所有数据,同时计算近似结果:
SELECT QUANTILES(num_characters, 100)
FROM [publicdata:samples.wikipedia]
Query complete (1.7s elapsed, 2.34 GB processed)
或者运行与原始问题相同的OVER(ORDER BY),但是在数据样本上运行:
SELECT id, num_characters, NTILE(100) OVER (ORDER BY num_characters) percentile
FROM [publicdata:samples.wikipedia]
WHERE id % 10 = 0;
Query complete (258.7s elapsed, 4.68 GB processed)
你会看到两者产生相似的结果(一个是近似值,另一个是采样值) - 但是一个更快。
答案 1 :(得分:0)
您可以使用UDF函数获取所有数据的nTiles,而不会导致内存饱和并且无需采样,尽管性能可能会降低。
我使用此方法来计算值的百分位数,就像内置的NTILE
函数一样。当应用于大量行时,内置函数在ORDER BY
操作期间将耗尽内存。
用户定义的函数采用一个分位数数组(在这种情况下,使用APPROX_QUANTILES
生成)和一个值,并返回该值所在的ntile。 / p>
-- Define UDF
CREATE TEMPORARY FUNCTION getNTile(quantiles ARRAY<INT64>, val INT64)
RETURNS INT64
LANGUAGE js AS """
var ntile = 0;
while(parseInt(val, 10) > parseInt(quantiles[ntile], 10) && ntile < quantiles.length) {
ntile+=1;
}
return ntile;
""";
-- Calculate an array of approximate quantiles, in this case percentiles
WITH master AS (
SELECT
id,
num_characters
FROM
`publicdata.samples.wikipedia`
),
quantiles AS (
SELECT
APPROX_QUANTILES(num_characters, 99) AS approx
FROM
master
)
-- Use UDF with approx quantile array to find nTile
SELECT
id,
num_characters,
getNTile(quantiles.approx, num_characters) AS percentile
FROM
master,
quantiles
UDF中的JS代码使用parseInt
将值强制为整数。可能是BigQuery错误,但出于某些原因,奇怪的是这些值是作为字符串传递的。
希望这对某人有帮助。