#scala #apache-spark
#scala #apache-spark
Вопрос:
У меня есть безумное количество столбцов пути, которые мне нужно разделить на 2 столбца: basename и dirname. Я знаю, как легко получить базовое имя моих путей, используя :
val df = Seq("/test/coucou/jambon/hello/file"
,"/test/jambon/test")
.toDF("column1")
df.withColumn("basename", substring_index($"column1" , "/", -1))
.show(2, false)
------------------------------ ---------
|column1 |basename |
------------------------------ ---------
|/test/coucou/jambon/hello/file|file |
|/test/jambon/test |test |
------------------------------ ---------
Однако я изо всех сил пытаюсь получить dirname следующим образом :
------------------------------ --------------------------
|column1 |dirname |
------------------------------ --------------------------
|/test/coucou/jambon/hello/file|/test/coucou/jambon/hello |
|/test/jambon/test |/test/jambon |
------------------------------ --------------------------
Я пробовал различные решения, однако я не могу найти функциональное столбчатое решение.
Моей лучшей идеей было бы вычесть $"basename"
из $"column1"
, однако я не смог найти способ вычесть строку в Spark.
Ответ №1:
Вы можете использовать expr для подстроки столбца 1. Код должен выглядеть следующим образом. Я надеюсь, что это полезно.
//Creating Test Data
val df = Seq("/test/coucou/jambon/hello/file"
,"/test/jambon/prout/test")
.toDF("column1")
val test = df.withColumn("basename", substring_index($"column1" , "/", -1))
.withColumn("path", expr("substring(column1, 1, length(column1)-length(basename)-1)"))
test.show(false)
------------------------------ -------- -------------------------
|column1 |basename|path |
------------------------------ -------- -------------------------
|/test/coucou/jambon/hello/file|file |/test/coucou/jambon/hello|
|/test/jambon/prout/test |test |/test/jambon/prout |
------------------------------ -------- -------------------------
Комментарии:
1. выглядит интересно, хотя я хотел бы, чтобы они были более простым способом: D Для IMO это слишком сложно, что должно быть намного проще…. Большое вам спасибо за вашу помощь.
2. Ну, после того, как в нем появилось больше мыслей. кажется, это единственный способ обработать короткий путь, такой как
/filex.txt
сохранение последнего/
(удалите -1 в подстроке)
Ответ №2:
Альтернативный подход к уже предоставленному решению с использованием регулярного выражения
Получите правильное регулярное выражение. regexp_extract UDF даст вам то, что вы хотели.
val df = Seq("/test/coucou/jambon/hello/file"
, "/test/jambon/prout/test")
.toDF("column1")
import org.apache.spark.sql.functions.regexp_extract
df.withColumn("path", regexp_extract('column1, "^\/(\w \/) ", 0)).withColumn("fileName",regexp_extract('column1, "\w $", 0)).show(false)
Вывод
------------------------------ -------------------------- --------
|column1 |path |fileName|
------------------------------ -------------------------- --------
|/test/coucou/jambon/hello/file|/test/coucou/jambon/hello/|file |
|/test/jambon/prout/test |/test/jambon/prout/ |test |
------------------------------ -------------------------- --------
Редактировать:
Регулярным выражением без косой черты в конце легче управлять:
df.withColumn("path",regexp_extract($"column1", "^(. )(/. )$", 1 ) ) )
Комментарии:
1. не работает при использовании более короткого пути, такого как:
/file.txt
путь к столбцу пуст и должен быть IMO a/
Ответ №3:
Другим подходом было бы использование UDFS:
import org.apache.spark.sql.functions.udf
val pathUDF = udf((s: String) => s.substring(0, s.lastIndexOf("/")))
val test = df.withColumn("basename", substring_index($"column1" , "/", -1))
.withColumn("path", pathUDF($"column1"))
test.show(false)
------------------------------ -------- -------------------------
|column1 |basename|path |
------------------------------ -------- -------------------------
|/test/coucou/jambon/hello/file|file |/test/coucou/jambon/hello|
|/test/jambon/prout/test |test |/test/jambon/prout |
------------------------------ -------- -------------------------
Комментарии:
1. не работает при использовании более короткого пути, такого как: /file.txt путь к столбцу пуст и должен быть IMO a /