如何在Spark中按键分区RDD?

时间:2015-09-12 22:18:50

标签: scala apache-spark rdd

鉴于HashPartitioner文档说:

  

[HashPartitioner]使用Java实现基于散列的分区   是Object.hashCode。

假设我想按DeviceData分区kind

case class DeviceData(kind: String, time: Long, data: String)

通过覆盖RDD[DeviceData]方法并仅使用deviceData.hashCode()的哈希码来对kind进行分区是否正确?

但鉴于HashPartitioner需要多个分区参数,我很困惑我是否需要事先知道种类的数量以及如果种类多于分区会发生什么?

如果我将分区数据写入磁盘,它会在读取时保持分区吗?

我的目标是致电

  deviceDataRdd.foreachPartition(d: Iterator[DeviceData] => ...)

在迭代器中只有DeviceDatakind个值。

2 个答案:

答案 0 :(得分:8)

使用1 10 2 20 ... A B ... groupByKey怎么样?或者另一种kind方法。

在我看来,你并不真正关心分区,只是你在一个处理流程中得到了所有特定的类型?

配对功能允许:

PairRDDFunctions

然而,你可能会更安全一点,比如:

rdd.keyBy(_.kind).partitionBy(new HashPartitioner(PARTITIONS))
   .foreachPartition(...)

rdd.keyBy(_.kind).reduceByKey(....) 或其他一对保证您整体获得作品的功能

答案 1 :(得分:7)

  

通过覆盖deviceData.hashCode()方法对RDD [DeviceData]进行分区并仅使用类型的哈希码是否正确?

不会。如果您使用Java Object.hashCode文档,您将找到有关hashCode的一般合同的以下信息:

  

如果两个对象根据equals(Object)方法相等,则对两个对象中的每个对象调用hashCode方法必须生成相同的整数结果。

因此,除非纯粹基于kind设备的平等概念符合您的使用案例,并且我严重怀疑它,修补HashCode以获得所需的分区是一个坏主意。一般情况下,您应implement your own partitioner,但此处不需要。

由于不包括SQL和GraphX中的特殊方案,partitionBy仅在PairRDD上有效,因此创建RDD[(String, DeviceData)]并使用普通HashPartitioner

是有意义的
deviceDataRdd.map(dev => (dev.kind, dev)).partitionBy(new HashPartitioner(n))

请记住,在kind具有低基数或使用它进行分区的高度偏斜分布的情况下,可能不是最佳解决方案。