使用Spark Scala中另一个数据框中的单词列表替换数据框中的单词

时间:2017-07-14 07:40:35

标签: scala apache-spark spark-dataframe

我有两个数据帧,比如说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中执行相同的操作非常感谢您的帮助。

3 个答案:

答案 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))))