如何在Avro中将记录与地图混合?

时间:2015-09-18 00:45:19

标签: avro

我正在处理JSON格式的服务器日志,我想以Parquet格式将我的日志存储在AWS S3上(而Parquet需要Avro架构)。首先,所有日志都有一组通用字段,其次,所有日志都有很多可选字段,这些字段不在公共集中。

例如,下面是三个日志:

{ "ip": "172.18.80.109", "timestamp": "2015-09-17T23:00:18.313Z", "message":"blahblahblah"}
{ "ip": "172.18.80.112", "timestamp": "2015-09-17T23:00:08.297Z", "message":"blahblahblah", "microseconds": 223}
{ "ip": "172.18.80.113", "timestamp": "2015-09-17T23:00:08.299Z", "message":"blahblahblah", "thread":"http-apr-8080-exec-1147"}

所有这三个日志都有3个共享字段:iptimestampmessage,某些日志还有其他字段,例如microseconds和{{1 }}

如果我使用以下架构,那么我将丢失所有其他字段。:

thread

以下架构工作正常:

{"namespace": "example.avro",
 "type": "record",
 "name": "Log",
 "fields": [
     {"name": "ip", "type": "string"},
     {"name": "timestamp",  "type": "String"},
     {"name": "message", "type": "string"}
 ]
}

但唯一的问题是我不知道所有可选字段的名称,除非我扫描所有日志,此外,将来会有新的附加字段。

然后我想出了一个结合{"namespace": "example.avro", "type": "record", "name": "Log", "fields": [ {"name": "ip", "type": "string"}, {"name": "timestamp", "type": "String"}, {"name": "message", "type": "string"}, {"name": "microseconds", "type": [null,long]}, {"name": "thread", "type": [null,string]} ] } record的想法:

map

不幸的是,这不会编译:

{"namespace": "example.avro",
 "type": "record",
 "name": "Log",
 "fields": [
     {"name": "ip", "type": "string"},
     {"name": "timestamp",  "type": "String"},
     {"name": "message", "type": "string"},
     {"type": "map", "values": "string"}  // error
 ]
}

会抛出错误:

java -jar avro-tools-1.7.7.jar compile schema example.avro .

有没有办法以Avro格式存储JSON字符串,可灵活处理未知的可选字段?

基本上这是架构演变问题,Spark可以通过Schema Merging来解决这个问题。我正在寻求Hadoop的解决方案。

1 个答案:

答案 0 :(得分:10)

地图类型是avro术语中的“复杂”类型。以下代码段有效:

{"namespace": "example.avro",
 "type": "record",
 "name": "Log",
 "fields": [
   {"name": "ip", "type": "string"},
   {"name": "timestamp",  "type": "string"},
   {"name": "message", "type": "string"},
   {"name": "additional", "type": {"type": "map", "values": "string"}}
  ]
}