Как использовать avro данные со старым и новым пространством имен
Я столкнулся с проблемой, когда я обновил пространство имен в моем файле схемы avsc. Так как мы использовали общий процессор, созданный в Java, для разбора XML на avro и использовали файл avsc.
Мы разделили интерфейсы и создали 2 разных пространства имен, и теперь имеем 2 одинаковые схемы avsc, только пространство имен отличается.
Поскольку у нас есть данные, которые были созданы с использованием старого пространства имен, я не могу запросить эти данные с новыми данными, сгенерированными с новым пространством имен.
Вот пример моей схемы -
Старая схема - "type" : "record",
"name" : "Message",
"namespace" : "com.myfirstavsc",
"fields" : [ {
"name" : "Header",.....**other fields**
Новая схема - "type" : "record",
"name" : "Message",
"namespace" : "com.mysecondavsc",
"fields" : [ {
"name" : "Header",.....**other fields**
Когда я запрашиваю свою таблицу улья, я получаю исключение ниже
Failed with exception java.io.IOException:org.apache.avro.AvroTypeException: Found com.myfirstavsc.Property, expecting union
2 ответа
Я не уверен, как вы пытаетесь прочитать ваши данные, но использование GenericDatumReader должно решить вашу проблему, после чего вы можете преобразовать общую запись в ваши конкретные записи. Я нашел что-то подобное здесь
http://apache-avro.679487.n3.nabble.com/Deserialize-with-different-schema-td4032782.html
http://apache-avro.679487.n3.nabble.com/Deserialize-with- Different-schema-td4032782.html
Ссылка, упомянутая выше, больше не работает, поэтому добавьте объяснение здесь.
Мы получили ту же ошибку в проекте под названием Hudi, поэтому подняли проблему по этому поводу: https://github.com/apache/hudi/issues/7284 .
После устранения неполадок основная причина этого исключенияorg.apache.avro.AvroTypeException: Found hoodie.test_mor_tab.test_mor_tab_record.new_test_col.fixed, expecting union
является правилом генератора схемы Avro, оно не может принять изменение пространства имен при обработкеUNION
тип.
Согласно документу Avro Schema Resolution , он может принять эволюцию схемы, если какая-либо схема является объединением в схеме чтения или записи в схеме.GenericDatumReader(Schema writer, Schema reader)
. Но он не упомянул, что есть еще одно ограничение: полное имя схемы должно быть таким же, если типRECORD
илиENUM
илиFIXED
.
Ссылка на код:
ResolvingGrammarGenerator#bestBranch
public class ResolvingGrammarGenerator extends ValidatingGrammarGenerator {
...
private int bestBranch(Schema r, Schema w, Map<LitS, Symbol> seen) throws IOException {
Schema.Type vt = w.getType();
// first scan for exact match
int j = 0;
int structureMatch = -1;
for (Schema b : r.getTypes()) {
if (vt == b.getType())
if (vt == Schema.Type.RECORD || vt == Schema.Type.ENUM ||
vt == Schema.Type.FIXED) {
String vname = w.getFullName();
String bname = b.getFullName();
// return immediately if the name matches exactly according to spec
if (vname != null && vname.equals(bname))
return j;
if (vt == Schema.Type.RECORD &&
!hasMatchError(resolveRecords(w, b, seen))) {
String vShortName = w.getName();
String bShortName = b.getName();
// use the first structure match or one where the name matches
if ((structureMatch < 0) ||
(vShortName != null && vShortName.equals(bShortName))) {
structureMatch = j;
}
}
} else
return j;
j++;
}
// if there is a record structure match, return it
if (structureMatch >= 0)
return structureMatch;
// then scan match via numeric promotion
j = 0;
for (Schema b : r.getTypes()) {
switch (vt) {
case INT:
switch (b.getType()) {
case LONG: case DOUBLE:
return j;
}
break;
case LONG:
case FLOAT:
switch (b.getType()) {
case DOUBLE:
return j;
}
break;
case STRING:
switch (b.getType()) {
case BYTES:
return j;
}
break;
case BYTES:
switch (b.getType()) {
case STRING:
return j;
}
break;
}
j++;
}
return -1;
}
...
}