Map-reduce 功能概述
Posted
技术标签:
【中文标题】Map-reduce 功能概述【英文标题】:Map-reduce functional outline 【发布时间】:2021-08-20 01:08:43 【问题描述】:注意:这只是一个基本的编程问题,与“大数据处理”的 Hadoop 或 Map/Reduce 方法无关。
我们来个序列(1 2 3 4 5)
:
要将其映射到某个函数,比如square
,我可以这样做:
(define (map function sequence)
; apply the function to each element in the sequence
; we do not reduce it, but return a list
(if (null? sequence)
nil
(cons (function (car sequence))
(map function (cdr sequence)))))
(map (lambda (x) (* x x)) '(1 2 3 4 5))
; (1 4 9 16 25)
>>> map(lambda x: x*x, [1,2,3,4,5])
# [1, 4, 9, 16, 25]
>>> def mymap(function, sequence):
return [function(item) for item in sequence]
>>> mymap(lambda x: x*x, [1,2,3,4,5])
# [1, 4, 9, 16, 25]
对于像“map-reduce”这样的东西,如果我们假设一个给定的序列,它可能有大约三个步骤(我认为?):
map
filter
(订单可能与 map
交换,具体取决于正在执行的操作)
reduce
这是对“map-reduce”范式的正确理解吗?它通常是不是一个看起来像这样的函数:
mapreduce(map_function, filter_function, reduce_function, sequence)
或者说组合在一起的时候一般是怎么处理的?
【问题讨论】:
我有点迷茫,究竟你在这里找什么? @gold_cy 非常熟悉上述数据/信号处理范例的人,可以对它通常如何完成进行结构性概述(我已经在方案或 python 中展示了一个示例......任何一种语言很好)。 【参考方案1】:为了让您有直觉,我们需要(简要地)远离代码中的具体实现。 MapReduce(我不只是在谈论特定的实现)是关于问题的形状。
假设我们有一个 xs 的线性数据结构(列表、数组等),我们有一个要应用于每个 xs 的变换函数,我们有一个聚合函数,可以表示为重复应用关联成对组合:
xA xB
| |
xform(xA) xform(xB)
\ /
aggregator(xform(xA), xform(xB))
|
value
我们可以递归地将聚合器应用于整个列表/数组/xs 的任何内容:
xA xB xC
| | |
xform(xA) xform(xB) xform(xC)
| | |
yA yB yC
\ / |
aggregator(yA, yB) |
| /
value /
| /
aggregator(value, yC)
|
next_value
您要求使用 Python 或 Scheme,但如果我们使用类型,我发现这更容易考虑。转换器xform
接受一个类型为 A 的参数并返回一个 B:(x: A) -> B
。聚合器aggregator
接受两个类型为 B 的参数并返回一个 B:(x: B, y: B) -> B
。
最简单且经常被过度使用的例子是平方和:
import functools
# Combiner
def add(a, b):
return a + b
# Transformer
def square(a):
return a * a
one_to_ten = range(1, 11)
functools.reduce(add, map(square, one_to_ten), 0)
不是很令人兴奋。但是,这与代码中没有真正显示的更直接的版本(但确实在图中显示)的区别在于,MapReduce 版本是完全可并行化的。您可以轻松地将其分块并在不同的线程、不同的盒子等上运行它的一部分。我们有变换,我们有组合功能,结合性意味着组合的顺序无关紧要。
现在,并非所有问题都可以通过这种方式进行分解,但令人惊讶的数量可以通过这种方式进行建模,并且它允许处理太大而无法在一个盒子上处理的数据集。现在显然,上面天真地编写的 Python 不能做到这一点,至少现在不能。但是没有理由一个足够聪明的编译器不能以这种方式发出字节码。
虽然我不知道 Scheme,但我知道 Clojure,它确实提供了 parallelized version of this exact thing:
(require '[clojure.core.reducers :as r])
(defn square [x] (* x x))
(r/fold + (pmap square (range 1 11)))
请注意,这并不完美:并行映射必须在(也是并行的)组合发生之前完成,但我们越来越接近了,这些是标准库调用。
【讨论】:
哇,很好的答案。感谢您的所有想法和时间。但是有一个问题:变量通常是如何完成的?例如xA
、xForm
、xs
等
@David542 这并不重要。您可以选择所需的任何变量名称。问题是真的可以将您的问题建模为转换的递归关联成对组合(即幺半群)吗?以上是关于Map-reduce 功能概述的主要内容,如果未能解决你的问题,请参考以下文章