Столбец String содержит точные совпадающие слова через spark scala

#scala #apache-spark #apache-spark-sql

#scala #apache-spark #apache-spark-sql

Вопрос:

У меня есть два фрейма данных, первый содержит фактические данные (считанные из файла CSV), а второй содержит один столбец с несколькими ключевыми словами. т.е. Фрейм данных-1 похожий ниже (где мы должны искать):

Текст имени идентификатора 1 test1

Dataframe-2:

введите описание изображения здесь

Вывод, который я хочу:

введите описание изображения здесь

Здесь я использую spark scala. Я хочу точное совпадение слов из dataframe-2 в dataframe-1. Я использовал такие функции, как like, rlike, contains, но это не дает мне желаемого результата. Кто-нибудь может знать, как разработать эту логику в spark scala SQL или с использованием функций spark scala dataframe. Пожалуйста, помогите мне с этим.

Ответ №1:

Вы можете выполнить полусоединение слева, исходя из условия, что текст df1 содержит строки в тексте df2 с пробелом перед и после слов:

 val result = df1.as("df1").join(
    df2.as("df2"),
    expr("df1.text rlike concat(' ', df2.text, ' ')"),
    "left_semi"
)

result.show(false)
 --- ----- ----------------------- 
|ID |Name |Text                   |
 --- ----- ----------------------- 
|1  |Test1|Amount paid to User1 dt|
|2  |Test2|Amount paid to User1 dt|
 --- ----- ----------------------- 
 

Ответ №2:

Вы можете разделить Text столбец в df1 на массив слов и объединить с помощью array_contains функции :

 val df3 = df1.alias("df1")
  .join(
    df2.alias("df2"),
    array_contains(split(col("df1.Text"), "\s"), col("df2.Text")),
    "left_semi"
  )

df3.show(false)

// --- ----- ----------------------- 
//|ID |Name |Text                   |
// --- ----- ----------------------- 
//|1  |Test1|Amount paid to User1 dt|
//|2  |Test2|Amount paid to User1 dt|
// --- ----- ----------------------- 
 

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

1. split вероятно, не будет работать, если в строке, которую нужно сопоставить, есть пробелы (например, «оплачено»).

2. @LeoC согласен. и, вероятно, это тоже не лучшее решение, но я хотел показать другой способ сделать хотя бы для ключевых слов из одного слова 🙂

Ответ №3:

Вы можете объединить два фрейма данных при Regex условии с помощью regexp_replace , как показано ниже:

 val df1 = Seq(
  (1, "Test1", "Amount paid to User1 dt"),
  (2, "Test2", "Amount paid to User1 dt"),
  (3, "Test3", "Amount paid to balamurugan dt"),
  (4, "Test4", "Amount paid to final dt"),
  (5, "Test5", "Amount paid to John less dt")
).toDF("ID", "Name", "Text")

val df2 = Seq("User1", "murugan", "Amo").toDF("Text")

val pattern = concat(lit("\b"), df2("Text"), lit("\b"))

df1.join(df2, regexp_replace(df1("Text"), pattern, lit("")) =!= df1("Text")).show
//  --- ----- ----------------------- ----- 
// |ID |Name |Text                   |Text |
//  --- ----- ----------------------- ----- 
// |1  |Test1|Amount paid to User1 dt|User1|
// |2  |Test2|Amount paid to User1 dt|User1|
//  --- ----- ----------------------- ----- 
 

Обратите внимание, что это b представляет границу слова, тем самым ограничивая совпадение регулярных выражений только совпадением слов.


Обновить:

Как предлагалось в других ответах, left_semi join, вероятно, будет работать лучше, чтобы избежать дублирования строк при наличии нескольких совпадений. inner Соединение по умолчанию было бы подходящим в случае df2 , если столбцы должны быть включены в результирующий набор данных.