Avro 日期和时间与 BigQuery 的兼容性?

Compatibility of Avro dates and times with BigQuery?

BigQuery 通常可以很好地加载 Avro 数据,但是 "bq load" 在处理时间戳和其他使用 Avro logicalType 属性的 date/time 字段时遇到很多问题。

  1. 当 BigQuery TIMESTAMP 将我的 Avro 类型时间戳-毫秒数据解释为微秒时间戳(相差 1000)时,我的数据被破坏了。
  2. 可以加载到 TIMESTAMP 中的时间戳微整数在 BigQuery DATETIME 中变为无效。我找不到在 https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types
  3. 有效的解释
  4. ISO8601 格式的字符串无法加载到 TIMESTAMP 或 DATETIME(不兼容类型错误),但我认为如果我加载的是纯文本,BigQuery 会支持 JSON.
  5. 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 模式如下所示。日期值的整数值必须是自纪元以来的天数(不是秒)。请注意使用嵌套格式的架构类型定义的样式。

  1. 我创建了一个 BQ table,其中一个字段名为“day”,类型为 DATE,mode=REQUIRED。
  2. 我创建了一个具有以下架构的 Avro 文件,其中一条记录包含几天的整数值 18639
  3. 我将该 Avro 文件上传到 GCS 中的存储桶
  4. 我使用以下方法将 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 库创建的测试文件。