Hadoop 将项目发送到特定分区

Hadoop 将项目发送到特定分区,hadoop,apache-spark,hdfs,Hadoop,Apache Spark,Hdfs,我正在寻找一种将结构发送到预定义分区的方法,以便其他RDD可以使用它们 假设我有两个RDD的键值对 val a:RDD[(Int, Foo)] val b:RDD[(Int, Foo)] val aStructure = a.reduceByKey(//reduce into large data structure) b.mapPartitions{ iter => val usefulItem = aStructure(samePartitionKey)

我正在寻找一种将结构发送到预定义分区的方法,以便其他RDD可以使用它们

假设我有两个RDD的键值对

val a:RDD[(Int, Foo)]
val b:RDD[(Int, Foo)]

val aStructure = a.reduceByKey(//reduce into large data structure)
b.mapPartitions{
    iter =>
         val usefulItem = aStructure(samePartitionKey)
         iter.map(//process iterator) 
}
我如何设置分区,使我需要的特定数据结构出现在mapPartition中,但我不会有发送所有值的额外开销(如果我创建一个广播变量,就会发生这种情况)

我的一个想法是将对象存储在HDFS中,但我不确定这是否是一个次优的解决方案

我目前正在探索的另一个想法是,是否有某种方法可以创建一个自定义分区或分区器来保存数据结构(尽管这可能会变得太复杂,并产生问题)

谢谢你的帮助

编辑:


Pangea提出了一个非常好的观点,我应该提供更多的细节。基本上,我给出了稀疏向量的RDD和反向索引的RDD。反向索引对象相当大

我希望在向量的RDD中做一个映射分区,在这里我可以将每个向量与反向索引进行比较。问题是,每个分区只需要一个反向索引对象,而进行连接会导致该索引有很多副本

val vectors:RDD[(Int, SparseVector)]

val invertedIndexes:RDD[(Int, InvIndex)] = a.reduceByKey(generateInvertedIndex)
vectors:RDD.mapPartitions{
    iter =>
         val invIndex = invertedIndexes(samePartitionKey)
         iter.map(invIndex.calculateSimilarity(_))
         ) 
}

Partitioner
是一个函数,给定一个泛型元素,它将返回它所属的分区。它还决定分区的数量。 有一种形式的
reduceByKey
,它将分区器作为参数。 如果我正确理解了您的问题,那么您希望在执行reduce时对数据进行分区。 请参见示例:

// create example data
val a =sc.parallelize(List( (1,1),(1,2), (2,3),(2,4) ) )
// create simple sample partitioner - 2 partitions, one for odd
// one for even key.hashCode. You should put your partitioning logic here
val p = new Partitioner { def numPartitions: Int = 2; def getPartition(key:Any) = key.hashCode % 2 }
// your reduceByKey function. Sample: just add
val f = (a:Int,b:Int) => a + b
val rdd = a.reduceByKey(p, f)
// here your rdd will be partitioned the way you want with the number
// of partitions you want
rdd.partitions.size
res8: Int = 2

rdd.map() .. // go on with your processing

Partitioner
是一个函数,给定一个泛型元素,它将返回它所属的分区。它还决定分区的数量。 有一种形式的
reduceByKey
,它将分区器作为参数。 如果我正确理解了您的问题,那么您希望在执行reduce时对数据进行分区。 请参见示例:

// create example data
val a =sc.parallelize(List( (1,1),(1,2), (2,3),(2,4) ) )
// create simple sample partitioner - 2 partitions, one for odd
// one for even key.hashCode. You should put your partitioning logic here
val p = new Partitioner { def numPartitions: Int = 2; def getPartition(key:Any) = key.hashCode % 2 }
// your reduceByKey function. Sample: just add
val f = (a:Int,b:Int) => a + b
val rdd = a.reduceByKey(p, f)
// here your rdd will be partitioned the way you want with the number
// of partitions you want
rdd.partitions.size
res8: Int = 2

rdd.map() .. // go on with your processing

你好@RobertoCongiu,这有点接近我想要的。问题是,一旦我将减少的值放入正确的分区中。我希望以后能够在不同RDD上进行映射分区时访问这些本地化值。你对我怎么做有什么想法吗?你到底需要用另一个RDD做什么?如果你需要连接两个
RDD
s,你不需要在上面做mapPartitions,因为
join
足够聪明,可以检测到RDD具有相同的分区器。基本上,我给出了SparseVector的RDD和反向索引的RDD。反向索引对象相当大。我希望在向量的RDD中做一个映射分区,在这里我可以将每个向量与反向索引进行比较。问题是,我每个分区只需要一个反向索引对象,而进行连接会导致该索引有很多副本。因此,每个分区有一个大型反向索引,每个索引都需要由每个执行器加载。反向索引有多大?这取决于用户创建的桶有多大。bucket是总向量空间的预定义百分比(因此,如果有1000个向量,并且用户决定需要10个bucket,则每个bucket将容纳100个值)。当然,它需要存储在单个对象中,但仍然可以相当大。问题是,一旦我将减少的值放入正确的分区中。我希望以后能够在不同RDD上进行映射分区时访问这些本地化值。你对我怎么做有什么想法吗?你到底需要用另一个RDD做什么?如果你需要连接两个
RDD
s,你不需要在上面做mapPartitions,因为
join
足够聪明,可以检测到RDD具有相同的分区器。基本上,我给出了SparseVector的RDD和反向索引的RDD。反向索引对象相当大。我希望在向量的RDD中做一个映射分区,在这里我可以将每个向量与反向索引进行比较。问题是,我每个分区只需要一个反向索引对象,而进行连接会导致该索引有很多副本。因此,每个分区有一个大型反向索引,每个索引都需要由每个执行器加载。反向索引有多大?这取决于用户创建的桶有多大。bucket是总向量空间的预定义百分比(因此,如果有1000个向量,并且用户决定需要10个bucket,则每个bucket将容纳100个值)。当然,它需要存储在单个对象中,但仍然可能相当大。请给我们一个示例,说明您对Astrestructure等中的数据的期望值。示例为您提供更多答案请给我们一个示例,说明您对Astrestructure等中的数据的期望值。示例为您提供更多答案