avro附带了一个名为avro tools的工具,可以用来在json、avro模式(.avsc)和二进制格式之间进行转换。但它不适用于循环引用。
我们有两个文件:
circular.avsc(由avro生成)
json(由jackson生成,因为它有循环引用,而avro不喜欢循环引用)。
圆形.avsc
{
"type":"record",
"name":"Parent",
"namespace":"bigdata.example.avro",
"fields":[
{
"name":"name",
"type":[
"null",
"string"
],
"default":null
},
{
"name":"child",
"type":[
"null",
{
"type":"record",
"name":"Child",
"fields":[
{
"name":"name",
"type":[
"null",
"string"
],
"default":null
},
{
"name":"parent",
"type":[
"null",
"Parent"
],
"default":null
}
]
}
],
"default":null
}
]
}
循环.json
{
"@class":"bigdata.example.avro.Parent",
"@circle_ref_id":1,
"name":"parent",
"child":{
"@class":"bigdata.example.avro.DerivedChild",
"@circle_ref_id":2,
"name":"hello",
"parent":1
}
}
命令在上面运行avro工具
java-jar avro-tools-1.7.6.jar fromjson--模式文件circular.avsc circular.json
输出
2014-06-09 14:29:17.759 java[55860:1607]无法从scdynamicstore objavro.codenullavro.schema加载领域Map信息?{“type“:”record“,”name“:”parent“,”namespace“:”bigdata.example.avro“,”fields“:[{”name“:”name“,”type“:[”null“,”string“,”default“:”null},{”name“,”child“,”type“,”record“,”name“:”child“,”fields“:[{”name“:”name“,”type“:[”null“,”string“,”default“:”null},{”name“:”parent“,”type“:[”null“,”parent“,”default“:”null}],“default”:null}]}?'???k?jh!??ė?线程“main”org.apache.avro.avrotypeexception中出现异常:应为start union。在org.apache.avro.io.jsondecoder.error(jsondecoder。java:697)
在org.apache.avro.io.jsondecoder.readindex(jsondecoder。java:441)
在org.apache.avro.io.resolvingdecoder.doaction(resolvingdecoder。java:229)
其他一些json值尝试使用相同的模式,但不起作用
json 1号
{
"name":"parent",
"child":{
"name":"hello",
"parent":null
}
}
json 2公司
{
"name":"parent",
"child":{
"name":"hello",
}
}
json 3公司
{
"@class":"bigdata.example.avro.Parent",
"@circle_ref_id":1,
"name":"parent",
"child":{
"@class":"bigdata.example.avro.DerivedChild",
"@circle_ref_id":2,
"name":"hello",
"parent":null
}
}
删除一些“可选”元素:
圆形.avsc
{
"type":"record",
"name":"Parent",
"namespace":"bigdata.example.avro",
"fields":[
{
"name":"name",
"type":
"string",
"default":null
},
{
"name":"child",
"type":
{
"type":"record",
"name":"Child",
"fields":[
{
"name":"name",
"type":
"string",
"default":null
},
{
"name":"parent",
"type":
"Parent",
"default":null
}
]
},
"default":null
}
]
}
循环.json
{
"@class":"bigdata.example.avro.Parent",
"@circle_ref_id":1,
"name":"parent",
"child":{
"@class":"bigdata.example.avro.DerivedChild",
"@circle_ref_id":2,
"name":"hello",
"parent":1
}
}
输出
2014-06-09 15:30:53.716 java[56261:1607]无法从scdynamicstore objavro.codenullavro.schema加载领域Map信息?{“type”:“record”,“name”:“parent”,“namespace”:“bigdata.example.avro”,“fields”:[{“name”:“name”,“type”:“string”,“default”:null},{“name”:“child”,“type”:{“type”:“record”,“name”:“child”,“fields”:[{“name”:“name”,“type”:“string”,“default”:null},{“name”:“parent”,“type”:“parent”,“default”:null}]},“default”:null}]}?x?n??o?m?`abexception in thread“main”java.lang.stackoverflowerror
在org.apache.avro.io.parsing.symbol.flattedSize(symbol。java:212)
在org.apache.avro.io.parsing.symbol$sequence.flattedSize(symbol。java:323)
在org.apache.avro.io.parsing.symbol.flattedSize(symbol。java:216)
在org.apache.avro.io.parsing.symbol$sequence.flattedSize(symbol。java:323)
在org.apache.avro.io.parsing.symbol.flattedSize(symbol。java:216)
在org.apache.avro.io.parsing.symbol$sequence.flattedSize(symbol。java:323)
有人知道我怎样才能使循环引用与avro一起工作吗?
1条答案
按热度按时间bjg7j2ky1#
我最近也遇到了同样的问题,并以一种变通的方式解决了,希望能有所帮助。
基于avro规范:
json编码除了联合之外,json编码与用于编码字段默认值的编码相同。
union的值用json编码,如下所示:
如果它的类型是null,那么它被编码为json null;
否则,它被编码为一个json对象,具有一个名称/值对,其名称是类型的名称,其值是递归编码的值。对于avro的命名类型(record、fixed或enum),使用用户指定的名称,对于其他类型,使用类型名称。
例如,联合模式[“null”,“string”,“foo”],其中foo是一个记录名,将编码:
空为空;
字符串“a”为{“string”:“a”};
foo示例为{“foo”:{…},其中{…}表示foo示例的json编码。
如果源文件不能按照要求更改,可能我们必须更改代码。因此,我从avro-1.7.7包中定制了原始的org.apache.avro.io.jsondecoder类,并创建了自己的类myjsondecoder。
这是除了创建新构造函数和类名之外,我更改的关键字:
generate的思想是检查源文件中的类型是否在union中找到。
这里还有一些问题:
此解决方案不支持“record”、“enum”或“fixed”avro类型,因为这些类型需要用户定义的名称。e、 g.如果您想要联合“type”:[“null”,{“name”:“”,“type”:“record”,“fields”:…}],此代码将不起作用。对于基元类型,应该可以这样做。但是在你把它用于你的项目之前,请先测试一下。
就我个人而言,我认为记录不应该是空的,因为我认为记录是我需要确保存在的,如果缺少了什么,那就意味着我有更大的问题。如果可以省略的话,我更喜欢使用“map”作为类型,而不是在定义模式时使用“record”。
希望这能有所帮助。