火花。将RDD分成批次

时间:2017-11-13 14:00:40

标签: apache-spark rdd batching

我有RDD,其中每条记录都是int:

[0,1,2,3,4,5,6,7,8]

我需要做的就是将这个RDD拆分成批。即制作另一个RDD,其中每个元素都是固定大小的元素列表:

[[0,1,2], [3,4,5], [6,7,8]]

这听起来微不足道,然而,我在最近几天感到困惑,除了以下解决方案之外找不到任何东西:

  1. 使用ZipWithIndex枚举RDD中的记录:

    [0,1,2,3,4,5] -> [(0, 0),(1, 1),(2, 2),(3, 3),(4, 4),(5, 5)]

  2. 使用map()迭代此RDD并计算类似index = int(index / batchSize)的索引

    [1,2,3,4,5,6] -> [(0, 0),(0, 1),(0, 2),(1, 3),(1, 4),(1, 5)]

  3. 然后按生成的索引进行分组。

    [(0, [0,1,2]), (1, [3,4,5])]

  4. 这将得到我所需要的,但是,我不想在这里使用组。当你使用普通的Map Reduce或像Apache Crunch这样的抽象时,这是微不足道的。但有没有办法在不使用重组的情况下在Spark中产生类似的结果?

2 个答案:

答案 0 :(得分:0)

你没有清楚地解释为什么你需要固定大小的RDD,取决于你想要实现的目标可以有更好的解决方案,但是为了回答问题,我看到以下选项:
1)根据项目数和批量大小实现过滤器。例如,如果您在原始RDD中有1000个项目并且想要将它们拆分为10个批次,则最终将应用10个过滤器,第一个检查索引是否为[0,99],第二个是[100,199]等等。应用每个过滤器后,您将拥有一个RDD。需要注意的是,原始RDD可能会在过滤之前被缓存。优点:每个生成的RDD可以单独处理,不必在一个节点上完全分配。缺点:这种方法随着批次数的增加而变慢 2)逻辑上与此类似,但是您只需实现一个自定义分区程序,它根据索引(键)返回分区ID,如下所述:Custom partitioner for equally sized partitions,而不是过滤器。优点:比过滤器更快。缺点:每个分区必须适合一个节点 3)如果原始RDD中的顺序不重要并且只需要大致相同的分块,您可以合并/重新分区,在此解释https://jaceklaskowski.gitbooks.io/mastering-apache-spark/spark-rdd-partitions.html

答案 1 :(得分:0)

也许您可以使用aggregateByKey,在这种情况下,它比groupByKey更快,更轻便。 我试图用10个执行程序将5亿个数据分成256个大小的批处理,只用了半个小时就完成了。

data = data.zipWithIndex().map(lambda x: (x[1] / 256, x[0]))
data = data.aggregateByKey(list(), lambda x, y: x + [y], add)

有关更多信息,请参见 Spark difference between reduceByKey vs groupByKey vs aggregateByKey vs combineByKey