Захват первого вхождения строки между двумя строками с использованием регулярного выражения в столбце в pyspark dataframe

#regex #apache-spark #pyspark #databricks #azure-databricks

#регулярное выражение #apache-spark #pyspark #databricks #azure-databricks

Вопрос:

У меня есть pyspark dataframe (df), который содержит столбец даты (тип данных: str) и столбец сообщений (тип данных str изменен из объекта списка с помощью concat_ws ()), как показано ниже:

Пример dataframe

 Date               message
2020-11-01         ['some not required text1', 'Startstring ID :AB_CD', 
                   'some not required text2', 'ID :EDGH', 'some not 
                    required text3', 'ID :XYZ', 'Stopstring' 'some not 
                    required text4', 'Startstring ID :cd_ab', 'some not 
                    required text5', 'ID :ghed', 
                    'some not required text6', ID :zyx', 'Stopstring 'some 
                    not required text7']
2020-11-02         ['some not required text8', Startstring 'ID :ABCD', 
                   'some not required text9', 'ID :ED_GH', 'some not 
                    required text10', ID :X_YZ, Stopstring 'some not 
                    required text11', 'Startstring 
                    ID :cdab', 'some not required text12', 'ID :gh_ed', 
                    'some not required text13', ID :z_yx', 'Stopstring 
                    'some not required text14']
 

Я хочу извлечь первое вхождение строки сразу после ID: между Startstring и Stopstring и отбросить идентификаторы, которые не являются первым появлением. За одну дату может быть несколько таких экземпляров.

Ожидаемый результат:

 Date               message
2020-11-01         AB_CD 
2020-11-01         cd_ab
2020-11-02         ABCD 
2020-11-02         cdab
 

Я попытался извлечь первое вхождение строки сразу после ID: as:

 import pyspark.sql.functions as F
from pyspark.sql.types import *

result = df.withColumn("message", F.regexp_extract(col("message"), r"Startstring[sS]*?ID :s*(S*)b[sS]*? Stopstring",1))
result.show()
 

Это дает мне только строку сразу после ID: в первый раз за определенную дату, как показано ниже:

 Date               message
2020-11-01         AB_CD 
2020-11-02         ABCD
 

Помощь в этом отношении высоко ценится. Спасибо

Ответ №1:

Что вы могли бы сделать, это:

  • объедините массив (как вы описали)
  • разделение на «Стоп-строку»
  • разнесите столбец, что означает, что вы получаете строку для каждого элемента массива (и, следовательно, для каждого вхождения вашего шаблона).
  • примените регулярное выражение.
 df
  .withColumn("concat_message", F.concat_ws(" ",F.col("message")))
  .withColumn("split_message", F.split(F.col("concat_message"), "Stopstring"))
  .withColumn("exploded_message", F.explode(F.col("split_message")))
  .withColumn("parsed_ids", F.regexp_extract(F.col("exploded_message"), r"Startstring[sS]*?ID :s*(S*)b[sS]*?",1))
  .filter(F.col("parsed_ids") != "")
  .show()
 

Одна из проблем заключается в том, что при разделении с помощью «Stopmessage» это слово удаляется из результирующих строк и не может использоваться в шаблоне регулярных выражений.

Комментарии:

1. Спасибо за ваш ответ. Я получаю сообщение об ошибке при запуске этого скрипта в databricks. «org.apache.spark.SparkException: задание прервано из-за сбоя этапа: задача 1 на этапе 100.0 выполнялась 4 раза, последний сбой: потерянная задача 1.3 на этапе 100.0 (TID 1425, 10.139.64.5, исполнитель 17): ExecutorLostFailure (executor 17 завершается из-за одной из запущенных задач) Причина: удаленный RPC-клиент отключен. Вероятно, из-за превышения пороговых значений контейнеров или проблем с сетью. Проверьте журналы драйверов на наличие предупреждающих сообщений «.

2. Я решил это. ваш код дает неправильный ответ. Спасибо

3. Ваше сообщение об ошибке звучит как проблема с сетью, а не проблема с кодом… Если вы считаете, что предоставленный ответ неверен, и нашли лучшее решение, было бы неплохо поделиться им здесь для последующего использования.

4. Да, понял, что ошибка произошла из-за проблемы с сетью. Я решил это. Однако ваш код не генерирует соответствующий вывод. В любом случае, я сделал код самостоятельно.