Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.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 是否应该缓存转换依赖关系图上的公共祖先?_Apache Spark_Rdd - Fatal编程技术网

Apache spark 是否应该缓存转换依赖关系图上的公共祖先?

Apache spark 是否应该缓存转换依赖关系图上的公共祖先?,apache-spark,rdd,Apache Spark,Rdd,我对spark比较陌生,甚至可能在完成构建场景问题之前就错了,所以请跳过阅读并指出我在概念上的错误,谢谢 想象一段如下的驱动程序代码: val A = ... (some transformation) val B = A.filter( fun1 ) val C = A.filter( fun2 ) ... B.someAction()... //do sth with B ... C.someAction()... //do sth with C val arr = Array(...

我对spark比较陌生,甚至可能在完成构建场景问题之前就错了,所以请跳过阅读并指出我在概念上的错误,谢谢

想象一段如下的驱动程序代码:

val A = ... (some transformation)
val B = A.filter( fun1 ) 
val C = A.filter( fun2 ) 
...
B.someAction()... //do sth with B
...
C.someAction()... //do sth with C
val arr = Array(...)
val A = sc.parallelize(...).flatMap(e => arr.map(_ * e)) //now A depends on some local array

... //B and C stays the same as above

B.someAction()
...
arr(i) = arr(i) + 10  //local state modified
...
C.someAction() //should A be recomputed? YES
转换RDDB和C都依赖于A,A本身可能是一个复杂的转换。那么A会被计算两次吗?我认为会,因为spark不能做任何内部转换,对吗?Spark在一次优化一个转换执行方面是智能的,因为它中的捆绑任务可以被彻底分析。例如,可能在B.someAction之后但在C.someAction之前发生一些状态变化,这可能会影响A的值,因此需要重新计算。例如,可能会发生如下情况:

val A = ... (some transformation)
val B = A.filter( fun1 ) 
val C = A.filter( fun2 ) 
...
B.someAction()... //do sth with B
...
C.someAction()... //do sth with C
val arr = Array(...)
val A = sc.parallelize(...).flatMap(e => arr.map(_ * e)) //now A depends on some local array

... //B and C stays the same as above

B.someAction()
...
arr(i) = arr(i) + 10  //local state modified
...
C.someAction() //should A be recomputed? YES
这很容易验证,所以我做了一个快速的实验,结果支持我的推理

然而,如果B和C只是独立地依赖于A,并且没有像上面那样的其他逻辑存在,那么程序员或某个工具可以静态地分析代码并说,嘿,在A上添加缓存是可行的,这样它就不会不必要地重新计算!但spark对此无能为力,有时人类甚至很难做出决定:

val A = ... (some transformation)
var B = A.filter( fun1 ) 
var C: ??? = null
var D: ??? = null

if (cond) {
  //now whether multiple dependencies exist is runtime determined
  C = A.filter( fun2 ) 
  D = A.filter( fun3 )
}

B.someAction()... //do sth with B

if (cond) {
  C.someAction()... //do sth with C
  D.someAction()... //do sth with D
}
如果条件为真,则很容易缓存一个,但在运行时之前您永远不会知道。我知道这是一个人工的蹩脚的例子,但这些都是简化的模型。在实践中,事情可能会变得更加复杂,依赖关系可能相当长,而且是隐式的,并且会在模块之间传播,所以我的问题是,处理这类问题的一般原则是什么。如果内存不是问题,什么时候应该缓存转换依赖关系图上的公共祖先

我想听到一些类似于始终遵循函数式编程范例来执行spark或始终缓存它们(如果可以的话)的内容,但是还有另一种情况我可能不需要:

val A = ... (some transformation)
val B = A.filter( fun1 ) 
val C = A.filter( fun2 ) 
...
B.join(C).someAction()

同样,B和C都依赖于A,但它们不是单独调用两个动作,而是连接起来形成一个转换。这一次,我相信spark足够聪明,可以精确计算一次A。还没有找到一种正确的运行和检查方法,但在web UI DAG中应该是显而易见的。此外,我认为spark甚至可以将两个过滤操作简化为对A的一次遍历,从而同时得到B和C。这是真的吗?

这里有很多东西需要解开

转换RDDB和C都依赖于A,A本身可能是一个复杂的转换。那么A会被计算两次吗?我认为会,因为spark不能做任何内部转换,对吗

是的,它将被计算两次,除非调用A.cache或A.persist,在这种情况下,它将只被计算一次

例如,可能在B.someAction之后但在C.someAction之前发生一些状态变化,这可能会影响A的值,因此需要重新计算

不,这是不正确的,A是不可变的,因此它的状态不能更改。B和C也是表示A的转换的不可变RDD

不,它不依赖于本地数组,它是一个不可变的RDD,包含驱动程序本地数组元素的副本。如果数组更改,则A不会更改。要获得这种行为,您必须将var A=sc.并行化。。。然后在本地数组更改时再次设置A=sc.parallelize。。。。在这种情况下,A不会被“更新”,而是被本地数组的新RDD表示形式替换,因此A的任何缓存版本都是无效的


您发布的后续示例从缓存A中获益。同样,因为RDD是不可变的。

谢谢Darren。所以我从中得到的是,缓存RDD总是有意义的,以防潜在的重新计算。RDD是不可变的,可以在创建RDD的快照中将其视为相关本地数据的包以及对其他RDD和指令的引用。但是我仍然无法理解我在本地spark shell中所做的实验:scala>val arr=Array1,2,3>val A=sc.parallelizeArray1,2,3.Flatmap=>arr.map\u*A>A.collect res0=Array1,2,3,2,4,6,6,9>arr0=100>A.collect res2=Array100,2,3,200,4,6,300,6,9缓存多次使用的RDD将阻止重新计算,缓存它是否有意义取决于用例和可用资源。关于你的实验,我认为这是使用REPL的副作用。很抱歉,这里的评论不能包含换行符。这意味着第二个collect结果发生了变化,这必然意味着创建了一些新的RDD。但是我一直使用同一个vala,所以不确定它是如何发生的。使用REPLYes的副作用我现在记得它是一个修改过的scala shell