BeamSQL中TIMESTAMP类型日期解析失败,编码报错求助
这个错误的核心原因很明确:你传入的日期字符串格式和Beam TIMESTAMP类型预期的格式不匹配。
Beam的TIMESTAMP类型默认只认两种输入:
- ISO 8601标准格式的字符串(比如
2017-12-02T00:00:00Z这种带时区标记的完整格式) - Java原生的时间对象(比如
Instant、java.sql.Timestamp)
而你提供的 2/12/2017 是自定义的短日期格式,BeamRecordCoder没有内置的逻辑去解析这种格式,自然会抛出编码失败的异常。
具体解决方案
这里给你三种可行的处理方式,按推荐优先级排序:
1. 转换日期为ISO 8601标准格式
把你的短日期字符串转换成Beam能识别的标准格式,比如如果 2/12/2017 代表2017年12月2日,就转成 2017-12-02T00:00:00Z;如果是2017年2月12日,就转成 2017-02-12T00:00:00Z。可以用Java的DateTimeFormatter来实现:
String originalDate = "2/12/2017"; // 这里的格式要和你的原始日期匹配,M/d/yyyy对应月/日/年 DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("M/d/yyyy").withZone(ZoneOffset.UTC); Instant timestamp = Instant.from(inputFormatter.parse(originalDate)); String isoDate = timestamp.toString(); // 得到标准ISO格式字符串
将转换后的isoDate存入dataValues,Beam就能正确识别为TIMESTAMP类型。
2. 直接使用Java时间对象构造BeamRecord
如果你是在代码里手动构造BeamRecord,完全可以跳过字符串转换,直接传入Instant对象:
String originalDate = "2/12/2017"; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy").withZone(ZoneOffset.UTC); Instant timestamp = Instant.from(formatter.parse(originalDate)); // 构造BeamRecord时直接传入Instant对象 BeamRecord record = new BeamRecord(Arrays.asList("c0"), Arrays.asList(timestamp));
这种方式最直接,也能避免格式解析的潜在问题。
3. 自定义Coder(特殊场景使用)
如果业务上必须保留2/12/2017这种格式的字符串,同时要标记为TIMESTAMP类型,你可以自定义一个Coder,在编码阶段把字符串转成Beam能处理的时间格式,解码时再转回来。不过这种方式比较繁琐,除非有特殊需求,否则不推荐。
另外可以确认下:你的fieldTypes=[12]确实对应TIMESTAMP类型(Beam中SQL类型12通常就是TIMESTAMP),如果类型映射没问题,那解决日期格式的问题后就能正常编码了。
内容的提问来源于stack exchange,提问作者Nagesh Singh Chauhan

