У меня есть таблица необработанных блоков данных с одним столбцом с именем «значение», данные которого взяты из CSV с разделителями-каналами.
Данные внутри этого единственного столбца представляют собой 5 полей.
Содержимое field3 представляет собой json, внутри которого содержится PIPE.
Данные выглядят так:
10|20|{"menu":{"id":"file","menuitem":[{"value":"New","onclick":"CreateNewDoc() || ReplaceDoc() || DeleteDoc()"}]}}|13123|344234
Я новичок в pyspark, и мои данные огромны, поэтому я попытался разбить содержимое на новую таблицу из 5 столбцов, используя регулярное выражение в поле 3, но безуспешно.
Мой код выглядит так:
from pyspark.sql.functions import split, col, regexp_extract
from pyspark.sql.functions import DataFrame
df = spark.sql(
"""
select value from my_table
"""
)
df_out = df.withColumn(field1, split(col("value", "\\|".getItem(0))
.withColumn(field2, split(col("value", "\\|".getItem(1))
.withColumn(field3, regex_extract("value", r"\|\{(.*?)\}\|",1))
.withColumn(field4, split(col("value", "\\|".getItem(3))
.withColumn(field5, split(col("value", "\\|".getItem(4))
new_table = df_out.select("field1", "field2", "field3", "field4", "field5")
new_table.display()
Мой результат из этого кода похож на то, что некоторая часть json в поле3 неправильно разбивается на поле4 и поле5.
Кто-нибудь может помочь мне решить эту проблему?
Может быть, рассмотреть все между первым { и последним } и считать все, что находится внутри, буквальным?
Спасибо!
Почему вы продолжаете отменять форматирование входных данных?
Извините, я не особо знаком с сообщениями о stackoverflow, братан.
Я не думаю, что есть какой-либо надежный способ сделать то, что вы хотите. Не существует простого способа отличить каналы, являющиеся разделителями, от буквальных. Вам следует исправить формат данных, чтобы его можно было правильно проанализировать.
Исправить данные — это на самом деле моя работа как инженера по данным, поскольку изначально это не исправляло бы. Мои литеральные каналы - это каналы, заключенные в {}, возможно, какое-то регулярное выражение, которое считает все внутри {} буквальным, должно решить. Проблема в том, что я не знаю, как это сделать :(
Регулярные выражения плохо различают «внутри» и «снаружи». Что, если в этом поле есть другие символы {}
?
Например. {"value":"New}", ...}
Регулярные выражения также не могут легко обнаружить сбалансированные фигурные скобки. Таким образом, регулярное выражение не может определить, что вложенные объекты не завершают внешний объект.
Regex будет использоваться для проверки первого появления "{" и последнего появления "}", поэтому все внутри является буквальным. В любом случае, я так думаю, если бы можно было сделать по-другому, то не было бы проблем.
Похоже, у вас .getItem()
не в том месте. Должно быть split(...).getItem(...)
@Бармар, это работает, братан, спасибо тебе огромное!!!
Для столбцов после поля JSON отсчитывайте с конца, а не с начала, чтобы каналы в JSON не приводили к неправильным индексам.
fields = split(col("value"), r'\|')
nfields = size(fields)
df_out = df.withColumn(field1, fields.getItem(0))
.withColumn(field2, fields.getItem(1))
.withColumn(field3, regexp_extract(col("value"), r"\|\{(.*?)\}\|",1))
.withColumn(field4, fields.getItem(nfields-2))
.withColumn(field5, fields.getItem(nfields-1))
Опечатка:
withColunm
должно бытьwithColumn