【问题标题】:Timestamp objects sent via BigQuery libraries return error "This field is not a record"通过 BigQuery 库发送的时间戳对象返回错误“此字段不是记录”
【发布时间】: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 herefirebase herejavascript here

【问题讨论】:

    标签: datetime google-bigquery


    【解决方案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 能在某处记录这些转换。

    【讨论】:

      猜你喜欢
      • 2018-09-27
      • 1970-01-01
      • 2022-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多