web-dev-qa-db-ja.com

Avroでレコードをマップと混合する方法は?

JSON形式のサーバーログを処理していて、ログをAWS S3にParquet形式で保存したい(そしてParquetにはAvroスキーマが必要です)。 1つ目は、すべてのログに共通のフィールドセットがあり、2つ目は、すべてのログに、共通セットにない多くのオプションフィールドがあります。

たとえば、次の3つのログがあります。

{ "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の3つの共有フィールドがあり、一部のログには、microsecondsthreadなどの追加フィールドがあります。

次のスキーマを使用すると、追加のフィールドがすべて失われます。

{"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]}
 ]
}

しかし、唯一の問題は、すべてのログをスキャンしない限り、オプションフィールドの名前がす​​べてわからないことです。さらに、将来的に新しいフィールドが追加されます。

次に、recordmapを組み合わせたアイデアを考えます。

{"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 .

エラーが発生します:

Exception in thread "main" org.Apache.avro.SchemaParseException: No field name: {"type":"map","values":"long"}
    at org.Apache.avro.Schema.getRequiredText(Schema.Java:1305)
    at org.Apache.avro.Schema.parse(Schema.Java:1192)
    at org.Apache.avro.Schema$Parser.parse(Schema.Java:965)
    at org.Apache.avro.Schema$Parser.parse(Schema.Java:932)
    at org.Apache.avro.tool.SpecificCompilerTool.run(SpecificCompilerTool.Java:73)
    at org.Apache.avro.tool.Main.run(Main.Java:84)
    at org.Apache.avro.tool.Main.main(Main.Java:73)

不明なオプションのフィールドを柔軟に処理できるJSON文字列をAvro形式で格納する方法はありますか?

基本的に、これはスキーマの進化の問題です。Sparkは スキーマのマージ =。Hadoopを使用した解決策を探しています。

12
soulmachine

マップタイプは、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"}}
  ]
}
16
oakad