【发布时间】: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 年,因此我很快就会达到这个限制。对于更高采样的数据,我认为分区和聚类是要走的路。
我能想到但尚未测试的一种解决方法是根据每小时数据的摄取时间创建单个分区,然后我可以在该单个分区上使用集群,看到集群当前需要一个表分区。据我了解,这应该给我一个排序表。
这个解决方案行得通吗?还是有更优雅的解决方案?
我可能错过的任何指针或参考将不胜感激。如果有任何不清楚的地方,请告诉我,我可以相应地更新问题。
【问题讨论】:
标签: d3.js google-cloud-platform google-bigquery