使用Array <Map <String,String >>列读取Parquet文件

时间:2019-07-14 02:06:32

标签: python dask python-3.7 pyarrow fastparquet

我正在使用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可以很好地读取所有其他列,但是对于复杂类型的列,返回None s列。设置engine='pyarrow'时,出现以下异常:

ArrowNotImplementedError: lists with structs are not supported.

许多谷歌搜索已经明确表明,目前尚不真正支持使用嵌套数组读取列,而且我也不完全确定处理此问题的最佳方法是什么。我认为我的选择是:

  • 有些如何告诉dask / fastparquet使用标准json库来解析列。模式很简单,并且在可能的情况下会完成工作
  • 看看我是否可以重新运行生成输出的Spark作业并将其另存为其他内容,尽管由于我的公司到处都使用镶木地板,这几乎是不可接受的解决方案
  • 将映射的键转换为列,并使用dtype list将数据分解为几列,并注意这些列中的数据通过索引相互关联/映射(例如idx {中的元素这些键/列中的{1}}均来自同一来源)。这行得通,但坦率地说,让我伤心了:(

我很想听听其他人如何绕过这个限制。我的公司经常在他们的parquest中使用嵌套数组,因此,我讨厌不得不放弃使用Dask。

2 个答案:

答案 0 :(得分:0)

公平地说,熊猫并不能很好地支持非简单类型(当前)。可能是pyarrow会不转换为大熊猫,而将来,大熊猫会直接使用这些箭头结构。

事实上,我认为最直接的方法是将列重写为B / JSON编码的文本,然后使用fastparquet进行加载,并指定使用B / JSON进行加载。您应该在该列中获得字典列表,但是性能会很慢。

请注意,旧项目oamap及其后继项目awkward提供了一种使用python语法在嵌套列表/地图/结构树上进行迭代和聚合的方法,但是使用Numba进行了编译,因此您永远不需要实例化中间python对象。它们不是为实木复合地板而设计的,而是具有实木复合地板的兼容性,因此可能对您很有用。

答案 1 :(得分:0)

当我尝试使用熊猫阅读时,我正在与pyarrow.lib.ArrowNotImplementedError: Reading lists of structs from Parquet files not yet supported交流;但是,当我使用pyspark阅读并转换为熊猫时,数据至少会加载:

import pyspark
spark = pyspark.sql.SparkSession.builder.getOrCreate()
df = spark.read.load(path)
pdf = df.toPandas()

,并且令人讨厌的字段现在呈现为pyspark Row对象,该对象具有一些结构化的解析,但是您可能必须编写自定义的熊猫函数才能从其中提取数据:

>>> 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-native选项