Java Map-Reduce(映射-归总)

来源:互联网 发布:工业软件 编辑:程序博客网 时间:2024/05/29 08:43

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

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

要点:

  • 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<Long> 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<Long> filter(Predicate<Long> p) {        List<Long> results = new ArrayList<>();        for (Long s : list) {            if (p.test(s)) {                results.add(s);            }        }        return results;    }    public static <T, R> List<R> map(List<T> list, Function<T, R> factor) {        List<R> 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<Integer> 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。



0 0
原创粉丝点击