web-dev-qa-db-ja.com

予想される開始ユニオンを修正する方法。コマンドラインでJSONをAvroに変換するときにVALUE_NUMBER_INTを取得しましたか?

Avroスキーマを使用してJSONファイルを検証し、対応するAvroファイルを書き込もうとしています。まず、user.avscという名前の次のAvroスキーマを定義しました。

{"namespace": "example.avro",
 "type": "record",
 "name": "user",
 "fields": [
     {"name": "name", "type": "string"},
     {"name": "favorite_number",  "type": ["int", "null"]},
     {"name": "favorite_color", "type": ["string", "null"]}
 ]
}

次に、user.jsonファイルを作成しました:

{"name": "Alyssa", "favorite_number": 256, "favorite_color": null}

そして、実行しようとしました:

Java -jar ~/bin/avro-tools-1.7.7.jar fromjson --schema-file user.avsc user.json > user.avro

しかし、次の例外が発生します。

Exception in thread "main" org.Apache.avro.AvroTypeException: Expected start-union. Got VALUE_NUMBER_INT
    at org.Apache.avro.io.JsonDecoder.error(JsonDecoder.Java:697)
    at org.Apache.avro.io.JsonDecoder.readIndex(JsonDecoder.Java:441)
    at org.Apache.avro.io.ResolvingDecoder.doAction(ResolvingDecoder.Java:290)
    at org.Apache.avro.io.parsing.Parser.advance(Parser.Java:88)
    at org.Apache.avro.io.ResolvingDecoder.readIndex(ResolvingDecoder.Java:267)
    at org.Apache.avro.generic.GenericDatumReader.read(GenericDatumReader.Java:155)
    at org.Apache.avro.generic.GenericDatumReader.readField(GenericDatumReader.Java:193)
    at org.Apache.avro.generic.GenericDatumReader.readRecord(GenericDatumReader.Java:183)
    at org.Apache.avro.generic.GenericDatumReader.read(GenericDatumReader.Java:151)
    at org.Apache.avro.generic.GenericDatumReader.read(GenericDatumReader.Java:142)
    at org.Apache.avro.tool.DataFileWriteTool.run(DataFileWriteTool.Java:99)
    at org.Apache.avro.tool.Main.run(Main.Java:84)
    at org.Apache.avro.tool.Main.main(Main.Java:73)

何か不足していますか? 「予期した開始ユニオン。VALUE_NUMBER_INTを取得しました」と表示されるのはなぜですか。

20
Emre Sevinç

ダグ・カッティングによる説明 によれば、

AvroのJSONエンコーディングでは、null以外のunion値に目的のタイプのタグを付ける必要があります。これは、["bytes"、 "string"]や["int"、 "long"]などのユニオンがJSONではあいまいであるため、最初のユニオンは両方ともJSON文字列としてエンコードされ、2番目のユニオンは両方ともJSON番号としてエンコードされます。

http://avro.Apache.org/docs/current/spec.html#json_encoding

したがって、レコードは次のようにエンコードする必要があります。

{"name": "Alyssa", "favorite_number": {"int": 7}, "favorite_color": null}
32
Emre Sevinç

この一般的な問題に対処する必要がある作業に新しいJSONエンコーダーがあります。

https://issues.Apache.org/jira/browse/AVRO-1582

https://github.com/zolyfarkas/avro

10
ppearcy

ユニオンとその検証を実装しました。ユニオンスキーマを作成し、その値をpostmanに渡します。 resgistry urlは、kafkaのプロパティに指定するURLです。uは動的な値をスキーマに渡すこともできます。

RestTemplate template = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<String>(headers);
        ResponseEntity<String> response = template.exchange(""+registryUrl+"/subjects/"+topic+"/versions/"+version+"", HttpMethod.GET, entity, String.class);
        String responseData = response.getBody();
        JSONObject jsonObject = new JSONObject(responseData);
        JSONObject jsonObjectResult = new JSONObject(jsonResult);
        String getData = jsonObject.get("schema").toString();
        Schema.Parser parser = new Schema.Parser();
        Schema schema = parser.parse(getData);
        GenericRecord genericRecord = new GenericData.Record(schema);
        schema.getFields().stream().forEach(field->{
            genericRecord.put(field.name(),jsonObjectResult.get(field.name()));
        });
        GenericDatumReader<GenericRecord>reader = new GenericDatumReader<GenericRecord>(schema);
        boolean data = reader.getData().validate(schema,genericRecord );
2
Tanmay Naik

@ Emre-Sevincが指摘したように、問題はAvroレコードのエンコードにあります。

ここでより具体的に説明します。

これを行わないでください:

   jsonRecord = avroGenericRecord.toString

代わりに、次のようにします。

    val writer = new GenericDatumWriter[GenericRecord](avroSchema)
    val baos = new ByteArrayOutputStream
    val jsonEncoder = EncoderFactory.get.jsonEncoder(avroSchema, baos)
    writer.write(avroGenericRecord, jsonEncoder)
    jsonEncoder.flush

    val jsonRecord = baos.toString("UTF-8")

次のインポートも必要です。

import org.Apache.avro.Schema
import org.Apache.avro.generic.{GenericData, GenericDatumReader, GenericDatumWriter, GenericRecord}
import org.Apache.avro.io.{DecoderFactory, EncoderFactory}

これを実行すると、目的の型でタグ付けされたnull以外のunion値を含むjsonRecordが得られます。

お役に立てれば !

0