通过 BigQuery 库发送的时间戳对象返回错误“此字段不是记录”

Posted

技术标签:

【中文标题】通过 BigQuery 库发送的时间戳对象返回错误“此字段不是记录”【英文标题】:Timestamp objects sent via BigQuery libraries return error "This field is not a record" 【发布时间】:2018-09-27 09:50:49 【问题描述】:

将日期字段作为对象发送到类型为时间戳的 BigQuery 表时,google java API 库不会引发异常,但不会引发数据。检查“InsertAllResponse”响应类型返回包括错误“此字段不是记录”。

例如

Hashmap<String,Object> rowContent = new Hashmap<>();
rowContent.put("Time", new Date());
rowContent.put("Name", "Harry");

然后

BigQuery bq = BigQueryOptions.getDefaultInstance().getService();
TableId tableId = TableId.of(datasetName, tableName);
InsertAllRequest.Builder insertReqBuilder = InsertAllRequest.newBuilder(tableId);
insertReqBuilder.addRow(some string, row);
InsertAllResponse response = bigquery.insertAll(insertReqBuilder.build());

返回一个 response.hasErrors() true。

还报告了 python here 和 firebase here 和 javascript here

【问题讨论】:

【参考方案1】:

似乎将日期作为对象发送会导致客户端 API 创建 JSON 记录而不是单个字段(这也表明日期时间类型尚未明确映射,因此可能会引入时区问题)。

相反,将日期/时间发送为自 1970 年以来的 UTC ,即修改上述内容:

Hashmap<String,Object> rowContent = new Hashmap<>();
rowContent.put("Time", Math.floor(new Date().getTime()/1000));
rowContent.put("Name", "Harry");

(注意:不知道如何处理毫秒,例如BigQuery not dealing with timestamp in millisecond with partition column,我会找出并回复)

【讨论】:

麻烦的Date 类在几年前被一个java.timeInstant 取代。在您的代码中使用类似 Instant.now().getEpochSecond() 的内容。 是的(ish); Date 仍在使用(周围有很多遗留代码)并且在这种情况下可以完成工作,因此它是一个合适的示例,并且您的评论是一个很好的提醒,提醒人们尽可能了解最新信息。 是的,以即时或任何日期对象形式发送日期,BIG Query API 将日期对象构造为 JSON 空对象(例如 date_field :)。所以将日期对象转换为字符串。 @YogaGowda 我已经包含了一个将时间戳转换为字符串的示例,以便在我的答案中达到微秒精度。感谢您的建议!【参考方案2】:

很遗憾,BigQuery 的 Java API 将 Java 类型转换为 BigQuery 类型,但没有记录在案。对于 BigQuery Timestamp,Java API 将 float 和 int 转换为自 Unix Epoch 以来截断的整数 seconds。这很愚蠢,考虑到几乎每个人都使用毫秒,因为 Unix Epoch 和 Timestamp 支持高达微秒的精度。如果您对秒没问题,请使用 int 作为秒。

如果您需要更高的准确性,请将您的 Timestamp 值转换为字符串。根据this documentation的规范字符串为:

YYYY-[M]M-[D]D[( |T)[H]H:[M]M:[S]S[.DDDDDD]][time zone] 

这是一个 Java 代码示例,其中“毫秒”存储自 Unix 纪元以来的毫秒数,但您可以使用您可能碰巧拥有的任何 DateTime:

long milliseconds = 1610399564959L;
LocalDateTime dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(milliseconds), ZoneOffset.UTC);
DateTimeFormatter timestampFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS");
String timestampText = dateTime.format(timestampFormatter);
rowContent.put("Time", timestampText);

我真希望 Google 能在某处记录这些转换。

【讨论】:

以上是关于通过 BigQuery 库发送的时间戳对象返回错误“此字段不是记录”的主要内容,如果未能解决你的问题,请参考以下文章

bigQuery 不支持毫秒时间戳

将 Google Data Studio 社区连接器与 BigQuery 结合使用时的时间戳查询问题

加载时间戳时出现 Bigquery 错误

BigQuery 日期和时间函数在时间戳列上返回 NULL

“pyarrow.lib.ArrowInvalid:从时间戳 [ns] 转换为时间戳 [ms] 会丢失数据”在将数据发送到没有架构的 BigQuery 时

BigQuery:插入行,但未写入