Схема Avro не учитывает псевдоним в определении схемы

#python #avro

Вопрос:

Avro schema schema.avsc :

 {
    "namespace": "standard",
    "type": "record",
    "name": "agent",
    "aliases":["agents"],
    "fields": [
        {
            "name": "id",
            "type": ["string", "null"]
        },
        {
            "name": "name",
            "type": ["string", "null"],
            "aliases":["title", "nickname"]
        }
    ]
}
 

Скрипт на Python main.py :

 from fastavro import writer, reader
from fastavro.schema import load_schema

schema = load_schema('schema.avsc')
avro_data = 'agent.avro'
data = jsonlines.open('data.jsonl')

with open(avro_data, 'wb') as fout:
    writer(fout, schema, data, validator=True)

with open(avro_data, 'rb') as fin:
    for i in reader(fin, schema):
        print(i)
 

Когда мой data.jsonl файл строк json выглядит следующим образом:

 {"id":"1","name":"foo"}
{"id":"2","name":"bar"}
 

Мой скрипт на python возвращает:

 {'id': '1', 'name': 'foo'}
{'id': '2', 'name': 'bar'}
 

Однако, если мой data.jsonl файл строк json выглядит следующим образом:

 {"id":"1","title":"foo"}
{"id":"2","title":"bar"}
 

Мой скрипт на python возвращает:

 {'id': '1', 'name': None}
{'id': '2', 'name': None}
 

Есть идеи, почему name столбец не соответствует aliases атрибуту, который я определил в файле схемы avro для этого конкретного поля?

Ответ №1:

Псевдонимы используются, когда у вас есть данные, записанные по старой схеме, которые вы хотите прочитать по новой схеме. В вашем примере используется только одна схема, поэтому псевдонимы не будут работать только с одной схемой.

Давайте в качестве примера воспользуемся следующими двумя схемами. Вот «старая» схема, которая использует title поле:

old_schema.avsc

 {
    "namespace": "standard",
    "type": "record",
    "name": "agent",
    "aliases":["agents"],
    "fields": [
        {
            "name": "id",
            "type": ["string", "null"]
        },
        {
            "name": "title",
            "type": ["string", "null"]
        }
    ]
}
 

И новая схема, в которой мы хотим, чтобы новое name поле было псевдонимом старого title поля:

new_schema.avsc

 {
    "namespace": "standard",
    "type": "record",
    "name": "agent",
    "aliases":["agents"],
    "fields": [
        {
            "name": "id",
            "type": ["string", "null"]
        },
        {
            "name": "name",
            "type": ["string", "null"],
            "aliases":["title"]
        }
    ]
}
 

Если мы используем вашу вторую data.jsonl , которая выглядит так:

 {"id":"1","title":"foo"}
{"id":"2","title":"bar"}
 

Затем мы можем использовать слегка измененную версию вашей main.py , чтобы данные записывались со старой схемой, а затем передавалась новая схема reader , чтобы соблюдались псевдонимы:

 from fastavro import writer, reader
from fastavro.schema import load_schema
import jsonlines

old_schema = load_schema('old_schema.avsc')
new_schema = load_schema('new_schema.avsc')
avro_data = 'agent.avro'
data = jsonlines.open('data.jsonl')

# Data is writen with old schema
with open(avro_data, 'wb') as fout:
    writer(fout, old_schema, data, validator=True)

# And read with new schema
with open(avro_data, 'rb') as fin:
    for i in reader(fin, new_schema):
        print(i)
 

Теперь вывод правильный:

 {'id': '1', 'name': 'foo'}
{'id': '2', 'name': 'bar'}