Spark (Scala) 将具有重复项的列表转换为 (list_entry, count) 的映射

时间:2021-05-30 09:47:20

标签: scala apache-spark

所以,我当前的代码看起来像

exec('import '+filename_without_py)

它读入 val tokens = .read.option("wholetext", true).textFile(path) .flatMap(line => line.split(" ") .withColumn("filename", substring_index(input_file_name, "/", -1)) .groupBy(col("value")) .agg(collect_list("filename") as "docs") 中的所有文本文档并创建一个如下所示的 Dataframe:

path

现在我想获取列表并将它们简化为这样的(抱歉,我实际上不知道 Scala 中的地图是什么样子)

|word1   |[1.txt]                            |
|word2   |[2.txt]                            |
|word3   |[2.txt, 1.txt, 1.txt]              |

理论上我知道该怎么做:获取列表条目,将它们映射到 (entry, 1) 然后通过将计数相加来减少它们。但我对 Scala 的经验很少,所以我实际上不知道如何将其写入代码。

如上所述,我想让文档名称成为地图中的键,以便更轻松地访问计数。

1 个答案:

答案 0 :(得分:3)

这样应该就可以了,得到一个Array,就可以转换成Map了。在这里,您得到一个字符串数组,您需要根据逗号将其拆分为 2 个字段,并在 Spark Scala Dataframe convert a column of Array of Struct to a column of Map 中寻找指导,我对此表示赞同。您也可以使用 struct 代替 Array

import org.apache.spark.sql.functions._
val df = spark.read.textFile("/FileStore/tables/fff1.txt", "/FileStore/tables/fff2.txt")
val df2 = df.flatMap(_.split(" ")).withColumn("filename", input_file_name).groupBy("Value", "filename").count()
val df3 = df2.groupBy("Value").agg(collect_list(array("filename", "count")) as "docs")
df3.show(false)

返回:

+-----+----------------------------------------------------------------------------+
|Value|docs                                                                        |
+-----+----------------------------------------------------------------------------+
|you  |[[dbfs:/FileStore/tables/fff2.txt, 2], [dbfs:/FileStore/tables/fff1.txt, 1]]|
|fine |[[dbfs:/FileStore/tables/fff2.txt, 1], [dbfs:/FileStore/tables/fff1.txt, 1]]|
|how  |[[dbfs:/FileStore/tables/fff2.txt, 1], [dbfs:/FileStore/tables/fff1.txt, 1]]|
|hear |[[dbfs:/FileStore/tables/fff2.txt, 1], [dbfs:/FileStore/tables/fff1.txt, 1]]|
|ok   |[[dbfs:/FileStore/tables/fff2.txt, 1]]                                      |
|have |[[dbfs:/FileStore/tables/fff2.txt, 1]]                                      |
...

为了完整性,获取地图:

import org.apache.spark.sql.functions._
import org.apache.spark.sql.types._

val arrayToMap = udf[Map[String, Long], Seq[Row]] {
  array => array.map { case Row(key: String, value: Long) => (key, value) }.toMap
}

val df = spark.read.textFile("/FileStore/tables/fff1.txt", "/FileStore/tables/fff2.txt")
val df2 = df.flatMap(_.split(" ")).withColumn("filename", input_file_name).groupBy("Value", "filename").count()
val df3 = df2.groupBy("Value").agg(collect_list(struct("filename", "count")))   

val df4 = df3.withColumn("words", arrayToMap($"collect_list(struct(filename, count))"))
df4.show(false)