带有自定义分区程序的 Spark RDD(不是 PairRDD)

Spark RDD (not a PairRDD) with a custom Partitioner

我可以创建带有自定义 Partitioner 的 Spark RDD(不是 PairRDD)吗?我似乎没有在 API 中找到任何允许这样做的东西...... partitionBy 方法仅适用于 PairRDDs

AFAIK,你不能,我的理解如下:

当 Apache Spark 读取数据时,它会将数据视为一种黑盒*。所以框架无法在最开始的步骤说 "Oh, here I've a line X, so I have to put it into the partition 1" ,它不知道它里面是什么。相反,该框架将使用许多不同的参数,如分区数、拆分大小等,以确定在每个任务中应从给定源读取多少数据(参数将取决于源)。因此,我们的想法是将大数据集的较小部分分配到任务(分区)中,而不是分析每个 line/row/record/whatever 并说明它可以着陆的位置。即使对于像 Apache Kafka 这样的原生分区数据源,Spark 也是这样工作的,即不解释分区数据。 IMO 这是分布式数据处理框架和分布式数据存储之间的主要区别之一,有时您可以定义自己的分区逻辑,但这只是因为您接收的是一些特定数据而不是 "bag" 数据。换句话说,Spark 的分区更依赖于数据源分区逻辑,以利用源的并行性进行初始读取。

还有一点,明确的partitionBy也是你的意图。通过这样做,您是在说管道需要在同一分区中包含此特定键的所有数据,因此您可以进行聚合操作或任何其他分组操作。

此外,如果您看一下 org.apache.spark.rdd.RDD#partitioner,您会发现它主要用于涉及随机播放的操作 - 这是用户想要的。不用于分配最开始计算时读取的数据。

因此 sum-up 并澄清一点,我会区分 2 个类别进行分区。第一个涉及数据源,在这里您需要使用框架公开的配置属性。第二个是业务逻辑分区器,在将平面 RDD 转换为一对 RDD 之后,这里的操作被视为分组操作,因为它表达了将所有相似数据放在同一分区上以对其执行某些操作的意图(聚合, 会话生成, ...)

* - 并非总是如此。例如,当您将 JDBC 与 Spark SQL 一起使用时,您可以定义一个用于分区的列,该列将用作一种带键的范围分区。但这更多要归功于存储的组织(结构化数据)。

恐怕你做不到。这就是 API 的设计方式。您需要在记录上放置一个标签,这样您就可以说您想将它发送到给定的分区。

除非你有信件上的邮政编码,否则邮递员无法决定将信件寄往哪个地点。

如果您的 RDD 中自然没有密钥,您可以使用以下 API 以编程方式创建它们 -

zipWithIndex()
zipWithUniqueId()