5.5 Map-Reduce(映射-归约)模型

Reduce,yqj2065译为归约/归结。We can reduce his speech to three sentences.他的哔哔哔哔,我们可以归总为3句话。

 

对于数组或List,我们可以设计一些宏观上的操作。如将它们视为信号,按照信号处理的方式,设计过滤/filter、映射/map和累积/accumulate方法。本节介绍信号处理的Map-Reduce(映射-归总)模型以及它们为什么不适合用于集合。

 

要点:

 

  • Map-Reduce并不神秘
  • Map-Reduce需要流,流的核心——如同基本for循环一样的,对于数据序列中的每一个元素,进行过滤和累积,然后再提供下一个数据。数据序列的供给过程和使用过程交替进行
  •  

 

1. MapReduce模型

假设求解问题:

  • 求[a,b]之间素数的和
  • 输出0-x之间符合条件(例如 3的倍数而且含5的或者含7)的数
  • 打印[10000,100000000]之间第一个素数

通常程序员容易地针对具体问题给出方案。

 

 

    public static long sum(long a, long b) {
        long result = 0;
        for (long i = a; i <= b; i++) {
            if (isPrime(i)) { // private static boolean isPrime(int n) 
                result += i;
            }
        }
        return result;
    }

按照信号处理的方式,这些问题可以归纳为统一的处理模型:
 对于一个数据序列,.
 对每一个数据进行转换,
 对这个数据序列进行归总,或统计或累积。

转换阶段,可以进行映射/map、过滤/filter、去重/等操作。
归总阶段,可以进行求和、求最大值、求最小值、求数量、打印每个元素等。
这一处理模型称为MapReduce模型。

 

2. Map-Reduce模型不适合用于集合

 

按照Map-Reduce模型,首先需要设计一个数据结构描述一个数据序列。假设使用List作为Map-Reduce模型的数据结构。

 

package streamsDemo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import static util.Print.pln;
public class MapReduce {
    static List list;
    public static void init(long a, long b) {
        int leng = (int)(b - a);
        Long[] arr = new Long[leng];
        for (long i = a; i < b; i++) {
            arr[(int)(i - a)] = i;
        }
        list = Arrays.asList(arr);
    }

    public static List filter(Predicate p) {
        List results = new ArrayList<>();
        for (Long s : list) {
            if (p.test(s)) {
                results.add(s);
            }
        }
        return results;
    }

    public static  List map(List list, Function factor) {
        List results = new ArrayList<>();
        for (T x : list) {
            results.add(factor.apply(x));
        }
        return results;
    }

    public static long accumulator() {
        long result = 0;
        for (Long x : list) {
            result += x;
        }
        return result;
    }
    public static void main(String[] args) {
        pln(sum(0, 10000));
        init(0, 10000);
        Predicate< Long> isPrime =  (Longn) -> {
                //略
        };
        list = filter(isPrime);
        long result  = accumulator() ;
        pln(result);
    }
}

采用List作为Map-Reduce模型的数据结构,在时间和空间上的开销太大。当用List list描述一个数据序列时,在init(int a, int b)阶段需要构造出包含期间[a,b]中所有整数的表,然后过滤器才开始工作并产生另外一个表;而例程2-2只需要一个result维持不断累积的和。

 


例程2-2所示的设计中,对于数据序列中的每一个元素,进行过滤和累积,然后再提供下一个数据。这种数据序列的供给过程和使用过程交替进行的方式,非常重要。假设求解问题为打印[10000,100000000]之间第一个素数,在MapReduce模型中采用List是难以容忍的。因为需要创建一个巨大的表,对表中所有的素数过滤出来(而我们需要的只是第一个素数),再打印第一个素数。

所以,要使用Map-Reduce模型,就需要设计一种替代List的结构,该结构对数据序列的供给过程和使用过程交替进行,即每提供一个元素就进行过滤和累积;这种结构就是流。流的本质。

 

Map-Reduce是流的特性吗?原则上,只有流才适合拥有Map-Reduce。这就如同18岁以上的女性才适合拥有baby。注意,List与流,在这个问题上的差异,不是男人与女人的不同,而是女性在18岁以下和以上的不同。如果空间和时间开销不那么严重,例如小规模的元素,我们可以让数组或List拥有Map-Reduce。

 

 

你可能感兴趣的:(垃圾桶)