Чтение файла Parquet со столбцом Array‹Map‹String,String››

Я использую Dask для чтения файла Parquet, созданного PySpark, и один из столбцов представляет собой список словарей (например, 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 нормально читает все остальные столбцы, но возвращает столбец Nones для столбца сложного типа. Когда я устанавливаю engine='pyarrow', я получаю следующее исключение:

ArrowNotImplementedError: lists with structs are not supported.

Многие поиски в Google показали, что чтение столбца с вложенным массивом просто не поддерживается прямо сейчас, и я не совсем уверен, как лучше всего справиться с этим. Я полагаю, что мои варианты:

  • Каким-то образом скажите dask/fastparquet проанализировать столбец, используя стандартную библиотеку json. Схема проста, и, если это возможно, она сделает работу.
  • Посмотрите, смогу ли я повторно запустить задание Spark, которое сгенерировало вывод, и сохранить его как что-то еще, хотя это почти неприемлемое решение, поскольку моя компания везде использует паркет.
  • Превратите ключи карты в столбцы и разбейте данные на несколько столбцов с помощью dtype list и обратите внимание, что данные в этих столбцах связаны/сопоставляются друг с другом по индексу (например, элементы в idx 0 по этим ключам/столбцам все пришли из того же источника). Это бы сработало, но, честно говоря, сердце разбивается :(

Я хотел бы услышать, как другие обошли это ограничение. Моя компания часто использует вложенные массивы в своем паркете, и я бы не хотел из-за этого отказываться от использования Dask.


person Jon.H    schedule 14.07.2019    source источник


Ответы (2)


Было бы справедливее сказать, что pandas не очень хорошо поддерживает непростые типы (в настоящее время). Может случиться так, что pyarrow будет без преобразования в pandas, и что в будущем pandas будут использовать эти структуры стрелок напрямую.

Действительно, самый прямой метод, который я могу вам предложить, — это переписать столбцы как текст в кодировке B/JSON, а затем загрузить с помощью fastparquet, указав загрузку с использованием B/JSON. Вы должны получить списки диктов в столбце, но производительность будет медленной.

Обратите внимание, что старый проект oamap и его преемник awkward предоставляет способ итерации и агрегирования по вложенным деревьям списков/карт/структур с использованием синтаксиса Python, но скомпилированного с помощью Numba, так что вы никогда не нужно создавать промежуточные объекты Python. Они не предназначены для паркета, но совместимы с паркетом, поэтому могут быть вам полезны.

person mdurant    schedule 14.07.2019

Я имею дело с pyarrow.lib.ArrowNotImplementedError: Reading lists of structs from Parquet files not yet supported, когда пытаюсь читать с помощью Pandas; однако, когда я читаю с помощью pyspark, а затем конвертирую в pandas, данные по крайней мере загружаются:

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

и оскорбительное поле теперь отображается как объект строки pyspark, который имеет некоторый структурированный синтаксический анализ, но вам, вероятно, придется написать собственные функции 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)]

отдельная запись может быть представлена ​​как словарь, просто вызовите .asDict(recursive=True) для объекта Row, который вам нужен.

К сожалению, для запуска контекста SparkSession требуется ~ 5 секунд, и каждое действие искры также занимает намного больше времени, чем операции pandas (для небольших и средних наборов данных), поэтому я бы предпочел более родной для python вариант.

person steeles    schedule 06.11.2019
comment
Я также пытался читать с помощью Spark и выполнять преобразование в pd.Dataframe, но в моем случае это не сработало. Вызов toPandas() приведет к тем же результатам, что и попытка чтения с помощью fastparquet; Я бы получил столбец Nones для любого столбца сложного типа. - person Jon.H; 06.11.2019
comment
Вы уже нашли решение? Я имею дело с тем же самым. Есть ли другой способ прочитать файлы паркета, не преобразовывая их в кадр данных pandas @Jon.H - person Nilan Saha; 24.08.2020
comment
@NilanSaha в итоге мы преобразовали столбец в строку JSON, а затем при чтении вызвали .loads(), чтобы преобразовать его обратно. Это совсем не красиво, но работает. Вы можете следить за ходом решения этой проблемы, но смотрите соответствующий тикет здесь: issues.apache.org /jira/browse/СТРЕЛКА-1644 . Похоже, идет активная разработка. Надеюсь, скоро у нас будет решение. - person Jon.H; 24.08.2020
comment
Мне жаль. Не поняла. Можете ли вы уточнить это? Вы в конечном итоге использовали PySpark и у вас есть POC? @Джон.Х - person Nilan Saha; 24.08.2020