事情で表記のようなことを考える必要があり、Parquetをちょっと調べています。
とりあえず、使いたい言語がPythonだったこと、Pandas等とも連携できることを考えて、Apache ArrowのPython bindingを使ってみることにしました。
参考情報
- Apache Parquet 公式サイトのHigh Level Document
- 物理pフォーマット(の概要)の解説も出ています。
- Apache Arrow ドキュメント
- Apache Arrow(PyArrow)を使って簡単かつ高速にParquetファイルに変換する
- Athena の CTAS (Create Table AS)では、デフォルトではParquetで保存されるらしい。
- Python: Apache Parquet フォーマットを扱ってみる
- Conversion of JSON to parquet format using Apache Parquet in JAVA
- Javaの場合
インストール
大人の事情でCentOS7系で動作確認したかったので、Pythonは(未だに)2.7系を使っています(苦笑)
Apache Arrow自体は新しいものを使いたかったので、virtualenv を使って以下のようにお手軽に作成しました。
$ virtualenv venvs/arrow
$ source venvs/arrow/bin/activate
$ pip install pyarrow
とりあえずやってみたこと
以下のようなテストデータを作って
{
"key1": 1,
"key2": "value2-1",
"key3": ["value3-1", "value3-1"]
}
以下のようなプログラムで試しました。
import pyarrow.parquet as pq
from pyarrow import json as pajson
table = pajson.read_json('test.json')
print('==================write table')
pq.write_table(table, 'test.parquet')
print('==================using parquet.read_schema')
schema = pq.read_schema('test.parquet')
print(schema)
実行するとこんな感じになります。
$ python test.py
==================write table
==================using parquet.read_schema
key1: int64
key2: string
key3: list<item: string>
child 0, item: string
metadata
--------
OrderedDict([('ARROW:schema', '/////wgBAAAQAAAAAAAKAAwABgAFAAgACgAAAAABAwAMAAAACAAIAAAABAAIAAAABAAAAAMAAACcAAAAXAAAAAQAAACA////AAABDEAAAAAQAAAABAAAAAEAAAAIAAAAsP///6D///8AAAEFFAAAAAwAAAAEAAAAAAAAAMz///8EAAAAaXRlbQAAAAAEAAAAa2V5MwAAAADU////AAABBRgAAAAQAAAABAAAAAAAAAAEAAQABAAAAAQAAABrZXkyAAAAABAAFAAIAAYABwAMAAAAEAAQAAAAAAABAiQAAAAUAAAABAAAAAAAAAAIAAwACAAHAAgAAAAAAAABQAAAAAQAAABrZXkxAAAAAAAAAAA=')])
後述の通り、先にスキーマを作らなくても動くのかどうか確認したかったのですが、入力に従ったスキーマが作成されているようです。
余談ですが、1レコードしかないので、サイズはこんな感じになりますね(苦笑)
$ du -b test.json test.parquet
80 test.json
232 test.parquet
TODO
- 圧縮を試す
- 複数レコード格納する
- 後述のトップレベル名無し配列の件も調べる
- 事前にスキーマを定義した場合と動的に作成させた場合の違いの確認
- スキーマにないelementが現れた場合の挙動の確認
TIPS(というか気づいたことのメモ)
スキーマは事前に準備しなくても動く
確かに動くのですが、これで最適なのか、確認要。(TBD)
pyarrow.json では Objectのネストはできない
以下の例では "key4"の値はさらにObject(Pythonではdcit)になっていますが、これはpyarrow.json.read_json()
に食わせるとエラーになるようです。
{
"key1": 1,
"key2": "value2-1",
"key3": [
"value3-1",
"value3-1"
],
"key4": {
"key41": 4,
"key42": "value42"
}
}
JSONで許されているトップレベルの名無しArrayは通らない
JSONの規格上、以下のようなデータは許されているのですが、
[
{
"key1": 1,
"key2": "value2-1",
"key3": [
"value3-1",
"value3-1"
]
},
{
"key1": 2,
"key2": "value2-2",
"key3": [
"value3-2",
"value3-2"
]
}
]
しかし、こんな感じでエラーになります。 これは、Arrayの要素を1つに減らしても同じです。
$ python test.py
Traceback (most recent call last):
File "test.py", line 6, in <module>
table = pajson.read_json('test3.json')
File "pyarrow/_json.pyx", line 193, in pyarrow._json.read_json
File "pyarrow/error.pxi", line 84, in pyarrow.lib.check_status
pyarrow.lib.ArrowInvalid: JSON parse error: Column() changed from object to array in row 0
続きます。