Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/401.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.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
Java (Spark skewed join)如何连接两个具有高度重复密钥的大型Spark RDD,而不会出现内存问题?_Java_Apache Spark_Join_Rdd_Scalability - Fatal编程技术网

Java (Spark skewed join)如何连接两个具有高度重复密钥的大型Spark RDD,而不会出现内存问题?

Java (Spark skewed join)如何连接两个具有高度重复密钥的大型Spark RDD,而不会出现内存问题?,java,apache-spark,join,rdd,scalability,Java,Apache Spark,Join,Rdd,Scalability,在中,我试图通过Sparkjoin避免使用join来避免内存问题 在这个新问题中,我使用了join,但试图用它解决内存问题 这是我的两个RDD: productToCustomerRDD: 大小:非常大,可能有数百万个不同的键 使用HashPartitioner对键进行分区 有些键将被高度复制,有些则不会 (toast, John) (butter, John) (toast, Jane) (jelly, Jane) productToCountRDD: 大小:非常大,可能有数百万个不同的键

在中,我试图通过Spark
join
避免使用
join
避免内存问题

在这个新问题中,我使用了
join
,但试图用它解决内存问题

这是我的两个RDD:

  • productToCustomerRDD:
    大小:非常大,可能有数百万个不同的键
    使用HashPartitioner对键进行分区 有些键将被高度复制,有些则不会

    (toast, John)
    (butter, John)
    (toast, Jane)
    (jelly, Jane)
    
  • productToCountRDD:
    大小:非常大,可能有数百万个不同的键,太大而无法播放 使用HashPartitioner对键进行分区 键是唯一的,值是购买该产品的客户数

    (toast, 2)
    (butter, 1)
    (jelly, 1)
    
  • 我想加入这两个RDD,结果将是:

  • customerToProductAndCountRDD:

    (toast, (John, 2))
    (butter, (John, 1))
    (toast, (Jane, 2))
    (jelly, (Jane, 1))
    
  • 如果我用
    productToCustomerRDD.join(productToCountRDD)
    连接两个RDD,我会在两个分区上得到一个
    OutOfMemoryError
    (共数千个分区)。在Spark UI中,我注意到在包含
    join
    的阶段,在
    Input Size/Records
    列中,所有分区都有从4K700K的大量记录。除了生成OOM的两个分区之外,所有分区都有:一个分区有9M记录,另一个分区有6M记录

    据我所知,为了加入,具有相同密钥的对需要被洗牌并移动到相同的分区(除非它们以前是按密钥分区的)。但是,由于某些键非常频繁(例如:数据集中几乎每个客户都购买的产品),因此在
    连接期间或在连接之前的
    重新分区期间,可能会将大量数据移动到一个分区

    我理解正确吗?
    有没有办法避免这种情况?

    有没有一种方法可以
    连接
    ,而不必在同一分区上拥有一个重复制键的所有数据

    我的第一个问题是:你真的需要这些详细的数据吗?你真的需要知道约翰买了2只蟾蜍等等吗?我们处于大数据环境中,处理大量数据,因此有时聚合是减少基数并在分析和性能方面获得良好结果的一件好事。因此,如果您想知道一个产品的销售次数,您可以使用pairdd(产品,计数)[这样,每个产品都有一个元素],或者如果您想知道用户偏好,您可以使用pairdd(用户,购买产品列表)[这样,每个用户都有一个元素]。如果您真的需要知道toast是从Jhon购买的,为什么要将toast键拆分为不同的重新分区?这样,您就无法计算全局结果,因为在每个chunck中,您只有一条关于键的信息。

    实际上,这是Spark中的一个标准问题,称为“歪斜连接”:连接的一侧歪斜,这意味着它的一些键比其他键更频繁。可以找到一些不适合我的答案

    我使用的策略受到了
    GraphFrame.skewedJoin()
    方法的启发,该方法是在
    ConnectedComponents.skewedJoin()中定义的,并在
    ConnectedComponents.skewedJoin()中使用的。
    连接将通过使用广播连接最频繁的键和使用标准连接较不频繁的键来执行

    在我的示例(OP)中,
    producttocountrd
    已经包含了有关键频率的信息。 所以它是这样的:

    • 过滤
      productToCountRDD
      以仅保留高于固定阈值的计数,并
      collectamap()
      将其发送给驱动程序
    • 将此地图广播给所有执行者
    • productToCustomerRDD
      拆分为两个RDD:在广播映射中找到的键(频繁键)和不在广播映射中的键(不频繁键)
    • 使用
      mapToPair
      执行频繁键的联接,从广播映射中获取
      计数
    • 使用
      join
      执行不常用键的联接
    • 最后使用
      union
      获取完整的RDD