Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark 如何分割一个巨大的rdd并轮流播放?_Apache Spark - Fatal编程技术网

Apache spark 如何分割一个巨大的rdd并轮流播放?

Apache spark 如何分割一个巨大的rdd并轮流播放?,apache-spark,Apache Spark,说明: 我们的spark版本是1.4.1 我们想要连接两个巨大的RDD,其中一个带有倾斜数据。因此,spark rdd操作连接可能会导致内存问题。我们试着把一个小的分成几块,然后分批播放。在每个广播回合中,我们尝试收集一部分较小的rdd到驱动程序,然后将其保存到HashMap,然后广播HashMap。每个执行器使用广播值对较大的rdd进行映射操作。我们通过这种方式实现了倾斜数据连接 但当它处理每一轮的广播值时。我们发现,我们不能破坏我们的广播价值后处理。如果我们使用broadcast.destr

说明

我们的spark版本是1.4.1

我们想要连接两个巨大的RDD,其中一个带有倾斜数据。因此,spark rdd操作连接可能会导致内存问题。我们试着把一个小的分成几块,然后分批播放。在每个广播回合中,我们尝试收集一部分较小的rdd到驱动程序,然后将其保存到HashMap,然后广播HashMap。每个执行器使用广播值对较大的rdd进行映射操作。我们通过这种方式实现了倾斜数据连接

但当它处理每一轮的广播值时。我们发现,我们不能破坏我们的广播价值后处理。如果我们使用broadcast.destroy(),下一步我们将处理数据 触发错误。像这样:

java.io.IOException: org.apache.spark.SparkException: Attempted to use Broadcast(6) after it was destroyed (destroy at xxx.java:369)
for (int i = 0; i < times; i++) {
    JavaPairRDD<Tuple2<String, String>, Double> prevItemPairRdd = curItemPairRdd;
    List<Tuple2<String, Double>> itemSplit = itemZippedRdd
            .filter(new FilterByHashFunction(times, i))
            .collect();

    Map<String, Double> itemSplitMap = new HashMap<String, Double>();
    for (Tuple2<String, Double> item : itemSplit) {
        itemSplitMap.put(item._1(), item._2());
    }
    Broadcast<Map<String, Double>> itemSplitBroadcast = jsc
            .broadcast(itemSplitMap);

    curItemPairRdd = prevItemPairRdd
            .mapToPair(new NormalizeScoreFunction(itemSplitBroadcast))
            .persist(StorageLevel.DISK_ONLY());
    curItemPairRdd.count();

    itemSplitBroadcast.destroy(true);
    itemSplit.clear();

}
我们查看了spark的源代码,发现这个问题是由rdd依赖关系导致的。如果rdd3->rdd2->rdd1(箭头显示相关性)。rdd1是使用名为b1的广播变量生成的,rdd2是使用b2生成的。在生成rdd3时,源代码显示需要序列化b1和b2。如果b1或b2在rdd3生产过程之前被破坏。它将导致我上面列出的故障

问题

它是否存在这样一种方式,可以让rdd3忘记它的依赖关系,使它在生产过程中不需要b1、b2,只需要rdd2

或者它是否存在一种处理偏斜连接问题的方法

顺便说一句,我们已经为每个回合设置了检查点。并将spark.cleaner.ttl设置为600。问题仍然存在。若我们不销毁广播变量,执行器将在第五轮中丢失

我们的代码如下:

