如何将RDD [Array [String]]转换为RDD [(Int,HashMap [String,List])]?

时间:2018-06-17 21:17:33

标签: scala list apache-spark hashmap

我有输入数据:

time, id, counter, value
00.2,  1 , c1     ,  0.2
00.2,  1 , c2     ,  0.3
00.2,  1 , c1     ,  0.1

我希望每个id都能创建一个存储计数器和值的结构。在考虑了载体并拒绝它们之后,我来到了这个:

(id, Hashmap( (counter1, List(Values)), (Counter2, List(Values)) ))
(1, HashMap( (c1,List(0.2, 0.1)), (c2,List(0.3)))

问题在于我无法在地图转换中转换为Hashmap,另外我不知道我是否能够通过计数器来减少地图中的列表。

有没有人有任何想法?

我的代码是:

val data = inputRdd
          .map(y => (y(1).toInt, mutable.HashMap(y(2), List(y(3).toDouble)))).reduceByKey(_++_)
  }

3 个答案:

答案 0 :(得分:0)

脱离我的头顶,未经测试:

import collection.mutable.HashMap

inputRdd
  .map{ case Array(t, id, c, v) => (id.toInt, (c, v)) }
  .aggregateByKey(HashMap.empty[String, List[String]])(
    { case (m, (c, v)) => { m(c) ::= v; m } },
    { case (m1, m2) => { for ((k, v) <- m2) m1(k) ::= v ; m1 } }
  )

答案 1 :(得分:0)

这是一种方法:

val rdd = sc.parallelize(Seq(
  ("00.2", 1, "c1", 0.2),
  ("00.2", 1, "c2", 0.3),
  ("00.2", 1, "c1", 0.1)
))

rdd.
  map{ case (t, i, c, v) => (i, (c, v)) }.
  groupByKey.mapValues(
    _.groupBy(_._1).mapValues(_.map(_._2)).map(identity)
  ).
  collect
// res1: Array[(Int, scala.collection.immutable.Map[String,Iterable[Double]])] = Array(
//   (1,Map(c1 -> List(0.2, 0.1), c2 -> List(0.3)))
// )

请注意,最终map(identity)是针对此Map#mapValues not serializable problem中建议的SO answer的补救措施。

答案 2 :(得分:0)

正如您所提到的,如果inputRdd

//inputRdd: org.apache.spark.rdd.RDD[Array[String]] = ParallelCollectionRDD[0] at parallelize at ....

然后,分组值上的简单groupByfoldLeft应该可以帮助您获得最终所需的结果

val resultRdd = inputRdd.groupBy(_(1))
                          .mapValues(x => x
                            .foldLeft(Map.empty[String, List[String]]){(a, b) => {
                              if(a.keySet.contains(b(2))){
                                val c = a ++ Map(b(2) -> (a(b(2)) ++ List(b(3))))
                                c
                              }
                              else{
                                val c = a ++ Map(b(2) -> List(b(3)))
                                c
                              }
                            }}
                          )
//resultRdd: org.apache.spark.rdd.RDD[(String, scala.collection.immutable.Map[String,List[String]])] = MapPartitionsRDD[3] at mapValues at ...
//(1,Map(c1 -> List(0.2, 0.1), c2 -> List(0.3)))

RDD[(String, scala.collection.immutable.Map[String,List[String]])]更改为RDD[(Int, HashMap[String,List[String]])]只会投出,我希望您这样做更容易

我希望答案很有帮助