sql - 折叠大型 BigQuery 结果
问题描述
我有什么简单的方法可以对fold_left
BigQuery 查询的结果执行类似 Ocaml 的操作,其中每次迭代对应于结果中的一行?
什么产品或方法是最简单的方法?如果:
- 我需要做的就是提供初始状态和“文件夹”功能
- 最好,我想用函数式语言编写“文件夹”函数
- 我不需要安装任何 GCP 包
由于我不知道哪种产品或语言会起作用,我不能更具体,但伪代码就像:
let my_init = []
let my_folder = fun state row ->
// append for now, but it will be complicated. I need to do some set operations here. The point is that I need some way of transferring "state" across rows, when I iterate over rows in a predefined order.
row.col1 :: state
let query = "SELECT col1, col2, col3 FROM table1 ORDER BY timestamp"
query |> List.fold my_folder my_init
我想从这个简化的例子中得到的结果是最终的“状态”。
- - 更新 - -
行数没有限制——如果我们收到更多,我们会得到更多行。通常,这个数字超过几百万,但也可能更大。
这是一个简化的示例,显示了我遇到的主要问题。我们有一个包含几列的表:
- 时间戳
- user_id:一个字符串id
- operation_json:一个字符串化的 JSON 对象,它是一个操作列表,每个操作对应于:
- 将 user_id 添加到集合中
- 从集合中删除 user_id
例如,以下是有效行:
----------+---------+----------------------------------------------
timestamp | user_id | operation_json
----------+---------+----------------------------------------------
1 | id1 | [ { "op": "add", "set": "set1" } ]
2 | id2 | [ { "op": "add", "set": "set1" } ]
3 | id1 | [ { "op": "add", "set": "set2" } ]
4 | id3 | [ { "op": "add", "set": "set2" } ]
5 | id1 | [ { "op": "remove", "set": "set1" } ]
----------+---------+----------------------------------------------
结果,我想获得一组用户;IE,
set1 |-> { id2 }
set2 |-> { id1, id3 }
我认为类似 fold_left 的操作会很方便。状态为 map>,初始状态为空映射。
解决方案
下面是 BigQuery 标准 SQL 的 [快速简单] 示例
#standardSQL
CREATE TEMP FUNCTION fold(arr ARRAY<INT64>, init INT64)
RETURNS FLOAT64
LANGUAGE js AS """
const reducer = (accumulator, currentValue) => accumulator + parseInt(currentValue);
return arr.reduce(reducer, 5);
""";
WITH `project.dataset.table` AS (
SELECT 1 id, [1, 2, 3, 4] arr, 5 initial_state UNION ALL
SELECT 2, [1, 2, 3, 4, 5, 6, 7], 10
)
SELECT id, fold(arr, initial_state) result
FROM `project.dataset.table`
输出是
Row id result
1 1 15.0
2 2 33.0
我认为这是不言自明的
查看更多JS UDF
行的折叠列表
请参见上面的扩展
下面在这里,您在应用折叠功能之前从结果的行中组装数组(当然,您需要limits
记住一些 UDF 以及您的 ARRAY 行可以有多大,等等。
#standardSQL
CREATE TEMP FUNCTION fold(arr ARRAY<INT64>, init INT64)
RETURNS FLOAT64
LANGUAGE js AS """
const reducer = (accumulator, currentValue) => accumulator + parseInt(currentValue);
return arr.reduce(reducer, 5);
""";
WITH `project.dataset.table` AS (
SELECT 1 id, 1 item UNION ALL
SELECT 1, 2 UNION ALL
SELECT 1, 3 UNION ALL
SELECT 1, 4 UNION ALL
SELECT 2, 1 UNION ALL
SELECT 2, 2 UNION ALL
SELECT 2, 3 UNION ALL
SELECT 2, 4 UNION ALL
SELECT 2, 5 UNION ALL
SELECT 2, 6 UNION ALL
SELECT 2, 7
)
SELECT id, fold(ARRAY_AGG(item), 5) result
FROM `project.dataset.table`
GROUP BY id
请注意,如果您需要在每一行中包含多个字段 - 您可以使用 STRUCT 的 ARRAY,如下例所示
ARRAY_AGG(STRUCT(id , item) ORDER by id)
当然,您需要分别调整折叠 UDF 的签名
例如:
#standardSQL
CREATE TEMP FUNCTION fold(arr ARRAY<STRUCT<id INT64, item INT64>>, init INT64)
RETURNS FLOAT64
LANGUAGE js AS """
const reducer = (accumulator, currentValue) => accumulator + parseInt(currentValue.item);
return arr.reduce(reducer, 5);
""";
WITH `project.dataset.table` AS (
SELECT 1 id, 1 item UNION ALL
SELECT 1, 2 UNION ALL
SELECT 1, 3 UNION ALL
SELECT 1, 4 UNION ALL
SELECT 2, 1 UNION ALL
SELECT 2, 2 UNION ALL
SELECT 2, 3 UNION ALL
SELECT 2, 4 UNION ALL
SELECT 2, 5 UNION ALL
SELECT 2, 6 UNION ALL
SELECT 2, 7
)
SELECT id, fold(ARRAY_AGG(t), 5) result
FROM `project.dataset.table` t
GROUP BY id
推荐阅读
- javascript - 反应提交表单不发送 POST 请求
- c# - SPAudit.WriteAuditEvent 重载不可用
- python-3.x - WAG 矩阵实现
- java - SOAP 消息作为字符串发送到 Java 中的端点
- cordova - 无法在点击事件时设置离子本地通知(奇怪的语法错误)
- python - 为什么这个lookbehind失败,这个异常是什么意思?
- ios - iOS 文件应用程序不会从另一个文件夹打开我的应用程序
- c# - Unity - Quaternion.Slerp 在一个半球
- javascript - ES6:如何比较两个数组中的值
- android - 解析平台包括在 Android 上