#scala #apache-spark #apache-spark-sql
#scala #apache-spark #apache-spark-sql
Вопрос:
У меня есть два фрейма данных, первый содержит фактические данные (считанные из файла CSV), а второй содержит один столбец с несколькими ключевыми словами. т.е. Фрейм данных-1 похожий ниже (где мы должны искать):
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
, если столбцы должны быть включены в результирующий набор данных.