java.io.IOException: org.apache.spark.SparkException: Attempted to use Broadcast(6) after it was destroyed (destroy at xxx.java:369)
for (int i = 0; i < times; i++) {
    JavaPairRDD<Tuple2<String, String>, Double> prevItemPairRdd = curItemPairRdd;
    List<Tuple2<String, Double>> itemSplit = itemZippedRdd
            .filter(new FilterByHashFunction(times, i))
            .collect();

    Map<String, Double> itemSplitMap = new HashMap<String, Double>();
    for (Tuple2<String, Double> item : itemSplit) {
        itemSplitMap.put(item._1(), item._2());
    }
    Broadcast<Map<String, Double>> itemSplitBroadcast = jsc
            .broadcast(itemSplitMap);

    curItemPairRdd = prevItemPairRdd
            .mapToPair(new NormalizeScoreFunction(itemSplitBroadcast))
            .persist(StorageLevel.DISK_ONLY());
    curItemPairRdd.count();

    itemSplitBroadcast.destroy(true);
    itemSplit.clear();

}
for(int i=0;i
就个人而言,我会尝试一些不同的方法。让我们从一个小的模拟数据集开始

导入scala.util.Random
随机设定速度(1)
val left=sc.parallelize(
顺序填充(200)(“a”,随机填充(100))++
顺序填充(150)(“b”,随机填充(100))++
序列填充(100)(Random.nextPrintableChar.toString,Random.nexttint(100))
)
和按键计数:

val keysDistribution=left.countByKey
进一步假设第二个RDD均匀分布:

val right=sc.parallelize(
keysDistribution.keys.flatMap(x=>(1到5).map((x,)).toSeq)
并将每个键可处理的值数阈值设置为10:

val阈值=10
  • 使用代理键来增加粒度

    这个想法很简单。与其加入
    (k,v)
    对,不如使用
    ((k,i),v)
    ,其中
    i
    是一个整数,它取决于给定
    k
    的阈值和元素数量

    val bucket=keysDistribution.map{
    案例(k,v)=>(k->(v/阈值+1).toInt)
    }
    //将随机i分配给左边的每个元素
    val leftWithSurrogates=left.map{case(k,v)=>{
    val i=随机的.nextInt(桶(k))
    ((k,i),v)
    }}
    //从右到右复制每个值
    val rightWithSurrogates=right.flatMap{case(k,v)=>{
    图(i=>((k,i,v))
    }}
    val resultViaSurrogates=leftwithurrogates
    .加入(右翼和右翼)
    .map{case((k,u),v)=>(k,v)}
    
  • 分治-对频繁键和不频繁键进行分割处理

    首先让我们使用不常用的键进行连接:

    val unfrequentleft=left.filter{
    情况(k,)=>键分布(k)<阈值
    }
    val unfrequenctright=right.filter{
    情况(k,)=>键分布(k)<阈值
    }
    val unfrequent=unfrequentleft.join(unfrequentright)
    
    接下来,让我们分别处理每个频繁密钥:

    val frequentKeys=keysDistribution
    .filter{case(v,v)=>v>=threshold}
    .钥匙
    val frequent=sc.union(frequentKeys.toSeq.map(k=>{
    左.过滤器(u._1==k)
    .cartesian(右.filter(u._1==k))
    .map{case((k,v1),((u,v2))=>(k,(v1,v2))}
    }))
    
    最后,让两个子集合并:

    val resultviaaunion=不频繁。联合(频繁)
    
  • 快速健康检查:

    val resultViaJoin=left.join(right).sortBy(identity.collect.toList
    require(resultViaUnion.sortBy(identity.collect.toList==resultViaJoin)
    require(resultViaSurrogates.sortBy(identity).collect.toList==resultViaJoin)
    
    显然,这更多的是一个草图,而不是一个完整的解决方案,但应该给你一些如何继续的想法。与
    广播
    it相比,它最大的优势在于消除了驱动程序瓶颈

    它是否存在这样一种方式,可以让rdd3忘记它的依赖关系,使它在生产过程中不需要b1、b2,只需要rdd2


    您使用了检查点和强制计算,但如果任何分区丢失,它仍然会失败。

    因此,您尝试连接两个RDD,但没有成功,因此您决定自己重新实现。我对这一决定表示怀疑。为什么您认为您的join实现会比Spark的更好?我宁愿建议你解决加入的问题。将这些问题发布为堆栈溢出问题。一个新手问题:如果
    left
    rdd中的数据高度倾斜(即同一个键的多个实例),那么
    rightWithSurrogates
    rdd的大小将远大于原始
    right
    rdd。那么我们是不是把备忘录上的问题复杂化了