我有两个数据帧,比如说Spark Scala中的df1和df2
df1有两个字段,' ID'和'文字'在哪里'文字'有一些描述(多个单词)。我已经从字段' Text'中删除了所有特殊字符和数字字符。只留下字母和空格。
df1示例
+--------------++--------------------+
|ID ||Text |
+--------------++--------------------+
| 1 ||helo how are you |
| 2 ||hai haiden |
| 3 ||hw are u uma |
--------------------------------------

df2包含单词列表和相应的替换单词
df2示例
+--------------++--------------------+
|Word ||Replace |
+--------------++--------------------+
| helo ||hello |
| hai ||hi |
| hw ||how |
| u ||you |
--------------------------------------

我需要从df1(" Word")中找到df2中所有出现的单词(" Text")并将其替换为df2("替换" )
使用上面的示例数据帧,我希望结果数据帧DF3如下所示
df3示例
+--------------++--------------------+
|ID ||Text |
+--------------++--------------------+
| 1 ||hello how are you |
| 2 ||hi haiden |
| 3 ||how are you uma |
--------------------------------------

使用Scala在Spark中执行相同的操作非常感谢您的帮助。
答案 0 :(得分:1)
我将仅针对第一个ID进行演示,并假设您无法对df2执行收集操作。首先,您需要确保数据帧的架构是df1
上的text列的数组+---+--------------------+
| id| text|
+---+--------------------+
| 1|[helo, how, are, ...|
+---+--------------------+
使用这样的架构:
|-- id: integer (nullable = true)
|-- text: array (nullable = true)
| |-- element: string (containsNull = true)
之后,您可以在文本列
上进行爆炸res1.withColumn("text", explode(res1("text")))
+---+----+
| id|text|
+---+----+
| 1|helo|
| 1| how|
| 1| are|
| 1| you|
+---+----+
假设您替换数据框如下所示:
+----+-------+
|word|replace|
+----+-------+
|helo| hello|
| hai| hi|
+----+-------+
加入这两个数据框将如下所示:
res6.join(res8, res6("text") === res8("word"), "left_outer")
+---+----+----+-------+
| id|text|word|replace|
+---+----+----+-------+
| 1| you|null| null|
| 1| how|null| null|
| 1|helo|helo| hello|
| 1| are|null| null|
+---+----+----+-------+
使用合并空值进行选择:
res26.select(res26("id"), coalesce(res26("replace"), res26("text")).as("replaced_text"))
+---+-------------+
| id|replaced_text|
+---+-------------+
| 1| you|
| 1| how|
| 1| hello|
| 1| are|
+---+-------------+
然后按ID和聚合分组到收集列表函数中:
res33.groupBy("id").agg(collect_list("replaced_text"))
+---+---------------------------+
| id|collect_list(replaced_text)|
+---+---------------------------+
| 1| [you, how, hello,...|
+---+---------------------------+
请记住,您应该保留文本元素的初始顺序。
答案 1 :(得分:1)
如果您将df2
转换为地图,则更容易实现此目的。假设它不是一张巨大的桌子,你可以做以下事情:
val keyVal = df2.map( r =>( r(0).toString, r(1).toString ) ).collect.toMap
这将为您提供Map
来引用:
scala.collection.immutable.Map[String,String] = Map(helo -> hello, hai -> hi, hw -> how, u -> you)
现在,您可以使用UDF
创建一个将keyVal
Map替换值的函数:
val getVal = udf[String, String] (x => x.split(" ").map(x => res18.get(x).getOrElse(x) ).mkString( " " ) )
现在,您可以在数据框上调用udf getVal
以获得所需的结果。
df1.withColumn("text" , getVal(df1("text")) ).show
+---+-----------------+
| id| text|
+---+-----------------+
| 1|hello how are you|
| 2| hi haiden|
| 3| how are you uma|
+---+-----------------+
答案 2 :(得分:0)
我假设下面的代码可以解决您的问题
我已经通过使用RDD
解决了这个问题 val wordRdd = df1.rdd.flatMap{ row =>
val wordList = row.getAs[String]("Text").split(" ").toList
wordList.map{word => Row.fromTuple(row.getAs[Int]("id"),word)}
}.zipWithIndex()
val wordDf = sqlContext.createDataFrame(wordRdd.map(x => Row.fromSeq(x._1.toSeq++Seq(x._2))),StructType(List(StructField("id",IntegerType),StructField("word",StringType),StructField("index",LongType))))
val opRdd = wordDf.join(df2,wordDf("word")===df2("word"),"left_outer").drop(df2("word")).rdd.groupBy(_.getAs[Int]("id")).map(x => Row.fromTuple(x._1,x._2.toList.sortBy(x => x.getAs[Long]("index")).map(row => if(row.getAs[String]("Replace")!=null) row.getAs[String]("Replace") else row.getAs[String]("word")).mkString(" ")))
val opDF = sqlContext.createDataFrame(opRdd,StructType(List(StructField("id",IntegerType),StructField("Text",StringType))))