Python Parquet 中的嵌套数据

Nested data in Parquet with Python

我有一个文件,每行有一个 JSON。这是一个示例:

{
    "product": {
        "id": "abcdef",
        "price": 19.99,
        "specs": {
            "voltage": "110v",
            "color": "white"
        }
    },
    "user": "Daniel Severo"
}

我想创建一个包含以下列的镶木地板文件:

product.id, product.price, product.specs.voltage, product.specs.color, user

我知道 parquet 有一个使用 Dremel 算法的嵌套编码,但我无法在 python 中使用它(不知道为什么)。

我是一个沉重的 pandas 和愚蠢的用户,所以我试图构建的管道是 json data -> dask -> parquet -> pandas,尽管 如果有人有一个简单的创建和使用 Python 在 parquet 中读取这些嵌套编码我认为这就足够了 :D

编辑

所以,在深入研究 PR 之后,我发现了这个:https://github.com/dask/fastparquet/pull/177

这基本上就是我想做的。虽然,我仍然无法让它一直工作。我如何准确地告诉 dask/fastparquet 我的 product 列是嵌套的?

在任意 Parquet 嵌套数据的读取和写入路径上实现转换非常复杂——实现分解和重组算法以及对某些 Python 数据结构的相关转换。我们在 Arrow / parquet-cpp 的路线图上有这个(见 https://github.com/apache/parquet-cpp/tree/master/src/parquet/arrow),但它还没有完成(现在只支持简单结构和 lists/arrays)。拥有此功能很重要,因为其他使用 Parquet 的系统,如 Impala、Hive、Presto、Drill 和 Spark,在其 SQL 方言中原生支持嵌套类型,因此我们需要能够从 Python.

忠实地读写这些结构

这也可以在 fastparquet 中类似地实现,但是无论您如何分割它都将需要大量工作(和编写测试用例)。

我可能会在今年晚些时候亲自承担这项工作(在 parquet-cpp 中),如果没有人比我强的话,但我很乐意得到一些帮助。

这不是正确的答案,但它可以提供帮助。

我们可以尝试将您的字典转换为 pandas DataFrame,然后将其写入 .parquet 文件:

import pandas as pd
from fastparquet import write, ParquetFile

d = {
    "product": {
        "id": "abcdef",
        "price": 19.99,
        "specs": {
            "voltage": "110v",
            "color": "white"
        }
    },
    "user": "Daniel Severo"
}

df_test = pd.DataFrame(d)
write('file_test.parquet', df_test)

这会引发错误:

ValueError: Can't infer object conversion type: 0                                   abcdef
1                                    19.99
2    {'voltage': '110v', 'color': 'white'}
Name: product, dtype: object

所以一个简单的解决方案是将 product 列转换为列表:

df_test['product'] = df_test['product'].apply(lambda x: [x])

# this should now works
write('file_test.parquet', df_test)

# and now compare the file with the initial DataFrame
ParquetFile('file_test.parquet').to_pandas().explode('product')
    index            product                                 user
0   id               abcdef                             Daniel Severo
1   price             19.99                             Daniel Severo
2   specs   {'voltage': '110v', 'color': 'white'}       Daniel Severo

我相信这个功能终于在 arrow/pyarrow 2.0.0 中添加了:

https://issues.apache.org/jira/browse/ARROW-1644

https://arrow.apache.org/docs/python/json.html