Parquetのスキーマを考える時などに使える型と、それがどのような形で保存されるかの一覧が欲しくなったので作る。以下の仕様書の内容をもとに、より一覧性の高い形にまとめたもの。
基礎知識
Parquetファイル内で使用される型(Physical Types)は8種類しかない。
それ以外の型は、これらの型の解釈を変えたり(uint8等)、組み合わせたり(list等)する形で表現される。
解釈を変えることによって実現されている型にはConverted TypesとLogical Typesがある。
Logical Typesは新しくできたもので、昔はConverted TypesがLogical Typesと呼ばれていたらしい。
このような型はデータの形式自体は元の型(Physical Types)のままで、どう解釈すべきかの情報がメタデータとして付与される。
Physical Typesが同じLogical Typesはファイル内で同じように保存されるため、(Writerが特別な最適化をしない限り)サイズは変わらない。
以下で実際にint8(int32の別解釈)で保存できる値をint32で保存してみてサイズを比較してみたが、サイズは変わらないどころかint8のほうがちょっと増えてしまった。
おそらくLogical Typesのメタデータである構造体の分が増えてしまったのだと思われる。
注目すべき点として、compression=Noneで作成したファイルのサイズを要素数で割ると1要素当たり約 0.89 バイトであり、int8のサイズである1バイトよりも小さい。
Parquetの整数は型のサイズではなく、実際の値に応じてサイズが決まる効率的なエンコードがされている。
既にわりと効率的なエンコードがされているので、gzip圧縮をかけてもあまりサイズは変わっていない(88740 → 88474)。
もちろん読み出すときにはint8としてメモリ上に展開されるので、値の特性上8ビット整数として取り扱うことが適切ならばint8にした方が良い。
ただ、ファイルサイズを削減することだけを目的にしてint8にする意味はあまりない。
import os
import numpy as np
import pyarrow as pa
import pyarrow.parquet as pq
arr = np.random.randint(0, 127, size=100000)
table1 = pa.table({'v': pa.array(arr, type=pa.int32())}) # Physical type
table2 = pa.table({'v': pa.array(arr, type=pa.int8())}) # Logical type (int8 -> int32)
# 無圧縮で保存
pq.write_table(table1, 'plain.parquet', compression=None)
pq.write_table(table2, 'int8.parquet', compression=None)
print(os.path.getsize('plain.parquet')) # 88740
print(os.path.getsize('int8.parquet')) # 88749
# 圧縮して保存
pq.write_table(table1, 'plain.parquet', compression='GZIP')
pq.write_table(table2, 'int8.parquet', compression='GZIP')
print(os.path.getsize('plain.parquet')) # 88474
print(os.path.getsize('int8.parquet')) # 88483
データ型の一覧
Physical Types
Parquetファイル内の実際の保存形式であるPhysical Typesの一覧。
| 型名 | 説明 |
|---|---|
| BOOLEAN | 1ビットのブール値 |
| INT32 | 32ビット符号付き整数 |
| INT64 | 64ビット符号付き整数 |
| 96ビット符号付き整数 (deprecated) | |
| FLOAT | IEEE 32ビット浮動小数点数 |
| DOUBLE | IEEE 64ビット浮動小数点数 |
| BYTE_ARRAY | 任意長バイト配列 |
| FIXED_LEN_BYTE_ARRAY | 固定長バイト配列 |
Logical Types / Converted Types
Physical Typesをどのように解釈するかを示す型の一覧。
Converted TypesはDeprecatedとなっている仕様で、現在はより表現力の高いLogical Typesが推奨されている。
ただし、互換性のために一部のLogical TypesはConverted Typesとの対応物とされ、Writerは両方の情報を付与する必要がある。
この表では仕様に書かれているLogical Typesの一覧を掲載し、対応するConverted Typesがある場合は併記するという形式をとっている。
| Logical Type | Physical Type | Converted Type | 説明 |
|---|---|---|---|
STRING |
BYTE_ARRAY |
UTF8 |
UTF8エンコードされた文字列 |
ENUM |
BYTE_ARRAY |
- | 列挙型1 |
UUID |
FIXED_LEN_BYTE_ARRAY[len=16] |
- | UUID |
IntType [bit_width=8, signed=true] 2
|
INT32 |
INT_8 |
8ビット符号付き整数 |
IntType [bit_width=16, signed=true] |
INT32 |
INT_16 |
|
IntType [bit_width=32, signed=true] |
INT32 |
INT_32 |
32ビット符号付き整数 |
IntType [bit_width=64, signed=true] |
INT64 |
INT_64 |
64ビット符号付き整数 |
IntType [bit_width=8, signed=false] |
INT32 |
UINT_8 |
8ビット符号無し整数 |
IntType [bit_width=16, signed=false] |
INT32 |
UINT_16 |
16ビット符号無し整数 |
IntType [bit_width=32, signed=false] |
INT32 |
UINT_32 |
32ビット符号無し整数 |
IntType [bit_width=64, signed=false] |
INT64 |
UINT_64 |
64ビット符号無し整数 |
DECIMAL |
INT32, INT64, FIXED_LEN_BYTE_ARRAY, BYTE_ARRAY
|
- | 10進小数 |
FLOAT16 |
FIXED_LEN_BYTE_ARRAY[len=2] |
- | IEEE 16ビット浮動小数点数 |
DATE |
INT32 |
- | 時刻情報のない日付。実態はUnix Epochからの日数 |
TimeType [isAdjustedToUTC=true, unit=MILLIS] |
INT32 |
TIME_MILLIS |
日付情報のない時刻。実態は0時からのミリ秒数 |
TimeType [isAdjustedToUTC=true, unit=MICROS] |
INT64 |
TIME_MICROS |
日付情報のない時刻。実態は0時からのマイクロ秒数 |
TimeType [isAdjustedToUTC=true, unit=NANOS] |
INT64 |
- | 日付情報のない時刻。実態は0時からのナノ秒数 |
TimeType [isAdjustedToUTC=false, unit=MILLIS] |
INT32 |
TIME_MILLIS |
タイムゾーン情報を持たない日付なし時刻。 3 |
TimeType [isAdjustedToUTC=false, unit=MICROS] |
INT64 |
TIME_MICROS |
タイムゾーン情報を持たない日付なし時刻。 |
TimeType [isAdjustedToUTC=false, unit=NANOS] |
INT64 |
- | タイムゾーン情報を持たない日付なし時刻。 |
TIMESTAMP [isAdjustedToUTC=true, unit=MILLIS] |
INT64 |
TIMESTAMP_MILLIS |
特定の瞬間を一意に示せるタイムスタンプ。実態はUnix Epochからのミリ秒数 |
TIMESTAMP [isAdjustedToUTC=true, unit=MICROS] |
INT64 |
TIMESTAMP_MICROS |
特定の瞬間を一意に示せるタイムスタンプ。実態はUnix Epochからのマイクロ秒数 |
TIMESTAMP [isAdjustedToUTC=true, unit=NANOS] |
INT64 |
- | 特定の瞬間を一意に示せるタイムスタンプ。実態はUnix Epochからのナノ秒数 |
TIMESTAMP [isAdjustedToUTC=false, unit=MILLIS] |
INT64 |
TIMESTAMP_MILLIS |
環境のタイムゾーンにかかわらず同じように表示されることが期待されるミリ秒単位のタイムスタンプ。3 |
TIMESTAMP [isAdjustedToUTC=false, unit=MICROS] |
INT64 |
TIMESTAMP_MICROS |
環境のタイムゾーンにかかわらず同じように表示されることが期待されるマイクロ秒単位のタイムスタンプ。 |
TIMESTAMP [isAdjustedToUTC=false, unit=NANOS] |
INT64 |
- | 環境のタイムゾーンにかかわらず同じように表示されることが期待されるナノ秒単位のタイムスタンプ。 |
INTERVAL |
FIXED_LEN_BYTE_ARRAY[len=12] |
- | 3つの32ビット整数(月、日、ミリ秒)で表現される時間の長さ。 |
JSON |
BYTE_ARRAY |
- | UTF8エンコードされたJSON文字列 |
BSON |
BYTE_ARRAY |
- | BSON形式のバイナリデータ |
VARIANT |
複合 | - | 任意の型を格納できる型。高速化のためにShreddingという構造を持つことができる。 |
GEOMETRY [crs=座標参照系名] |
BYTE_ARRAY |
- | 頂点間を直線でつないで表現されるGeospatial Feature(地図上に配置された図形)。WKB形式で保存される。 |
GEOGRAPHY [crs=座標参照系名, algorithm=アルゴリズム名] |
BYTE_ARRAY |
- | 頂点間を補完アルゴリズムによって非線形につないで表現されるGeospatial Feature(地図上に配置された図形)。WKB形式で保存される。 |
LIST |
複合 | - | リストとして解釈される繰り返し型。 |
MAP |
複合 | - | マップとして解釈される繰り返し型。基本的にはキーと値が1対1で対応するように構成され、そのように解釈される。 |
UNKNOWN |
- | - | 特殊な型。このフィールドの値は常にnullとなる。 |