Java 以编程方式合并两个avro模式
我有两个相似的模式,其中只有一个嵌套字段发生变化(在模式A1中称为Java 以编程方式合并两个avro模式,java,avro,Java,Avro,我有两个相似的模式,其中只有一个嵌套字段发生变化(在模式A1中称为onefield,在模式A2中称为anotherfield) schema1 { "type": "record", "name": "event", "namespace": "foo", "fields": [ { "name": "metadata", "type": { "type": "reco
onefield
,在模式A2中称为anotherfield
)
schema1
{
"type": "record",
"name": "event",
"namespace": "foo",
"fields": [
{
"name": "metadata",
"type": {
"type": "record",
"name": "event",
"namespace": "foo.metadata",
"fields": [
{
"name": "onefield",
"type": [
"null",
"string"
],
"default": null
}
]
},
"default": null
}
]
}
schema2
{
"type": "record",
"name": "event",
"namespace": "foo",
"fields": [
{
"name": "metadata",
"type": {
"type": "record",
"name": "event",
"namespace": "foo.metadata",
"fields": [
{
"name": "anotherfield",
"type": [
"null",
"string"
],
"default": null
}
]
},
"default": null
}
]
}
我能够使用avro 1.8.0以编程方式合并两种模式:
Schema s1 = new Schema.Parser().parse(schema1);
Schema s2 = new Schema.Parser().parse(schema2);
Schema[] schemas = {s1, s2};
Schema mergedSchema = null;
for (Schema schema: schemas) {
mergedSchema = AvroStorageUtils.mergeSchema(mergedSchema, schema);
}
并使用它将输入json转换为avro或json表示:
JsonAvroConverter converter = new JsonAvroConverter();
try {
byte[] example = new String("{}").getBytes("UTF-8");
byte[] avro = converter.convertToAvro(example, mergedSchema);
byte[] json = converter.convertToJson(avro, mergedSchema);
System.out.println(new String(json));
} catch (AvroConversionException e) {
e.printStackTrace();
}
该代码显示了预期的输出:{“元数据”:{“onefield”:null,“anotherfield”:null}
。问题是我无法看到合并的模式。如果我做一个简单的System.out.println(mergedSchema)
我会得到以下异常:
Exception in thread "main" org.apache.avro.SchemaParseException: Can't redefine: merged schema (generated by AvroStorage).merged
at org.apache.avro.Schema$Names.put(Schema.java:1127)
at org.apache.avro.Schema$NamedSchema.writeNameRef(Schema.java:561)
at org.apache.avro.Schema$RecordSchema.toJson(Schema.java:689)
at org.apache.avro.Schema$RecordSchema.fieldsToJson(Schema.java:715)
at org.apache.avro.Schema$RecordSchema.toJson(Schema.java:700)
at org.apache.avro.Schema.toString(Schema.java:323)
at org.apache.avro.Schema.toString(Schema.java:313)
at java.lang.String.valueOf(String.java:2982)
at java.lang.StringBuilder.append(StringBuilder.java:131)
我称之为avro测不准原理:)。看起来avro能够处理合并的模式,但在尝试将模式序列化为JSON时失败。合并可以使用更简单的模式,所以对我来说,它听起来像是AVRO1.8.0中的一个bug
你知道会发生什么或者如何解决它吗?欢迎使用任何变通方法(例如:alternative
Schema
Serializer)。我在pig util类中发现了相同的问题。。。实际上这里有两个bug
- AVRO允许使用无效架构通过GenericDatumWriter序列化数据
- piggybank util类正在生成无效的架构,因为它对所有合并字段使用相同的名称/命名空间(保留原始名称的实例)
{
"type": "record",
"name": "event",
"namespace": "foo",
"fields": [
{
"name": "metadata",
"type": {
"type": "record",
"name": "event",
"namespace": "foo.metadata",
"fields": [
{
"name": "onefield",
"type": [
"null",
"string"
],
"default": null
},
{
"name": "anotherfield",
"type": [
"null",
"string"
],
"default": null
}
]
},
"default": null
}
]
}
希望这能帮助其他人 avro文件尚不支持合并架构功能。 但假设您在一个目录中有多个avro文件,这些文件具有不同的模式,例如:/demo,这样您就可以使用spark来读取它。并提供一个主模式文件(即avsc文件),这样spark将在内部读取该文件中的所有记录,如果任何一个文件缺少列,那么它将显示空值
object AvroSchemaEvolution {
def main(args: Array[String]): Unit = {
val schema = new Schema.Parser().parse(new File("C:\\Users\\murtazaz\\Documents\\Avro_Schema_Evolution\\schema\\emp_inserted.avsc"))
val spark = SparkSession.builder().master("local").getOrCreate()
val df = spark.read
.format("com.databricks.spark.avro").option("avroSchema", schema.toString)
.load("C:\\Users\\murtazaz\\Documents\\Avro_Schema_Evolution\\demo").show()
}
}
这似乎也发生在avro(1.7.6)的早期版本中,谢谢@lake。我不能尝试,但它看起来真的很好。
object AvroSchemaEvolution {
def main(args: Array[String]): Unit = {
val schema = new Schema.Parser().parse(new File("C:\\Users\\murtazaz\\Documents\\Avro_Schema_Evolution\\schema\\emp_inserted.avsc"))
val spark = SparkSession.builder().master("local").getOrCreate()
val df = spark.read
.format("com.databricks.spark.avro").option("avroSchema", schema.toString)
.load("C:\\Users\\murtazaz\\Documents\\Avro_Schema_Evolution\\demo").show()
}
}