2
votes

Spark: udf pour obtenir le nom du répertoire à partir du chemin

J'ai une quantité insensée de colonnes de chemin à diviser en 2 colonnes, basename et dirname. Je sais comment obtenir facilement le nom de base de mes chemins en utilisant:

+------------------------------+--------------------------+
|column1                       |dirname                   |
+------------------------------+--------------------------+
|/test/coucou/jambon/hello/file|/test/coucou/jambon/hello |
|/test/jambon/test             |/test/jambon              |
+------------------------------+--------------------------+

Cependant, je me démène pour obtenir le nom du répertoire comme ceci:

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     |
+------------------------------+---------+

J'ai essayé différentes solutions mais je ne parviens pas à trouver une solution fonctionnelle en colonne.
Ma meilleure idée serait de soustraire $ "basename" à $ "column1" , mais je n'ai pas trouvé de moyen de soustraire String dans Spark.


0 commentaires

3 Réponses :


3
votes

Vous pouvez utiliser expr pour sous-chaîne la colonne1. Le code devrait ressembler à celui ci-dessous. J'espère que cela vous sera utile.

//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       |
+------------------------------+--------+-------------------------+


2 commentaires

semble intéressant, même si j'aurais aimé que ce soit un moyen plus simple: D C'est trop compliqué pour l'OMI, quelque chose qui devrait être beaucoup plus facile ... Merci beaucoup pour votre aide.


Eh bien, après y avoir mis plus de pensées. cela semble être le seul moyen de gérer un chemin court tel que /filex.txt en gardant le dernier / (supprimez le -1 dans la sous-chaîne)



2
votes

Une autre approche consisterait à utiliser des UDF:

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 commentaires

ne fonctionne pas lorsque vous utilisez un chemin plus court tel que: /file.txt le chemin de la colonne est vide et devrait être IMO



3
votes

Approche alternative à une solution déjà fournie utilisant l'expression régulière

Obtenez votre expression régulière correctement. regexp_extract UDF vous donnera ce que vous vouliez.

df.withColumn("path",regexp_extract($"column1", "^(.+)(/.+)$", 1 ) ) )

Sortie

+------------------------------+--------------------------+--------+
|column1                       |path                      |fileName|
+------------------------------+--------------------------+--------+
|/test/coucou/jambon/hello/file|/test/coucou/jambon/hello/|file    |
|/test/jambon/prout/test       |/test/jambon/prout/       |test    |
+------------------------------+--------------------------+--------+

Modifier:
Sans slash, les expressions régulières sont plus faciles à gérer:

   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)


1 commentaires

ne fonctionne pas lorsque vous utilisez un chemin plus court tel que: /file.txt le chemin de la colonne est vide et doit être IMO a /