Как разложить и повернуть несколько JSON-подобных структур внутри фрейма данных PySpark

Я пытаюсь преобразовать необработанные данные «События», поступающие из учетной записи Google Analytics, с помощью PySpark. Каждая запись «Event» имеет поле с именем «event_params», которое содержит подполя в виде пар ключ-значение. Вот пример записи:


| event_date | event_timestamp | event_name | event_params                  
| --------   | --------        | --------   | ----------------------|
| 20230207   | 1675797300185610| Page View  | [{key=engaged_session_event, value = {string_value=null,        
                                               int_value=1, float_value=null, double_value=null}},
                                               {key=ga_session_number, value = {string_value=null, 
                                               int_value=1, float_value=null, double_value=null}}, 
                                               {key=page_title, value = {string_value=BlahBlah,
                                               double_value=null}}]                                |

Я бы хотел, чтобы окончательный набор данных выглядел примерно так:

Дата события event_timestamp название события вовлеченный_сессион_событие ga_session_number Заголовок страницы 20230207 1675797300185610 Вид страницы 1 1 БлаБла

Я пытался преобразовать поле «event_params» в ArrayType, StructType и строку JSON, но не могу даже извлечь отдельные «ключевые» поля. Как только я смогу это сделать, мне нужно будет игнорировать нулевые «значения» и повернуть оставшиеся пары ключ-значение как новые поля.

Можете ли вы распечатать и показать схему исходного df, используя .printSchema()?

arudsekaberne 16.05.2023 08:42

Да, каждое поле является строкой: root |-- event_date: строка (nullable = true) |-- event_timestamp: string (nullable = true) |-- event_name: string (nullable = true) |-- event_params: string (nullable = true) |-- event_params: string (nullable = true) = true) |-- event_previous_timestamp: string (nullable = true) |-- event_value_in_usd: string (nullable = true) |-- event_bundle_sequence_id: string (nullable = true) |-- event_server_timestamp_offset: string (nullable = true) |-- user_id: строка (nullable = true)

aknickel 16.05.2023 16:10

Одна проблема заключается в том, что строка имеет значения без кавычек, можете ли вы проверить, можете ли вы сохранить ее с кавычками, а затем мы можем взять ее оттуда?

Ronak Jain 16.05.2023 18:09

@RonakJain В настоящее время я не могу хранить значения в кавычках.

aknickel 16.05.2023 23:44

Вы можете преобразовать строку в допустимую строку json благодаря замене регулярного выражения. Или используйте UDF для его анализа и создания вложенного типа данных.

parisni 17.05.2023 00:11
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
5
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Попробуй это:

Импорт необходимых пакетов

from pyspark.sql.functions import col, regexp_replace, split, regexp_extract, from_json, struct, coalesce, max
  1. Разделение каждого строкового значения JSON на записи
df = df \
    .withColumn("event_params", regexp_replace("event_params", "\[", "")) \
    .withColumn("event_params", regexp_replace("event_params", "\]", "")) \
    .withColumn("event_params", regexp_replace("event_params", "\}},", "}}|")) \
    .withColumn("event_params", split("event_params", "\|")) \
    .withColumn("event_params", explode("event_params"))
  1. Парсинг строковых значений JSON
df = df \
    .withColumn("event_params", regexp_replace("event_params", " ", "")) \
    .withColumn("event_params", regexp_replace("event_params", " = ", ":")) \
    .withColumn("event_params", regexp_replace("event_params", ",", "',")) \
    .withColumn("event_params", regexp_replace("event_params", "\{", "{'")) \
    .withColumn("event_params", regexp_replace("event_params", "\}}", "'}}")) \
    .withColumn("event_params", regexp_replace("event_params", ",", ",'")) \
    .withColumn("event_params", regexp_replace("event_params", ":", "':'")) \
    .withColumn("event_params", regexp_replace("event_params", ":'\{", ":{")) \
    .withColumn("event_params", regexp_replace("event_params", "'null'", "null"))
  1. Преобразование и извлечение значений из event_params
df = df \
    .withColumn("event_params", from_json("event_params", MapType(StringType(), StringType()))) \
    .withColumn("event_params_key", col("event_params").getField("key")) \
    .withColumn("event_params_value", col("event_params").getField("value")) \
    .withColumn("event_params_value", from_json("event_params_value", MapType(StringType(), StringType()))) \
  1. Чтобы получить сводной вывод
df = df.withColumn("event_params_value", coalesce(
    "event_params_value.string_value",
    "event_params_value.int_value",
    "event_params_value.float_value",
    "event_params_value.double_value",
))

df = df.groupBy(["event_date", "event_timestamp", "event_name"]).pivot("event_params_key").agg(
    max("event_params_value")
)

df.show(truncate=False)

Выход:

+----------+----------------+----------+---------------------+-----------------+----------+
|event_date|event_timestamp |event_name|engaged_session_event|ga_session_number|page_title|
+----------+----------------+----------+---------------------+-----------------+----------+
|20230207  |1675797300185610|Page View |1                    |1                |BlahBlah  |
+----------+----------------+----------+---------------------+-----------------+----------+

Примечание: я не очень хорошо пишу regexp. Если кто-то может это сделать, не стесняйтесь переформатировать код (2).

@aknickel Не могли бы вы принять это как ответ.

arudsekaberne 17.05.2023 18:30

Другие вопросы по теме