如何使用scala从RDD [String]创建地图?

时间:2014-11-11 10:53:52

标签: scala

我的档案是,

sunny,hot,high,FALSE,no
sunny,hot,high,TRUE,no
overcast,hot,high,FALSE,yes
rainy,mild,high,FALSE,yes
rainy,cool,normal,FALSE,yes
rainy,cool,normal,TRUE,no
overcast,cool,normal,TRUE,yes

这里有7排& 5列(0,1,2,3,4)

我希望输出为,

Map(0 -> Set("sunny","overcast","rainy"))
Map(1 -> Set("hot","mild","cool"))
Map(2 -> Set("high","normal"))
Map(3 -> Set("false","true"))
Map(4 -> Set("yes","no"))

输出必须是[Map [Int,Set [String]]]

的类型

2 个答案:

答案 0 :(得分:4)

编辑:重写以首先展示map-reduce版本,因为它更适合Spark

由于这是Spark,我们可能对并行/分发感兴趣。所以我们需要注意启用它。

将每个字符串拆分为单词可以在分区中完成。获取每列中使用的值集更加棘手 - 初始化集合然后添加每行中的每个值的天真方法本质上是串行/本地,因为我们只有一组(每列)&# 39;重新添加每行的值。

但是,如果我们为行的某些部分设置了集合,而为其余部分设置了集合,那么答案就是这些集合的并集。这表示减少操作,我们合并行的某些子集的集合,然后合并这些,依此类推,直到我们有一个集合。

所以,算法:

  • 将每一行拆分为一个字符串数组,然后将其更改为一个 每列的单个字符串值的数组 - 这可以 一切都用一张地图完成,然后分发。
  • 现在使用一个减少这个 依次合并每列的集合的操作。这也可以 分发
  • 将产生的单行转换为Map

我们做地图然后是减少并不是巧合,这应该提醒你一些事情:)

这是一个产生单行的单行:

val data = List(
"sunny,hot,high,FALSE,no",
"sunny,hot,high,TRUE,no",
"overcast,hot,high,FALSE,yes",
"rainy,mild,high,FALSE,yes",
"rainy,cool,normal,FALSE,yes",
"rainy,cool,normal,TRUE,no",
"overcast,cool,normal,TRUE,yes") 

val row = data.map(_.split("\\W+").map(s=>Set(s)))
              .reduce{(a, b) => (a zip b).map{case (l, r) => l ++ r}}

将问题转换为地图,问题是:

val theMap = row.zipWithIndex.map(_.swap).toMap
  • 使用索引压缩列表,因为这是我们需要的密钥 地图。
  • 遗憾的是,每个元组的元素都是错误的 订购.toMap,所以交换它们。
  • 然后我们有一个(键,值)列表 .toMap将成为所需结果的对。

这些不需要更改AT ALL以与Spark一起使用。我们只需要使用RDD而不是List。让我们将数据转换为RDD只是为了演示这个:

val conf = new SparkConf().setAppName("spark-scratch").setMaster("local")
val sc= new SparkContext(conf)
val rdd = sc.makeRDD(data)

val row = rdd.map(_.split("\\W+").map(s=>Set(s)))
             .reduce{(a, b) => (a zip b).map{case (l, r) => l ++ r}}

(这可以像以前一样转换成地图)

早期的oneliner工作得很整齐(转置正是这里所需要的)但很难分发(转置本身就需要访问每一行)

data.map(_.split("\\W+")).transpose.map(_.toSet)

(为清晰起见省略转换为地图)

  • 将每个字符串拆分为单词。
  • 转置结果,所以我们有一个列表,其中包含第一个单词的列表,然后是第二个单词的列表等。
  • 将每个转换为一组。

答案 1 :(得分:1)

也许这就是诀窍:

    val a = Array(
      "sunny,hot,high,FALSE,no",
      "sunny,hot,high,TRUE,no",
      "overcast,hot,high,FALSE,yes",
      "rainy,mild,high,FALSE,yes",
      "rainy,cool,normal,FALSE,yes",
      "rainy,cool,normal,TRUE,no",
      "overcast,cool,normal,TRUE,yes")

    val b  = new Array[Map[String, Set[String]]](5)

    for (i <- 0 to 4)
      b(i) = Map(i.toString -> (Set() ++ (for (s <- a) yield s.split(",")(i))) )

    println(b.mkString("\n"))