有一个名为Avro-Tools的工具,它随Avro一起提供,可以用来在JSON、Avro-Schema(.avsc)和二进制格式之间进行转换。但它不能用于循环引用。
我们有两个文件:
>
循环.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
}
]
}
circular.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-tools的命令
Java-jar avro-tools-1.7.6.jar fromjson--schema-file circular.avsc circular.json
输出
2014-06-09 14:29:17.759 Java[55860:1607]无法从SCDynamicStore objavro.codeNullavro.schema加载领域映射信息?{“type”:“record”,“name”:“parent”,“namespace”:“bigdata.example.avro”,“fields”:[{“name”:“name”,“type”:[“null”,“string”],“default”:null},{“name”:“child”,“type”:[“null”,“child”,“fields”:[{“name”:“name”,“default”:null},“default”:null},{“nype”:“record”,“name”:“在org.apache.avro.io.jsonDecoder.error处获得VALUE_STRING(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
}
]
}
circular.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加载领域映射信息?{“type”:“record”,“name”:“parent”,“namespace”:“bigdata.example.avro”,“fields”:[{“name”:“name”,“type”:“string”,“default”:null},{“name”:“child”,“type”:{“type”:“child”,“fields”:[{“name”:“name”
在org.apache.avro.io.parsing.symbol.FlatenedSize(符号.java:212)
在org.apache.avro.io.parsing.symbol$sequence.flattenedsize(Symbol.java:323)
在org.apache.avro.io.parsing.symbol.FlatenedSize(符号.java:216)
在org.apache.avro.io.parsing.symbol$sequence.flattenedsize(Symbol.java:323)
在org.apache.avro.io.parsing.symbol.FlatenedSize(符号.java:216)
在org.apache.avro.io.parsing.symbol$sequence.flattenedsize(Symbol.java:323)
有没有人知道我如何让循环参考与Avro一起工作?
我最近遇到了同样的问题,并以一种变通的方式解决了这个问题,希望它能起到帮助作用。
基于Avro规范:
JSON编码除了联合之外,JSON编码与用于编码字段默认值的编码相同。
union的值在JSON中编码如下:
例如,联合模式[“null”,“string”,“Foo”](其中Foo是记录名)将编码:
如果源文件不能被改变以符合要求,也许我们不得不改变代码。所以我从avro-1.7.7包中定制了原始的org.apache.avro.io.JsonDecoder类,并创建了自己的类MyJsonDecoder。
下面是除了创建新的构造函数和类名之外,我更改的键:
@Override
public int readIndex() throws IOException {
advance(Symbol.UNION);
Symbol.Alternative a = (Symbol.Alternative) parser.popSymbol();
String label;
if (in.getCurrentToken() == JsonToken.VALUE_NULL) {
label = "null";
//***********************************************
// Original code: according to Avor document "JSON Encoding":
// it is encoded as a Json object with one name/value pair whose name is
// the type's name and whose value is the recursively encoded value.
// Can't change source data, so remove this rule.
// } else if (in.getCurrentToken() == JsonToken.START_OBJECT &&
// in.nextToken() == JsonToken.FIELD_NAME) {
// label = in.getText();
// in.nextToken();
// parser.pushSymbol(Symbol.UNION_END);
//***********************************************
// Customized code:
// Add to check if type is in the union then parse it.
// Check if type match types in union or not.
} else {
label = findTypeInUnion(in.getCurrentToken(), a);
// Field missing but not allow to be null
// or field type is not in union.
if (label == null) {
throw error("start-union, type may not be in UNION,");
}
}
//***********************************************
// Original code: directly error out if union
// } else {
// throw error("start-union");
// }
//***********************************************
int n = a.findLabel(label);
if (n < 0)
throw new AvroTypeException("Unknown union branch " + label);
parser.pushSymbol(a.getSymbol(n));
return n;
}
/**
* Method to check if current JSON token type is declared in union.
* Do NOT support "record", "enum", "fix":
* Because there types require user defined name in Avro schema,
* if user defined names could not be found in Json file, can't decode.
*
* @param jsonToken JsonToken
* @param symbolAlternative Symbol.Alternative
* @return String Parsing label, decode in which way.
*/
private String findTypeInUnion(final JsonToken jsonToken,
final Symbol.Alternative symbolAlternative) {
// Create a map for looking up: JsonToken and Avro type
final HashMap<JsonToken, String> json2Avro = new HashMap<>();
for (int i = 0; i < symbolAlternative.size(); i++) {
// Get the type declared in union: symbolAlternative.getLabel(i).
// Map the JsonToken with Avro type.
switch (symbolAlternative.getLabel(i)) {
case "null":
json2Avro.put(JsonToken.VALUE_NULL, "null");
break;
case "boolean":
json2Avro.put(JsonToken.VALUE_TRUE, "boolean");
json2Avro.put(JsonToken.VALUE_FALSE, "boolean");
break;
case "int":
json2Avro.put(JsonToken.VALUE_NUMBER_INT, "int");
break;
case "long":
json2Avro.put(JsonToken.VALUE_NUMBER_INT, "long");
break;
case "float":
json2Avro.put(JsonToken.VALUE_NUMBER_FLOAT, "float");
break;
case "double":
json2Avro.put(JsonToken.VALUE_NUMBER_FLOAT, "double");
break;
case "bytes":
json2Avro.put(JsonToken.VALUE_STRING, "bytes");
break;
case "string":
json2Avro.put(JsonToken.VALUE_STRING, "string");
break;
case "array":
json2Avro.put(JsonToken.START_ARRAY, "array");
break;
case "map":
json2Avro.put(JsonToken.START_OBJECT, "map");
break;
default: break;
}
}
// Looking up the map to find out related Avro type to JsonToken
return json2Avro.get(jsonToken);
}
生成的思想是检查源文件中的类型是否可以在union中找到。
这里还有一些问题:
>
此解决方案不支持“record”、“enum”或“fixed”Avro类型,因为这些类型需要用户定义名称。例如。如果要联合“type”:[“null”,{“name”:“abc”,“type”:“record”,“fields”:...}],则此代码将不起作用。对于基元类型,这应该起作用。但请在您将其用于您的项目之前对其进行测试。
就我个人而言,我认为记录不应该是空的,因为我认为记录是我需要确保存在的,如果缺少了什么,那意味着我有更大的问题。如果可以省略,我更喜欢在定义模式时使用“map”作为类型,而不是使用“record”。
希望这能有所帮助。
下面是我的父组件,它包含一个循环的多个输入。如何选择一个来聚焦?在这种情况下,我必须创建动态吗?
问题内容: 我正在尝试在某些类图中围绕类生成运行时包装,但是当图中有一个循环时,我不知道如何处理这种情况。想象有一个类A的字段类型为B,但是类型B的字段类型为A。我想生成类A’和B’,以便类A’的字段类型为B’,而B’的字段类型为B。 A’类型的字段。在字节伙伴中,方法“ defineField”可以接收类型定义的参数。我认为必须有一种方法可以为尚未定义的类型定义TypeDefinition,但我
这里是一个以圆圈为单位的交叉网格,当前为5x5。我试图得到一行5,下面是一行4,然后是3,然后是2等等。我试着改变for循环和值,但什么都不起作用。我需要使用行和列吗? 谢谢!
问题内容: 您使用哪种SQL技巧将数据输入到两个表之间,并在两个表之间使用循环引用。 员工属于部门,部门必须有经理(部门负责人)。 我是否必须禁用约束才能进行插入? 问题答案: 问: 是否必须禁用约束才能进行插入? 答: 在Oracle中,否,如果外键约束为否,则为否 (请参见下面的示例) 对于Oracle: 让我们解压一下: (必须禁用自动提交) 推迟执行外键约束 在“部门”表中插入一行,并为F
问题内容: 我有一个数组(称为),其中包含数百个天文学图像文件的名称。然后处理这些图像。我的代码有效,并且需要几秒钟来处理每个图像。但是,一次只能执行一张图像,因为我是通过循环运行阵列: 没有理由我必须先修改映像,因此可以利用计算机上的所有4个内核,每个内核都通过for循环在不同的映像上运行吗? 我已经阅读了有关该模块的信息,但是不确定如何在我的情况下实现它。我热衷于工作,因为最终我必须在10,0
问题内容: 给定一个以复杂的,循环的方式相互引用的类实例的集合:垃圾收集器是否可能无法释放这些对象? 我隐约记得过去这是JVM中的问题,但我 认为 这在几年前已解决。但是,在jhat中进行的一些调查显示,循环引用是我现在面临的内存泄漏的原因。 注意:我一直给人以JVM能够解析循环引用并从内存中释放这种“垃圾岛”的印象。 但是,我提出这个问题只是为了看看是否有人发现了任何异常。 问题答案: 循环引用