单源最短路径算法的MapReduce实现(Metis版本)

1. Mapreduce框架

1.1 Mapreduce介绍

Mapreduce 是谷歌提出的一个分布式计算框架, 利用该框架, 能够让用户方便地利用多机并行处理数据。 该框架有两个重要的函数: Map 和 Reduce, Map 函数对整个输入数据进行处理, 按照用户定义的处理方式, 从输入的数据中产生中间键值对( key, value)。Reduce 函数对这些键值对进行处理, 相同 key 的键值对由同一个 Reduce 进程进行处理。最终将处理的结果进行合并。 整个处理流程如下:
单源最短路径算法的MapReduce实现(Metis版本)_第1张图片

1.2 Phoenix & Metis

Phoenix 是由斯坦福大学基于多核多处理器系统实现的一套 mapreduce 框架, Phoenix框架能够自动管理线程的创建, 动态任务调度, 数据划分和故障容错。 本质上与用户写的多线程程序没有区别, 只不过通过这个框架, 能够更容易编写出能够划分为“map-reduce-merge”模式的数据处理业务。

Metis 框架是在 Phoenix 的基础上改进而来, Phoenix 中在 map 阶段使用哈希表, 对于哈希表中的每条条目使用排序数组进行保存, 而 Metis 采用了 BTree 的方式进行了代替, 以此来提高速度。
单源最短路径算法的MapReduce实现(Metis版本)_第2张图片


2. Metis 框架

2.1 三种数据处理模式

  • map_reduce
  • map_group
  • map_only

2.2 框架使用

struct SPFA: public map_reduce{
    bool split(split_t *out, int ncores);
    void map_function(split_t *ma);
    void reduce_function(void *k, void **v, size_t length);
    int key_compare(const void *s1, const void *s2);
};
  • split: 数据切分函数, 在这里根据 ncores 参数, 用户 自定义如何划分数据, 并将数据切分信息保存在 out 中。

  • Map_funcion:对每个数据分片进行处理, 产生键值对。

  • Reduce_function:对键值对进行处理。

  • Key_compare: 用户自定义键值对的比较函数

2.3 程序执行流程

    SPFA app;
    app.set_reduce_task(reduce_tasks);
    app.set_ncore(nprocs);
    mapreduce_appbase::initialize();
    app.sched_run();
    mapreduce_appbase::deinitialize();
  • set_reduce_task: 设置 reduce 线程的数量

  • set_ncore: 设置使用的核数

  • sched_run: 程序启动, 内部会先后调用数据切分, map, reduce, merge 等操作

  • map 线程数量: 由数据切分函数间接控制, 数据分块的数量对应 map_tasks。


3. 单源最短路经算法

3.1 SPFA 算法

SPFA 的思想十分简单, 简单说是加队列优化后的 bellman-ford 算法, 利用松弛操作, 更新距离。 通过引入队列, 有以下几个优化:

  • 减少松弛操作: bellman-ford 算法每次迭代中, 不需利用所有的点对其他的点进行松弛操作, 减少了松弛次数。

  • 负环判断: 通过点进入队列的次数, 可以判断是否存在负环, 如果进入队列 n 次, 则说明存在负环。

3.2 Dijkstra 算法

Dijkstra 算法采用贪心的方式, 每次从更新的节点中, 选出最小并且该点的值不可能再由剩下的节点来更新(无负环的情况下)。


4. 实现设计

4.1 SPFA算法实现

图的存储方式: 二维数组
数据处理模式: map_only
Mapreduce 处理过程:

  1. 数据划分: 将整个图的节点集合按 map_tasks 数量进行均匀划分, 每个 map 处理其中一部分。

  2. Map: 在一个数据分片中, 使用更新队列 [1] 中所有的点对当前数据分片进行松弛操作, 如果出现更新操作, 在标记数组 [2] 中对该点进行记录, 并修改 dist [3] 数组的值。

  3. 替换更新队列: 清空更新队列, 将标记数组中标记过的节点加入更新队列, 用
    于下一次迭代对其他节点进行松弛操作。

  4. 如果更新队列为空, 迭代结束, 否则继续下一次迭代。

说明:
[1] 更新队列: 节点被更新后放入的队列, 依次使用该队列中的节点对整个图的节点进行松弛操作。
[2] 标记数组: 用来标记该节点在当前迭代中是否被更新过, 作为是否放入下一次迭代中更新队列的依据。
[3] dist 数组: 源点到其他点的最近距离, 初始值为无穷大。

4.2 Dijkstra 算法实现

图的存储方式: 二维数组
数据处理模式: map_reduce
Mapreduce 处理过程:

  1. 数据划分: 将整个图的节点集合按 map_tasks 数量进行均匀划分, 每个 map 处理其中一部分。

  2. Map: 在一个数据分片中, 使用当前未使用中离源点最近的点来对数据分片中
    点的距离进行松弛操作, 如果出现更新操作, 发送以(点的编号%reduce_tasks)的值作为 key,点的编号作为 value 的键值对。

  3. Reduce: 在每个 reduce 中, 找出当前离源点最近的点, 发送(点的编号, 点的距离)的键值对。

  4. 寻找最近的点: 在最终处理完的结果数组 result_中,挑选出离源点最近的点, 用
    来在下一次迭代中更新其他点。 如果 result_数组为空, 退出迭代。
    说明: 将整个找离源点最近的点分为了两个阶段, 先在 reduce 阶段求出了局部最近, 最后在局部最近的结果集中求出全局最近的点。

你可能感兴趣的:(一一『,图计算,』)