所以,我当前的代码看起来像
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 的经验很少,所以我实际上不知道如何将其写入代码。
如上所述,我想让文档名称成为地图中的键,以便更轻松地访问计数。
答案 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)