我用一些随机数学值填充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}}的数组是什么,因为节点只访问过一次?我以为我开始掌握血统;然而,这刚刚抛弃了我。
答案 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不会尝试重建一个从记忆中驱逐的块。