在 BigQuery 中订购大型时间序列数据集以进行导出

Posted

技术标签:

【中文标题】在 BigQuery 中订购大型时间序列数据集以进行导出【英文标题】:Ordering large time series datasets in BigQuery for export 【发布时间】:2020-01-03 17:42:35 【问题描述】:

我目前正在使用 BigQuery 存储来自各种系统的大型时间序列数据集,其采样率从 1 个样本/小时到 1000 个样本/秒。

我在每个基表上应用了一个不重叠的滑动窗口来聚合数据,这实际上是对其进行下采样。我对每个聚合表重复执行此操作,直到最终表中的行数不超过 6000 行。我这样做的原因是我可以查看多个不同详细级别的时间序列数据。

目前,我使用 Python SDK 通过 csv 上传到 BigQuery 来加载数据。 csv 文件是测量系统输出的内容,我无法控制。我使用以下代码执行表聚合:

.
.
.

# Create an array of the field names in the table to be aggregated
field_names = [schema_field.name for schema_field in bq_client.get_table(f'dataset.table').schema]

# Create a string to be used in the query to extract the MIN and MAX of each field for a specified window
min_max_string = [f'MIN(field) field_min, MAX(field) field_max,' for field in field_names if field != index_col]

# Create table for each additional level of detail beyond the base table which has been predetermined
        if num_lvls > 0:

            for lvl in range(1, num_lvls + 1):
                lod_dataset_name = f'dataset'
                lod_table_name = f'table_lvl_lvl'

                # Query string to aggregate base table for each level of detail. 
                query = f'''CREATE OR REPLACE TABLE
                    lod_dataset_name.lod_table_name 
                    AS
                    With RankedData AS  (
                        SELECT ROW_NUMBER() OVER (ORDER BY index_col) Rank, * 
                        FROM `dataset.table`
                    )
                    SELECT DIV((Rank -1), window_length**lvl ) GroupId, MIN(index_col) index_col, (' ').join(query_string) MIN(Rank) index
                        FROM  RankedData
                        GROUP BY GroupId
                        ORDER BY GroupId'''

                # Create query job via API request to Google
                query_job = bq_client.query(query) 
.
.
.

上面代码中变量的注意事项: num_lvls 是需要创建的聚合表的数量,根据窗口大小和最聚合表中的最大元素数确定。 index_col 是数据必须排序的列。在 99% 的情况下,时间戳 GroupId 用于将数据分组到“bins”中,然后我们可以通过获取每个 bin 的最大值和最小值来使用它来进行下采样。

我担心的是,尽管这似乎适用于当前数据,但我担心如果数据集变得更大,我将遇到与 Order By 子句相关的问题。据我了解,BigQuery 没有有序数据的概念,因为数据被拆分到各种存储资源中。因此,当我需要对数据进行排序时,它需要将所有数据加载到单个 VM 上并在那里进行排序。我想这很快就会导致内存问题。

我需要对数据进行排序的原因是因为下采样需要按时间戳对数据进行排序。每个时间戳都是唯一的,并且时间戳之间的增量是恒定的。然后我将数据推送到 React 前端,该前端使用 D3 绘制时间序列数据。我只选择每个表的一部分,具体取决于用户选择的详细程度。这意味着我需要在发送到前端之前对数据进行排序。

使用分区和集群的问题在于,对于每小时采样的数据,我将在每个表中有 24 行(每小时一个样本,按天分区)。每个表最多有 4000 个分区,我将在大约 10 年的数据后超过这个限制。不幸的是,一些数据集已经可以追溯到 7 或 8 年,因此我很快就会达到这个限制。对于更高采样的数据,我认为分区和聚类是要走的路。

我能想到但尚未测试的一种解决方法是根据每小时数据的摄取时间创建单个分区,然后我可以在该单个分区上使用集群,看到集群当前需要一个表分区。据我了解,这应该给我一个排序表。

这个解决方案行得通吗?还是有更优雅的解决方案?

我可能错过的任何指针或参考将不胜感激。如果有任何不清楚的地方,请告诉我,我可以相应地更新问题。

【问题讨论】:

【参考方案1】:

您的担忧是完全可以理解的,因为您使用的是 BigQuery,请参阅此 *** 问题 [1] 的答案,如果我理解正确,您使用 BigQuery 作为数据库来存储数据,而不是使用数据做分析功能。

因此,我建议使用另一种数据库,例如Firestore [2],这样您就可以运行查询对值进行排序而不会出现问题,因为 firestore 对每一列都有一个时间戳值,因此您可以使用此列对数据进行排序。这是在 Firestore [3] 中排序数据的链接。

另外,我不太清楚你的用例,如果你只能创建一个带有时间戳值的大表,并且只为这个表收集数据,为什么还要创建这么多表。

[1]bigquery resource limited exeeded due to order by

[2]https://cloud.google.com/firestore/

[3]https://firebase.google.com/docs/firestore/query-data/order-limit-data

【讨论】:

您好,贡萨洛,感谢您的回复。不幸的是,我拥有的数据量将超过 Firestore 的典型容量,并且数据是关系数据,因此所有查询都是使用 SQL 设计的。我可以将表格拆分,但将数据保存在一个表格中会非常理想。如果此时无法并行排序和输出到目标表,我将不得不拆分表。 在发表此评论后,我不太了解您的数据结构。你的数据是关系数据吗?您的数据是在不同的表中还是在一个表中?但是,如果您使用的是关系数据,我认为 BigQuery 不适合这样做。

以上是关于在 BigQuery 中订购大型时间序列数据集以进行导出的主要内容,如果未能解决你的问题,请参考以下文章

公开大型 Web 服务数据集以供 Access 或 Excel 使用

有效地组织大型数据集以进行报告

BigQuery - 最大数据集大小

使用 Python 的 BigQuery

R - 为 Google BigQuery 导入清理数据

如何从 BigQuery 中存储的大型线串数据集中查找所有道路交叉口