Мне нужно сопоставить список столбцов с другим столбцом в наборе данных Spark: подумайте примерно так
val translationMap: Map[Column, Column] = Map(
lit("foo") -> lit("bar"),
lit("baz") -> lit("bab")
)
И у меня есть фрейм данных, подобный этому:
val df = Seq("foo", "baz").toDF("mov")
Поэтому я намерен выполнить перевод следующим образом:
df.select(
col("mov"),
translationMap(col("mov"))
)
но этот кусок кода выдает следующую ошибку
key not found: movs
java.util.NoSuchElementException: key not found: movs
Есть ли способ выполнить такой перевод без объединения сотен when
s? думаю, что translationMap
может иметь много пар ключ-значение.
Вы не можете ссылаться на коллекцию Scala, объявленную в драйвере, внутри распределенного фрейма данных. Альтернативой может быть использование UDF, который не будет эффективным с точки зрения производительности, если у вас большой набор данных, поскольку Spark не оптимизирует UDF.
val translationMap = Map( "foo" -> "bar" , "baz" -> "bab" )
val getTranslationValue = udf ((x: String)=>translationMap.getOrElse(x,null.asInstanceOf[String]) )
df.select(col("mov"), getTranslationValue($"mov").as("value") ).show
//+---+-----+
//|mov|value|
//+---+-----+
//|foo| bar|
//|baz| bab|
//+---+-----+
Другим решением было бы загрузить Map
как DataSet[(String, String)]
и объединить два набора данных, взяв mov
в качестве ключа.
@philantrovert Я использую то же самое, но в кластере translationMap приходит как null, как с этим справиться? можно ли отправить translationMap в UDF в качестве параметра? stackoverflow.com/questions/63935600/…
Вместо Map[Column, Column]
вы должны использовать Column
, содержащий литерал карты:
import org.apache.spark.sql.functions.typedLit
val translationMap: Column = typedLit(Map(
"foo" -> "bar",
"baz" -> "bab"
))
Остальной код можно оставить как есть:
df.select(
col("mov"),
translationMap(col("mov"))
).show
+---+---------------------------------------+
|mov|keys: [foo,baz], values: [bar,bab][mov]|
+---+---------------------------------------+
|foo| bar|
|baz| bab|
+---+---------------------------------------+
Кстати, как это обрабатывает случай неизвестного ключа? например, если я передам столбец со значением, отличным от foo
или baz
, в translationMap
? В идеале я хотел бы вернуть неизвестное значение без изменений
@mrbolichi, coalesce(translationMap(col("mov")), col("mov"))
будет обрабатывать несовпадающие ключи так, как вы хотите.
Если возможно, я бы предпочел избегать
udf
из-за проблем с производительностью, о которых вы упомянули. Кроме того, это будет очень распространенная операция, поэтому я хотел бы избежать объединений, так как было бы удобно иметь функцию, которая будет возвращать столбец, чтобы вставить его в моиselect
s