ちょっと Parquet ファイルのスキーマを確認したいことがあった。
こんな感じのスクリプトを書いた。
import argparse import pyarrow.parquet as pq from pyarrow.parquet import ParquetFile def main(input_file: str) -> None: try: parquet_file: ParquetFile = pq.ParquetFile(input_file) schema = parquet_file.schema print(schema) except FileNotFoundError: print(f"Error: File not found - {input_file}") except Exception as e: print(f"An error occurred: {e}") if __name__ == "__main__": parser = argparse.ArgumentParser( description="Print Parquet file's schema") parser.add_argument("input_file", help="Path to the parquet file") args = parser.parse_args() main(args.input_file)
こいつで確認したら、map<string, string>
なカラムは以下のような感じになってた。resource_tags は、いわゆるタグが複数格納されている感じね。
resource_tags: map<string, string ('resource_tags')> child 0, resource_tags: struct<key: string not null, value: string> not null child 0, key: string not null child 1, value: string
mapは struct<key: string not null, value: string>
が複数格納されている。
なんかネストされた構造がある? と思ってフォーマットの説明を眺めていた。
MAP is used to annotate types that should be interpreted as a map from keys to values. MAP must annotate a 3-level structure:
<map-repetition> group
(MAP) { repeated group key_value { required <key-type> key; <value-repetition> <value-type> value; } }
- The outer-most level must be a group annotated with MAP that contains a single field named key_value. The repetition of this level must be either optional or required and determines whether the map is nullable.
- The middle level, named key_value, must be a repeated group with a key field for map keys and, optionally, a value field for map values. It must not contain any other values.
map<string, T>
は、
key_value
って名前のフィールドを持つ struct だよkey_value
はkey: string (required)
と、value: T(optional)
を持つstruct
がrepeated
になっているよ
というように表現される。なるほどね。
BigQuery にデータをインポートしたとき、map<string, T>
が struct<{key_value: Repeated<strict{key: string, value: T}>}>
みたいな感じに変換されていて、key_value
ってどっからきたんやろと思っていた。Parquetファイルの方の仕様だったのねえ。