我在Spark shell中使用Scala。我将数据减少到RDD,byHour: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[47] at reduceByKey at <console>:16
或者如果收集了数组byHour: Array[(String, Int)]
,则看起来像:
Array((6497+2006-03-19 20:00,13), (7511+2006-03-17 02:00,1), (13508+2006-03-26 10:00,4), (217+2006-05-16 16:00,1), (12404+2006-03-27 15:00,1), (9777+2006-05-14 09:00,1), (10291+2006-03-03 17:00,2), (4781+2006-05-10 14:00,2), (10291+2006-04-26 17:00,1), (15198+2006-04-26 12:00,1))
我想将它存储在Python或csv文件中的嵌套字典中。
在Python中我会创建
{"6497": {"2006-03-19 20:00": 13, "2006-03-19 22:00": 1}, "7511": {"2006-03-17 02:00": 1}...}
最后我想要
userid, 2006-03-17 01:00, 2006-03-17 02:00, ... , 2006-03-19 20:00, 2006-03-19 21:00, 2006-03-19 22:00
6497,0,0, ..., 13,0,1
7511,0,1, ..., 0,0,0
我不确定如何在Scala中到达那里。我想我需要一个列表或一组哈希映射或一个hashMap [String =&gt; HashMap中。
更新: byHour是RDD [(String,Int)]
val byUserHour = byHour.map(x => (x._1.split("\\+")(0),(x._1.split("\\+")(1),x._2)))
val byUser = byUserHour.groupByKey
val times = byHour.map(x => x._1.split("\\+")(1)).distinct.collect.sortWith(_ < _)
val broadcastTimes = sc.broadcast(times)
val userMaps = byUser.mapValues {
x => x.map{
case(time,cnt) => time -> cnt
}.toMap
}
val result = userMaps.map {
case(u,ut) => (u +: broadcastTimes.value.map(ut.getOrElse(_,0).toString))}
val lines = result.map(_.mkString(","))
val header = List("userid") ::: times.toList
答案 0 :(得分:2)
首先,您将拆分用户ID,因此您获得data: Seq[(String, String, Int)]
。然后,按用户ID分组:
val byUser: Map[String, Seq[(String, String, Int)]] = data.groupBy(_._1)
现在我们可以为每个用户创建一个地图:
val userMaps: Map[String, Map[String, Int]] = byUser.mapValues {
s => s.map {
case (user, time, n) => time -> n
}.toMap
}
对于最终格式化,您首先需要获取不同的时间戳,然后在每个用户的地图中查看这些时间戳:
val times: Seq[String] = data.map(_._2).toSet.toList
val result: Seq[Seq[String]] = userMaps.toSeq.map {
case (u, ut) => (u +: times.map(ut.getOrElse(_, 0).toString))
}
val lines: Seq[String] = result.map(_.mkString(","))
希望这足以让你入门。您可以在http://twitter.github.io/scala_school/collections.html(以及许多其他地方)阅读有关Scala集合的更多信息。
以上所有内容都是本地计算 - 根本不分发。要以分布式方式执行相同操作,您可以在开始时将数据读入RDD(sc.textFile()
),并执行大致相同的操作序列。
一个细微差别是,groupBy
代替groupByKey
,而RDD[A, B]
的行为略有不同。从RDD[A, Iterable[B]]
开始,您获得Map[A, Seq[(A, B)]]
,而不是times
。
主要区别在于您需要从群集中收集val times: Seq[String] = data.map(_._2).distinct.collect
val broadcast = sc.broadcast(times)
val result: RDD[Seq[String]] = userMaps.map {
val times = broadcast.value
case (u, ut) => (u +: times.map(ut.getOrElse(_, 0).toString))
}
到应用程序,然后将其广播到所有节点:
{{1}}