Scala 如何将RDD[Array[String]]转换为RDD[(Int,HashMap[String,List])?
我有输入数据:Scala 如何将RDD[Array[String]]转换为RDD[(Int,HashMap[String,List])?,scala,list,apache-spark,hashmap,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
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(_++_)
}
在我的头顶上,未经测试:
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 } }
)
import collection.mutable.HashMap
输入
.map{case数组(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)这里有一种方法:
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)
是本文建议的补救措施。如果如您所述,将inpurdd
作为
//inputRdd: org.apache.spark.rdd.RDD[Array[String]] = ParallelCollectionRDD[0] at parallelize at ....
然后,对分组值执行一个简单的groupBy
和foldLeft
,就可以获得最终的预期结果
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]]]]]]
将只是强制转换,我希望您可以更轻松地执行此操作
我希望答案是有帮助的为什么RDDAPI不是DataFrame/Dataset?!为什么要考虑替换a.keySet.contains(b(2))
withmutable.Map
and?@JacekLaskowski感谢您的回复,如果键存在,getOrElseUpdate将返回我的值,否则值是新操作,但是如果键存在,场景就像添加新列表。我只是不知道您的信息如何有助于改进答案?您为什么考虑repl用case
加下划线?这会提高可读性,从而提高理解能力吗?@Jacek Laskowski,为了可读性,我通常更喜欢使用case和更有意义的变量,而不是元组访问器(特别是当元组大小大于2和/或转换涉及分组/位置洗牌时)。