在Scala for Spark

时间:2015-08-20 14:53:38

标签: scala functional-programming apache-spark

所以我有一些表格的表格数据:

node    parent   value
c1      p1       2
p1               3
c2      p1       1
c11     c1       1
c12     c1       1

如果有一个由节点和父列表示的树(父节点可能有多少个子节点),并且每个子节点的值总和=父节点的值。 (我的意思是,这应该是正确的但它可能没有,这就是我想要检查的内容)

我想做的事情:

我想检查一下"每个孩子的价值总和=父母的价值"对输入数据中给出的每个父项都成立。

我在Spark中使用Scala实现这个逻辑,所以我想在功能上实现它。

到目前为止我做了什么:

输入是一个csv文件,我从中创建一个数据帧,并执行以下操作,给我,parent =>孩子的名单,这是我知道我需要的信息。

tree = fileDataFrame.select(parent, node).map( x => (x(0), x(1)).groupByKey()

同样我得到了,node =>价值,这也是有用的信息:

values = fileDataFrame.select(node, value).map( x => (x(0), x(1))

我被困在哪里离开这里。我想要添加所有孩子的值(使用reduceByKey即时猜测),但我还没有设置,因为我有父=>孩子的名单,我需要parent =>儿童价值观清单。

我对函数式编程很陌生,所以我的大脑仍然在循环中思考。

实施此检查的好方法是什么? Spark允许以下转换(http://spark.apache.org/docs/latest/programming-guide.html#transformations

提前致谢,欢迎提出任何建议!

2 个答案:

答案 0 :(得分:2)

我不是理解你的问题,但我认为以下方法应该有效。

首先使用以下架构创建数据框

root
 |-- node: string (nullable = true)
 |-- parent: string (nullable = true)
 |-- value: integer (nullable = true)

汇总儿童数据:

val children = df.groupBy($"parent").agg(sum($"value").alias("csum"))

加入原始数据:

df
  .select($"node", $"value")
  .join(children, df("node") <=> children("parent"))
  .select($"node", ($"value" === $"csum").alias("holds"))

as suggested的GraphX @mattinbits类似的解决方案:

import org.apache.spark._
import org.apache.spark.graphx._
import org.apache.spark.rdd.RDD

val nodes: RDD[(VertexId, (String, Int))] = sc.parallelize(Array(
    (0L, ("p1", 3)),
    (1L, ("c1", 2)),
    (2L, ("c2", 1)),
    (11L, ("c11",  1)),
    (12L, ("c12", 1))
))

val relationships: RDD[Edge[String]] = sc.parallelize(Array(
    Edge(1L, 0L, "child"),
    Edge(2L, 0L, "child"),
    Edge(11L, 1L, "child"),
    Edge(12L, 1L, "child")
))

val graph = Graph(nodes, relationships)


graph.aggregateMessages[(Int, Int)](
    triplet => triplet.sendToDst(triplet.dstAttr._2, triplet.srcAttr._2),
    (a, b) => (a._1,  a._2 + b._2)
).map{case (id, (expected, actual)) => expected == actual}.reduce(_ & _)

答案 1 :(得分:1)

尝试:

val nodeParents: RDD[(String, String, Long)] = // ...
val nodes: RDD[(String, Long)] = nodeParents.map { case(n, _, v) => (n, v) }
val parents: RDD[(String, Long)] = nodeParents.filter { case(_, p, _) => p != ""}
                                              .map { case(_, p, v) => (p, v) }
                                              .reduceByKey(_ + _)
val joined: RDD[(String, (Long, Long))] = parents.join(nodes)

对于你的例子:

> nodes: [(c1, 2), (p1, 3), (c2, 1), (c11, 1), (c12, 1)]
> parents: [(c1, 2), (p1, 3)]
> joined: [(c1, (2, 2)), (p1, (3, 3))]