使用 Array<Map<String,String>> 列读取 Parquet 文件
Reading Parquet File with Array<Map<String,String>> Column
我正在使用 Dask 读取由 PySpark 生成的 Parquet 文件,其中一列是字典列表(即 array<map<string,string>>'
)。 df 的一个例子是:
import pandas as pd
df = pd.DataFrame.from_records([
(1, [{'job_id': 1, 'started': '2019-07-04'}, {'job_id': 2, 'started': '2019-05-04'}], 100),
(5, [{'job_id': 3, 'started': '2015-06-04'}, {'job_id': 9, 'started': '2019-02-02'}], 540)],
columns=['uid', 'job_history', 'latency']
)
当使用 engine='fastparquet
时,Dask 可以正常读取所有其他列,但 returns 具有复杂类型的列的 None
列。当我设置 engine='pyarrow'
时,出现以下异常:
ArrowNotImplementedError: lists with structs are not supported.
很多谷歌搜索已经清楚地表明,现在并不真正支持读取带有嵌套数组的列,而且我不完全确定处理这个问题的最佳方法是什么。我认为我的选择是:
- 一些如何告诉 dask/fastparquet 使用标准
json
库解析列。架构很简单,如果可能就可以完成工作
- 看看我是否可以重新运行生成输出的 Spark 作业并将其另存为其他内容,尽管这几乎不是一个可接受的解决方案,因为我的公司到处都使用镶木地板
- 将地图的键转换为列,并使用 dtype
list
将数据分解成多个列,并注意这些列中的数据按索引相互 related/map(例如这些 keys/columns 中 idx 0
中的元素都来自同一来源)。这会奏效,但坦率地说,让我心碎:(
我很想听听其他人是如何解决这个限制的。我的公司经常在他们的 parquest 中使用嵌套数组,因此我不想不得不放弃使用 Dask。
更公平地说 pandas 不能很好地支持 non-simple 类型(目前)。 pyarrow 可能会在不转换为 pandas 的情况下出现这种情况,并且作为未来的某个点,pandas 将直接使用这些箭头结构。
确实,我能想到的最直接的方法就是将列重写为B/JSON-encoded文本,然后使用fastparquet加载,指定使用B/JSON加载。您应该在列中获得字典列表,但性能会很慢。
请注意,旧项目 oamap and its successor awkward 提供了一种使用 python 语法迭代和聚合嵌套 list/map/struct 树的方法,但使用 Numba 编译,因此您永远不需要实例化中间 python 个对象。它们不是为镶木地板设计的,但具有镶木地板兼容性,因此可能对您有用。
当我尝试使用 Pandas 阅读时,我正在处理 pyarrow.lib.ArrowNotImplementedError: Reading lists of structs from Parquet files not yet supported
;然而,当我使用 pyspark 阅读然后转换为 pandas 时,数据至少加载:
import pyspark
spark = pyspark.sql.SparkSession.builder.getOrCreate()
df = spark.read.load(path)
pdf = df.toPandas()
并且违规字段现在呈现为 pyspark Row 对象,它具有一些结构化解析,但您可能必须编写自定义 pandas 函数才能从中提取数据:
>>> pdf["user"][0]["sessions"][0]["views"]
[Row(is_search=True, price=None, search_string='ABC', segment='listing', time=1571250719.393951), Row(is_search=True, price=None, search_string='ZYX', segment='homepage', time=1571250791.588197), Row(is_search=True, price=None, search_string='XYZ', segment='listing', time=1571250824.106184)]
单个记录可以呈现为字典,只需在您想要的 Row 对象上调用 .asDict(recursive=True)
。
不幸的是,启动 SparkSession 上下文需要大约 5 秒,而且每个 spark 操作也比 pandas 操作(对于中小型数据集)花费的时间长得多,所以我更喜欢 python-原生选项
我正在使用 Dask 读取由 PySpark 生成的 Parquet 文件,其中一列是字典列表(即 array<map<string,string>>'
)。 df 的一个例子是:
import pandas as pd
df = pd.DataFrame.from_records([
(1, [{'job_id': 1, 'started': '2019-07-04'}, {'job_id': 2, 'started': '2019-05-04'}], 100),
(5, [{'job_id': 3, 'started': '2015-06-04'}, {'job_id': 9, 'started': '2019-02-02'}], 540)],
columns=['uid', 'job_history', 'latency']
)
当使用 engine='fastparquet
时,Dask 可以正常读取所有其他列,但 returns 具有复杂类型的列的 None
列。当我设置 engine='pyarrow'
时,出现以下异常:
ArrowNotImplementedError: lists with structs are not supported.
很多谷歌搜索已经清楚地表明,现在并不真正支持读取带有嵌套数组的列,而且我不完全确定处理这个问题的最佳方法是什么。我认为我的选择是:
- 一些如何告诉 dask/fastparquet 使用标准
json
库解析列。架构很简单,如果可能就可以完成工作 - 看看我是否可以重新运行生成输出的 Spark 作业并将其另存为其他内容,尽管这几乎不是一个可接受的解决方案,因为我的公司到处都使用镶木地板
- 将地图的键转换为列,并使用 dtype
list
将数据分解成多个列,并注意这些列中的数据按索引相互 related/map(例如这些 keys/columns 中 idx0
中的元素都来自同一来源)。这会奏效,但坦率地说,让我心碎:(
我很想听听其他人是如何解决这个限制的。我的公司经常在他们的 parquest 中使用嵌套数组,因此我不想不得不放弃使用 Dask。
更公平地说 pandas 不能很好地支持 non-simple 类型(目前)。 pyarrow 可能会在不转换为 pandas 的情况下出现这种情况,并且作为未来的某个点,pandas 将直接使用这些箭头结构。
确实,我能想到的最直接的方法就是将列重写为B/JSON-encoded文本,然后使用fastparquet加载,指定使用B/JSON加载。您应该在列中获得字典列表,但性能会很慢。
请注意,旧项目 oamap and its successor awkward 提供了一种使用 python 语法迭代和聚合嵌套 list/map/struct 树的方法,但使用 Numba 编译,因此您永远不需要实例化中间 python 个对象。它们不是为镶木地板设计的,但具有镶木地板兼容性,因此可能对您有用。
当我尝试使用 Pandas 阅读时,我正在处理 pyarrow.lib.ArrowNotImplementedError: Reading lists of structs from Parquet files not yet supported
;然而,当我使用 pyspark 阅读然后转换为 pandas 时,数据至少加载:
import pyspark
spark = pyspark.sql.SparkSession.builder.getOrCreate()
df = spark.read.load(path)
pdf = df.toPandas()
并且违规字段现在呈现为 pyspark Row 对象,它具有一些结构化解析,但您可能必须编写自定义 pandas 函数才能从中提取数据:
>>> pdf["user"][0]["sessions"][0]["views"]
[Row(is_search=True, price=None, search_string='ABC', segment='listing', time=1571250719.393951), Row(is_search=True, price=None, search_string='ZYX', segment='homepage', time=1571250791.588197), Row(is_search=True, price=None, search_string='XYZ', segment='listing', time=1571250824.106184)]
单个记录可以呈现为字典,只需在您想要的 Row 对象上调用 .asDict(recursive=True)
。
不幸的是,启动 SparkSession 上下文需要大约 5 秒,而且每个 spark 操作也比 pandas 操作(对于中小型数据集)花费的时间长得多,所以我更喜欢 python-原生选项