Python 转换 Apache Avro 数据为 Parquet 格式

前面尝试过用 Java 转换 Apache Avro 数据为 Parquet 格式,本文用 Python 来做同样的事情,并且加入 logicalType: date 类型的支持。本测试中的 Avro 数据也是由 Python 代码生成的。

重复一句 Avro 与 Parquet 的最粗略的区别:Avro 广泛的应用于数据的序列化,如 Kafka,它是基于行的格式,可被流式处理,而 Parquet 是列式存储格式的,适合于基于列的查询。

第一步,生成 Avro 数据文件 user.avro, 须先安装 fastavro
pip install fastavro

生成 user.avro 的代码

 1from datetime import date
 2
 3from fastavro import parse_schema, writer
 4
 5schema = {
 6    "namespace": "data",
 7    "type": "record",
 8    "name": "User",
 9    "fields": [
10        {"name": "id", "type": "int"},
11        {"name": "name", "type": "string"},
12        {"name": "birthday", "type": {"type": "int", "logicalType": "date"}}
13    ]
14}
15
16parsed_schema = parse_schema(schema)
17
18records = [
19    {'id': 100, 'name': 'Tom', 'birthday': date.today()},
20    {'id': 101, 'name': 'Jerry', 'birthday': date(2019, 4, 24)},
21]
22
23with open('user.avro', 'wb') as out:
24    writer(out, parsed_schema, records)

产生了一个 user.avro, 用 avro-tools 查看其中的数据与 schema
 1$ avro-tools getschema user.avro
 2{
 3  "type" : "record",
 4  "name" : "User",
 5  "namespace" : "data",
 6  "fields" : [ {
 7    "name" : "id",
 8    "type" : "int"
 9  }, {
10    "name" : "name",
11    "type" : "string"
12  }, {
13    "name" : "birthday",
14    "type" : {
15      "type" : "int",
16      "logicalType" : "date"
17    }
18  } ]
19}
20$ avro-tools tojson user.avro
21{"id":100,"name":"Tom","birthday":18747}
22{"id":101,"name":"Jerry","birthday":18010}

user.avro 数据文件中的 birthday 能识别为 logicalType: date 类型

转换 Avro 为 Parquet

先安装 pandas
pip install pyarrow pandas
转换代码
 1import pandas as pd
 2from fastavro import reader
 3
 4
 5def process(records):
 6    df = pd.DataFrame.from_records(records)
 7    df.to_parquet('user.parquet')
 8
 9
10with open('user.avro', 'rb') as fo:
11    avro_reader = reader(fo)
12    rs = [r for r in avro_reader]
13    process(rs)

用 parque-tools 查看生成的 user.parquet 文件的 schema 与数据
 1$ parquet-tools schema user.parquet
 2message schema {
 3  optional int64 id;
 4  optional binary name (STRING);
 5  optional int32 birthday (DATE);
 6}
 7
 8$ parquet-tools cat --json user.parquet
 9{"id":100,"name":"Tom","birthday":18747}
10{"id":101,"name":"Jerry","birthday":18010}

数据完全正确,并且 birthday 在 Parquet 的 schema 中仍然是 int32(DATE) 类型。

如果喜欢在 Python 中用 Apache 的 avro 库也没问题, 安装 avro
pip install avro
读取记录的代码如下
1from avro.datafile import DataFileReader
2from avro.io import DatumReader
3with open('user.avro', 'rb') as fo:
4    reader = DataFileReader(fo, DatumReader())
5    rs = [r for r in reader]
6    process(rs)

更简单的使用 pandavro 包读取 avro 文件的方式

安装 pyarrow 和 pandavro
pip install pyarrow pandavro
会连带安装多个包,用 pip freeze 看下
$ pip freeze
fastavro==1.4.0
numpy==1.20.2
pandas==1.2.4
pandavro==1.6.0
pyarrow==4.0.0
python-dateutil==2.8.1
pytz==2021.1
six==1.15.0
读取 avro 的代码
1import pandavro as pdx
2
3rs = pdx.from_avro('user.avro')
4process(rs)

最后汇总一下如何最简单的转换 Avro 文件为 Parquet 格式

须安装的插件
pip install pyarrow pandas
完整转换 avro 文件为 parquet 文件代码如下
1import pandas as pd
2import pandavro as pdx
3
4rs = pdx.from_avro('user.avro')
5df = pd.DataFrame.from_records(rs)
6df.to_parquet('user.parquet')

执行代码只须 3 行。代码中虽未显式导入 pyarrow, 但内部会用到,所以必须安装 pyarrow

链接:

  1. Big Data File Showdown - Avro vs Parquet with Python
永久链接 https://yanbin.blog/python-convert-avro-to-parquet/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。