Apache Spark RDD缓存和Lineage混淆

时间:2015-04-10 21:30:04

标签: apache-spark rdd

我用一些随机数学值填充RDD:

val itemFactors = rddItems.mapValues(newFactors => 
    Vector(Array.fill(2){math.random})
)

然后我将RDD加入到其他RDD并缓存它:

val finalRDD = itemFactors.join(rddItemsUsers).map{
    case(itemid, (itemVector, ((userid, rating), userVector))) => 
        (itemid, itemVector, userid, userVector, rating)}.cache

然后,我对finalRDD

中保存的数据进行计算
sqrt(finalRDD.aggregate(0.0)((accum, item) => 
    accum + pow(item._5 - item._4.dot(item._2), 2), _ + _) / finalRDD.count)

我从控制台反复调用代码的最后一部分sqrt(...),每次都得到不同的结果 - 这是不可取的,因为我没有改变任何东西!这可以通过两种方式得到纠正(即使我得到一致的结果):

  • 我可以使用固定数字填充数组,例如itemFactors,而不是使用math.random初始化itemFactors.cache。 1.0

  • 我可以itemFactors

现在,我了解由于血统,每次调用math.random时,它都会调用finalRDD并创建一个新数字 - 这将影响我执行时的计算。这就是为什么在填充数组时使用固定数字会产生一致的结果。

但是,最大的问题和我不理解的一点是:我正在缓存itemFactors这是执行计算的内容,因为它包含itemFactor,当然它应该不应该无论{{1}}的数组是什么,因为节点只访问过一次?我以为我开始掌握血统;然而,这刚刚抛弃了我。

1 个答案:

答案 0 :(得分:1)

如果您的缓存无法容纳在内存中,则会根据LRU策略丢失缓存。

为了避免你可以使用带有参数的persist,如图所示

val result = input.map(x => x*x)
result.persist(MEMORY_ONLY)

MEMORY_ONLY - 将RDD存储为JVM中的反序列化Java对象。如果RDD不适合内存,则某些分区将不会被缓存,并且每次需要时都会重新计算。这是默认级别。

MEMORY_AND_DISK 将RDD存储为JVM中的反序列化Java对象。如果RDD不适合内存,请存储不适合磁盘的分区,并在需要时从那里读取。

MEMORY_ONLY_SER 将RDD存储为序列化Java对象(每个分区一个字节数组)。这通常比反序列化对象更节省空间,特别是在使用快速序列化器时,但读取CPU密集程度更高。

MEMORY_AND_DISK_SER 与MEMORY_ONLY_SER类似,但将不适合内存的分区溢出到磁盘,而不是每次需要时重新计算它们。

DISK_ONLY 仅将RDD分区存储在磁盘上。 MEMORY_ONLY_2,MEMORY_AND_DISK_2等。与上面的级别相同,但复制两个群集节点上的每个分区。

OFF_HEAP (实验性)在Tachyon中以序列化格式存储RDD。与MEMORY_ONLY_SER相比,OFF_HEAP减少了垃圾收集开销,并允许执行器更小并共享内存池,使其在具有大堆或多个并发应用程序的环境中具有吸引力。此外,由于RDD驻留在Tachyon中,执行程序的崩溃不会导致丢失内存缓存。在这种模式下,Tachyon中的内存是可丢弃的。因此,Tachyon不会尝试重建一个从记忆中驱逐的块。

Refer to this link for more documentation