Scala 聚合泛化折叠和折叠泛化如何减少?
据我所知,Scala 聚合泛化折叠和折叠泛化如何减少?,scala,apache-spark,Scala,Apache Spark,据我所知,aggregate是fold的泛化,而fold又是reduce的泛化 类似地,combineByKey是aggregateebykey的泛化,后者又是foldByKey的泛化,后者又是reduceByKey的泛化 然而,我很难为这七种方法中的每一种找到简单的例子,而这七种方法只能用它们来表达,而不能用它们不那么一般的版本来表达。例如,我发现为fold提供了一个示例,但我也能够在相同的情况下使用reduce 到目前为止,我发现: 我读到更一般化的方法可能更有效,但这将是一个非功能性要求
aggregate
是fold
的泛化,而fold又是reduce
的泛化
类似地,combineByKey
是aggregateebykey
的泛化,后者又是foldByKey
的泛化,后者又是reduceByKey
的泛化
然而,我很难为这七种方法中的每一种找到简单的例子,而这七种方法只能用它们来表达,而不能用它们不那么一般的版本来表达。例如,我发现为fold
提供了一个示例,但我也能够在相同的情况下使用reduce
到目前为止,我发现:
- 我读到更一般化的方法可能更有效,但这将是一个非功能性要求,我想得到一些无法用更具体的方法实现的示例
- 我还读到,例如,传递给
的函数必须是关联的,而fold
的函数必须是可交换的:(然而,我仍然不知道任何好的简单示例。)而在我读到的文章中,fold需要两个属性来保持reduce
- 我们可以将零值视为“添加所有元素并添加3”中的一个特性(例如,对于
折叠
超过
减少
),并使用3作为零值,但这会产生误导,因为每个分区将添加3,而不是仅添加一次。此外,据我所知,这并不是折叠的目的——它不是作为一种功能,而是实现它的必要性,以便能够实现非交换功能
折叠
的操作不同,如中所述:
这与为非分布式系统实现的折叠操作有些不同
函数语言(如Scala)中的集合
此折叠操作可应用于
单独分区,然后将这些结果折叠成最终结果,而不是
将折叠
按定义的顺序依次应用于每个元素。功能
如果不是可交换的,则结果可能不同于应用于
非分布式收集
正如您所见,合并部分值的顺序不是契约的一部分,因此用于折叠的函数必须是可交换的
我读到更普遍的方法可能更有效
从技术上讲,应该没有显著差异。对于fold
vsreduce
关于*byKey
方法,所有方法都是使用相同的基本构造来实现的,即将byKey与classtag组合起来,可以简化为三个简单的操作:
createCombiner
-为给定分区创建“零”值
mergeValue
-将值合并到累加器中
mergeCombiners
-为每个分区创建的合并累加器
让我们从逻辑上研究实际需要的东西
首先,请注意,如果集合是无序的,则其上的任何(二进制)操作集都需要是可交换的和关联的,否则您将根据每次选择的(任意)顺序得到不同的答案。由于
reduce
、fold
和aggregate
都使用二进制操作,因此如果在无序(或被视为无序)的集合上使用这些操作,则所有内容都必须是可交换和关联的
reduce
是这样一种思想的实现,即如果可以将两个对象转换为一个对象,则可以将任意长的集合折叠为单个元素。关联性正是这样一种属性,即无论你如何配对,只要你最终将它们配对,并保持从左到右的顺序不变,那么这正是你所需要的
a b c d a b c d a b c d
a # b c d a # b c d a b # c d
(a#b) c # d (a#b) # c d a (b#c) d
(a#b) # (c#d) ((a#b)#c) # d a # ((b#c)#d)
只要操作(这里称为#
)是关联的,上述所有操作都是相同的。没有理由交换哪些东西在左边,哪些东西在右边,因此操作不需要是可交换的(加法是:a+b==b+a;concat不是:ab!=ba)
reduce
在数学上很简单,只需要一个关联运算
但是,Reduce是有限的,因为它不适用于空集合,并且不能更改类型。如果按顺序工作,可以创建一个函数,该函数接受新类型和旧类型,并生成具有新类型的内容。这是一个顺序折叠(如果新类型在左侧,则为左折叠,如果在右侧,则为右折叠)。这里没有关于操作顺序的选择,所以交换性、结合性和所有东西都是无关的。只有一种方法可以按顺序浏览列表。(如果希望左折叠和右折叠始终相同,则操作必须是关联的和可交换的,但由于左折叠和右折叠通常不会意外交换,因此确保这一点并不十分重要。)
当你想并行工作时,问题就来了。你不能按顺序浏览你的收藏;从定义上讲,这不是平行的!因此,您必须在多个位置插入新类型!让我们调用我们的折叠操作@
,我们会说新类型在左边。此外,我们要说的是,我们总是从同一个元素开始,Z
。现在我们可以做任何一件事了
a b c d a b c d a b c d
Z@a b c d Z@a b Z@c d Z@a Z@b Z@c Z@d
(Z@a) @ b c d (Z@a) @ b (Z@c) @ d
((Z@a)@b) @ c d
(((Z@a)@b)@c) @ d
a b c d a b c d a b c d
Z@a b c d Z@a b Z@c d Z@a Z@b Z@c Z@d
(Z@a) @ b c d (Z@a) @ b (Z@c) @ d Z@a $ Z@b Z@c $ Z@d
((Z@a)@b) @ c d ((Z@a)@b) $ ((Z@c)@d) ((Z@a)$(Z@b)) $ ((Z@c)$(Z@d))
(((Z@a)@b)@c) @ d
(0.0+2) * (0.0+3) == 2.0 * 3.0 == 6.0
((0.0+2) + 3) == 2.0 + 3 == 5.0
a b c d () <- empty
z#a z#b z
z#a (z#b)#c
z#a ((z#b)#c)#d
(z#a)#((z#b)#c)#d