Avro 日期和时间与 BigQuery 的兼容性?
Compatibility of Avro dates and times with BigQuery?
BigQuery 通常可以很好地加载 Avro 数据,但是 "bq load" 在处理时间戳和其他使用 Avro logicalType 属性的 date/time 字段时遇到很多问题。
- 当 BigQuery TIMESTAMP 将我的 Avro 类型时间戳-毫秒数据解释为微秒时间戳(相差 1000)时,我的数据被破坏了。
- 可以加载到 TIMESTAMP 中的时间戳微整数在 BigQuery DATETIME 中变为无效。我找不到在 https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types
有效的解释
- ISO8601 格式的字符串无法加载到 TIMESTAMP 或 DATETIME(不兼容类型错误),但我认为如果我加载的是纯文本,BigQuery 会支持 JSON.
- Avro "date" 类型无法加载到 DATE(也是不兼容的类型)。
我想我可以通过始终将数据加载到临时字段并使用查询来 CAST 或将它们转换为其他字段来解决这些问题,但这不能很好地扩展或支持模式演变或流式传输。使用定义明确的模式在 Avro 中生成数据应该可以避免为不同的消费者再次转换数据的额外步骤。
BigQuery 真的与 Avro 日期和时间如此不兼容吗? (或者我在做什么蠢事)
或者 "bq load" 问题出在这里?有没有更好的方法来加载 Avro 数据?
对 Avro 逻辑类型的原生理解现已公开供所有 BigQuery 用户使用。有关详细信息,请参阅此处的文档页面:https://cloud.google.com/bigquery/docs/loading-data-cloud-storage-avro#logical_types
我在 PostgreSQL table 中有包含 TIMESTAMP 列的数据。在遵循 https://github.com/spotify/spark-bigquery/issues/19.
评论中的建议后,我能够通过 Avro 将其导入 BigQuery
在 Kotlin 中使用 PostgreSQL JDBC 库,我重新计算了时间戳 into BigQuery internal format(自 Unix 时代开始以来的微秒数)
(object as java.sql.Timestamp).time * 1000
并将其放入我的 avro 记录中,类型为 Schema.Type.LONG
。
然后我 created a schema file for my data in JSON 我给列类型 "timestamp"。
[
{"name": "job", "type": "string", "mode": "required"},
...
{"name": "began", "type": "timestamp", "mode": "required"},
...
]
(见开始字段)
最后,我使用
将其导入 BigQuery
bq mk test.test2 dataset.avro schema.json
结果是
$ bq head test.test2
+------+----+----------+---------------------+---------+-----------+
| job | id | duration | began | status | node_name |
+------+----+----------+---------------------+---------+-----------+
| job1 | 1 | 0.0 | 2012-04-01 00:00:00 | aStatus | aNodeName |
| job2 | 1 | 0.0 | 2020-02-02 00:02:02 | aStatus | aNodeName |
+------+----+----------+---------------------+---------+-----------+
Web UI 不允许为 Avro 文件指定架构,但 CLI 客户端和 API 可以。
我仍然遇到的唯一问题是处理时区。但这不是 Avro 的问题。
更新:现已支持该功能,更多信息请关注issuetracker.google.com/35905894。
正如 Hua 所说,BigQuery 不支持 Avro 逻辑类型,但支持使用时间戳加载 Avro 数据的方法是使用 LONG Avro 类型将数据加载到现有的具有 TIMESTAMP 的 BigQuery table柱子。此外,该值应该是从 EPOCH 算起的微秒(而不是秒或毫秒)。例如,下面的 Avro 文件有一个值为 1408452095000000 的 LONG 字段,表示“2014-08-19 12:41:35”。
Avro 文件的架构:
% avro-tools getschema ~/dataset/simple_timestamp.avro
{
"type" : "record",
"name" : "FullName",
"fields" : [ {
"name" : "t",
"type" : "long"
} ]
}
使用时间戳字段将 Avro 文件加载到 table 的示例:
bq mk --schema t:TIMESTAMP -t vimota.simple_timestamp
bq load --source_format=AVRO vimota.simple_timestamp ~/dataset/simple_timestamp.avro
bq head vimota.simple_timestamp:
+---------------------+
| t |
+---------------------+
| 2014-08-19 12:41:35 |
+---------------------+
我们遇到了同样的问题并解决了。用于将日期数据导入 DATE 类型的现有 BQ table 字段的 Avro 模式如下所示。日期值的整数值必须是自纪元以来的天数(不是秒)。请注意使用嵌套格式的架构类型定义的样式。
- 我创建了一个 BQ table,其中一个字段名为“day”,类型为 DATE,mode=REQUIRED。
- 我创建了一个具有以下架构的 Avro 文件,其中一条记录包含几天的整数值 18639
- 我将该 Avro 文件上传到 GCS 中的存储桶
- 我使用以下方法将 Avro 数据加载到 table 中,当我在 table 中查看它时,它被转换为 BQ DATE 类型:
bq load --source_format AVRO --use_avro_logical_types s1.avro_date gs://bucket_name/bq_date_int_logical_nested.avro
echo "select * from s1.avro_date" | bq query
Waiting on bqjob_r1433d5cfa5eb9a89_00000176f3182f03_1 ... (0s) Current status: DONE
+------------+
| day |
+------------+
| 2021-01-12 |
+------------+
使用的架构:
{
"type" : "record",
"name" : "bq_date",
"namespace" : "my.namespace",
"fields" : [{
"name" : "day",
"type" : {
"type" : "int",
"logicalType" : "date"
}
}
]
}
FWIW:我们测试了使用 Avro Python 1.10.1 和 Java 库创建的测试文件。
BigQuery 通常可以很好地加载 Avro 数据,但是 "bq load" 在处理时间戳和其他使用 Avro logicalType 属性的 date/time 字段时遇到很多问题。
- 当 BigQuery TIMESTAMP 将我的 Avro 类型时间戳-毫秒数据解释为微秒时间戳(相差 1000)时,我的数据被破坏了。
- 可以加载到 TIMESTAMP 中的时间戳微整数在 BigQuery DATETIME 中变为无效。我找不到在 https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types 有效的解释
- ISO8601 格式的字符串无法加载到 TIMESTAMP 或 DATETIME(不兼容类型错误),但我认为如果我加载的是纯文本,BigQuery 会支持 JSON.
- Avro "date" 类型无法加载到 DATE(也是不兼容的类型)。
我想我可以通过始终将数据加载到临时字段并使用查询来 CAST 或将它们转换为其他字段来解决这些问题,但这不能很好地扩展或支持模式演变或流式传输。使用定义明确的模式在 Avro 中生成数据应该可以避免为不同的消费者再次转换数据的额外步骤。
BigQuery 真的与 Avro 日期和时间如此不兼容吗? (或者我在做什么蠢事)
或者 "bq load" 问题出在这里?有没有更好的方法来加载 Avro 数据?
对 Avro 逻辑类型的原生理解现已公开供所有 BigQuery 用户使用。有关详细信息,请参阅此处的文档页面:https://cloud.google.com/bigquery/docs/loading-data-cloud-storage-avro#logical_types
我在 PostgreSQL table 中有包含 TIMESTAMP 列的数据。在遵循 https://github.com/spotify/spark-bigquery/issues/19.
评论中的建议后,我能够通过 Avro 将其导入 BigQuery在 Kotlin 中使用 PostgreSQL JDBC 库,我重新计算了时间戳 into BigQuery internal format(自 Unix 时代开始以来的微秒数)
(object as java.sql.Timestamp).time * 1000
并将其放入我的 avro 记录中,类型为 Schema.Type.LONG
。
然后我 created a schema file for my data in JSON 我给列类型 "timestamp"。
[
{"name": "job", "type": "string", "mode": "required"},
...
{"name": "began", "type": "timestamp", "mode": "required"},
...
]
(见开始字段)
最后,我使用
将其导入 BigQuerybq mk test.test2 dataset.avro schema.json
结果是
$ bq head test.test2
+------+----+----------+---------------------+---------+-----------+
| job | id | duration | began | status | node_name |
+------+----+----------+---------------------+---------+-----------+
| job1 | 1 | 0.0 | 2012-04-01 00:00:00 | aStatus | aNodeName |
| job2 | 1 | 0.0 | 2020-02-02 00:02:02 | aStatus | aNodeName |
+------+----+----------+---------------------+---------+-----------+
Web UI 不允许为 Avro 文件指定架构,但 CLI 客户端和 API 可以。
我仍然遇到的唯一问题是处理时区。但这不是 Avro 的问题。
更新:现已支持该功能,更多信息请关注issuetracker.google.com/35905894。
正如 Hua 所说,BigQuery 不支持 Avro 逻辑类型,但支持使用时间戳加载 Avro 数据的方法是使用 LONG Avro 类型将数据加载到现有的具有 TIMESTAMP 的 BigQuery table柱子。此外,该值应该是从 EPOCH 算起的微秒(而不是秒或毫秒)。例如,下面的 Avro 文件有一个值为 1408452095000000 的 LONG 字段,表示“2014-08-19 12:41:35”。
Avro 文件的架构:
% avro-tools getschema ~/dataset/simple_timestamp.avro
{
"type" : "record",
"name" : "FullName",
"fields" : [ {
"name" : "t",
"type" : "long"
} ]
}
使用时间戳字段将 Avro 文件加载到 table 的示例:
bq mk --schema t:TIMESTAMP -t vimota.simple_timestamp
bq load --source_format=AVRO vimota.simple_timestamp ~/dataset/simple_timestamp.avro
bq head vimota.simple_timestamp:
+---------------------+
| t |
+---------------------+
| 2014-08-19 12:41:35 |
+---------------------+
我们遇到了同样的问题并解决了。用于将日期数据导入 DATE 类型的现有 BQ table 字段的 Avro 模式如下所示。日期值的整数值必须是自纪元以来的天数(不是秒)。请注意使用嵌套格式的架构类型定义的样式。
- 我创建了一个 BQ table,其中一个字段名为“day”,类型为 DATE,mode=REQUIRED。
- 我创建了一个具有以下架构的 Avro 文件,其中一条记录包含几天的整数值 18639
- 我将该 Avro 文件上传到 GCS 中的存储桶
- 我使用以下方法将 Avro 数据加载到 table 中,当我在 table 中查看它时,它被转换为 BQ DATE 类型:
bq load --source_format AVRO --use_avro_logical_types s1.avro_date gs://bucket_name/bq_date_int_logical_nested.avro
echo "select * from s1.avro_date" | bq query
Waiting on bqjob_r1433d5cfa5eb9a89_00000176f3182f03_1 ... (0s) Current status: DONE
+------------+
| day |
+------------+
| 2021-01-12 |
+------------+
使用的架构:
{
"type" : "record",
"name" : "bq_date",
"namespace" : "my.namespace",
"fields" : [{
"name" : "day",
"type" : {
"type" : "int",
"logicalType" : "date"
}
}
]
}
FWIW:我们测试了使用 Avro Python 1.10.1 和 Java 库创建的测试文件。