相关知识

最优路径算法是无向图中满足通路上所有顶点(除起点、终点外)各异,所有边也各异的通路。应用在公路运输中,可以提供起点和终点之间的最短路径,节省运输成本。可以大大提高交通运输效率。

本实验采用Dijkstra算法,迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

算法伪代码如下:

Dijkstra(G,w, s)

d[s] ← 0

for all vertex v ∈ V do

d[v] ← ∞

Q ← {V }

while Q != ∅ do

u ←ExtractMin(Q)

for all vertex v ∈ u.AdjacencyList do

if d[v] > d[u] + w(u, v) then

d[v] ← d[u] + w(u, v)

Dijkstra算法关键的一点是优先队列Q,它保存了全局的从源点出发最近的结点。而map-reduce则无法做到这一点。

基于map-reduce的并行算法跟Dijkstra算法有点类似,它也基于Dijkstra的迭代思想,伪代码如下:

class Mapper

method Map(nid n, node N)

d ← N.Distance

Emit(nid n,N) //Pass along graph

structure [1]

for all nodeid m ∈ N.AdjacencyList do

Emit(nid m, d+w) //Emit distances to

reachable nodes [2]

class Reducer

method Reduce(nid m, [d1, d2, . . .])

dmin←∞

M ← ∅

for all d ∈ counts [d1, d2, . . .] do

if IsNode(d) then

M ← d //Recover graph

structure

else if d < dmin then //Look for shorter

distance

dmin ← d

M.Distance← dmin //Update shortest

distance

Emit(nid m, node M)

它每次迭代执行一个map-reduce job,并且只遍历一个节点。在Map中,它先输出这个节点的完整邻接节点数据,即[1]。然后遍历该节点的邻接节点,并输出该节点ID及权重。在Reduce中,对当前节点m,遍历map的输出权重,若比当前的路径值小,则更新。最后输出该节点的路径值及完整邻接节点数据,作为下一次迭代的输入。

实现上有个细节需要注意的是,map的输出有两种类型的数据:邻接节点数据和权重数据,这可以通过一个包装类,并设置一个dataType变量来实现。

当遍历完所有的节点之后,迭代就终止了。

系统环境

Linux Ubuntu 16.04

jdk-7u75-linux-x64

Hadoop 2.6.0-cdh5.4.5

任务内容

原始数据:

A(B,10) (D,5)

B(C,1) (D,2)

C(E,4)

D(B,3) (C,9) E,2)

E(A,7) (C,6)

如图,A为初始节点,A到B的距离为10,A到D的距离为5。

B到C的距离为1,B到D的距离为3

Map阶段:

从初始A节点开始,将节点到其他相连节点的距离列举出来,然后传递给reduce,找到距离最短的。

从初始A节点开始,找到B和D,然后再找B和D的相邻节点,依次类推,这个就是广度优先搜索。

从A节点出发,A节点不能直接到达节点默认的距离为inf,表示距离无穷大。

A能到达的节点有:A本身(距离为0),B(距离为10),D(距离为5)

则可以表示为:

A 0(B,10) (D,5)

B 10

D 5

Reduce阶段:

找到所有存在的距离中最短的,并更新记录中的最短距离。

如A节点到C节点有两种路径:

A=>B=>C,距离为:10+1=11

A=>D=>B=>C,距离为5+3+1=9

则A节点到C节点的最短距离为9

任务步骤

1.首先,我们来准备实验需要用到的数据,切换到/data/mydata目录下,使用vim编辑一个data.txt文件

mkdir -p /data/mydata
cd /data/mydata
vim data.txt

2.将如下数据写入其中(注意数据之间以\t分割)

A (B,10) (D,5)

B (C,1) (D,2)

C (E,4)

D (B,3) (C,9) (E,2)

E (A,7) (C,6)

3.切换到/apps/hadoop/sbin目录下,开启Hadoop相关进程

cd /apps/hadoop/sbin
./start-all.sh

4.输入JPS查看一下相关进程是否已经启动。

view plain copy

jps

5.在HDFS的根下创建一个input目录,并将data.txt文件上传到HDFS上的input文件夹下

hadoop fs -mkdir /input
hadoop fs -put /data/mydata/data.txt /input

6.打开Eclipse,创建一个Map/Reduce项目

7.设置项目名为mr_sf并点击Finish

8.创建一个包,名为mr_mindistance

9.创建一个类,名为RunJob,作用为计算最短路径。

10.下面开始编写Runjob类的代码

完整代码为:

package mr_mindistance;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.KeyValueTextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.StringUtils;
public class RunJob {
static enum eInf {
COUNTER
}
public static void main(String[] args) {
Configuration conf = new Configuration();
//设置主机地址及端口号 conf.set("fs.defaultFS", "hdfs://localhost:9000");
try {
FileSystem fs = FileSystem.get(conf);
int i = 0;
long num = 1;
long tmp = 0;
while (num > 0) {
i++;
conf.setInt("run.counter", i);
Job job = Job.getInstance(conf);
job.setJarByClass(RunJob.class);
job.setMapperClass(ShortestPathMapper.class);
job.setReducerClass(ShortestPathReducer.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
//key value 的格式 第一个item为key,后面的item为value
job.setInputFormatClass(KeyValueTextInputFormat.class);
//设置输入、输出路径 if (i == 1)
FileInputFormat.addInputPath(job, new Path("/input/"));
else
FileInputFormat.addInputPath(job, new Path("/output/" + (i - 1)));
Path outPath = new Path("/output/" + i);
if (fs.exists(outPath)) {
fs.delete(outPath, true);
}
FileOutputFormat.setOutputPath(job, outPath);
boolean b = job.waitForCompletion(true);
if (b) {
num = job.getCounters().findCounter(eInf.COUNTER).getValue();
if (num == 0) {
System.out.println("共执行了" + i + "次,完成最短路径计算");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static class ShortestPathMapper extends Mapper<Text, Text, Text, Text> {
protected void map(Text key, Text value, Context context) throws IOException, InterruptedException {
int conuter = context.getConfiguration().getInt("run.counter", 1);
Node node = new Node();
String distance = null;
String str = null;
// 第一次计算,填写默认距离 A:0 其他:inf
if (conuter == 1) {
if (key.toString().equals("A") || key.toString().equals("1")) {
distance = "0";
} else {
distance = "inf";
}
str = distance + "\t" + value.toString();
} else {
str = value.toString();
}
context.write(key, new Text(str));
node.FormatNode(str);
// 没走到此节点 退出
if (node.getDistance().equals("inf"))
return;
// 重新计算源点A到各点的距离
for (int i = 0; i < node.getNodeNum(); i++) {
String k = node.getNodeKey(i);
String v = new String(
Integer.parseInt(node.getNodeValue(i)) + Integer.parseInt(node.getDistance()) + "");
context.write(new Text(k), new Text(v));
}
}
}
public static class ShortestPathReducer extends Reducer<Text, Text, Text, Text> {
protected void reduce(Text arg0, Iterable<Text> arg1, Context arg2) throws IOException, InterruptedException {
String min = null;
int i = 0;
String dis = "inf";
Node node = new Node();
for (Text t : arg1) {
i++;
dis = StringUtils.split(t.toString(), '\t')[0];
// 如果存在inf节点,表示存在没有计算距离的节点。
// if(dis.equals("inf"))
// arg2.getCounter(eInf.COUNTER).increment(1L);
// 判断是否存在相邻节点,如果是则需要保留信息,并找到最小距离进行更新。
String[] strs = StringUtils.split(t.toString(), '\t');
if (strs.length > 1) {
node.FormatNode(t.toString());
}
// 第一条数据默认是最小距离
if (i == 1) {
min = dis;
} else {
if (dis.equals("inf"))
;
else if (min.equals("inf"))
min = dis;
else if (Integer.parseInt(min) > Integer.parseInt(dis)) {
min = dis;
}
}
}
// 有新的最小值,说明还在进行优化计算,需要继续循环计算
if (!min.equals("inf")) {
if (node.getDistance().equals("inf"))
arg2.getCounter(eInf.COUNTER).increment(1L);
else {
if (Integer.parseInt(node.getDistance()) > Integer.parseInt(min))
arg2.getCounter(eInf.COUNTER).increment(1L);
}
}
node.setDistance(min);
arg2.write(arg0, new Text(node.toString()));
}
}
}

11.创建一个Node类,作用为保存节点的信息

12.下面开始编写代码

完整代码为:

package mr_mindistance;
import org.apache.hadoop.util.StringUtils;
public class Node {
private String distance;
private String[] adjs;
public String getDistance() {
return distance;
}
public void setDistance(String distance) {
this.distance = distance;
}
public String getKey(String str)
{
return str.substring(1, str.indexOf(","));
}
public String getValue(String str)
{
return str.substring(str.indexOf(",")+1, str.indexOf(")"));
}
public String getNodeKey(int num)
{
return getKey(adjs[num]);
}
public String getNodeValue(int num)
{
return getValue(adjs[num]);
}
public int getNodeNum()
{
return adjs.length;
}
public void FormatNode(String str)
{
if(str.length() == 0)
return ;
String[] strs = StringUtils.split(str, '\t');
adjs = new String[strs.length-1];
for(int i=0; i<strs.length; i++)
{
if(i == 0)
{
setDistance(strs[i]);
continue;
}
this.adjs[i-1]=strs[i];
}
}
public String toString()
{
String str = this.distance+"" ;
if(this.adjs == null)
return str;
for(String s:this.adjs)
{
str = str+"\t"+s;
}
return str;
}
public static void main(String[] args)
{
Node node = new Node();
node.FormatNode("1 (A,20) (B,30)");
System.out.println(node.distance+"|"+node.getNodeNum()+"|"+node.toString());
}
}

13.下面在Runjob类下,单击右键,选择Run As=>Run on Hadoop,运行程序,查看执行结果

可以在Console界面看到如下输出,证明程序执行成功,共进行了4次运算。

14.查看HDFS上的/output目录及最终计算结果(/ouput/下的1、2、3、4目录分别保存了4次执行程序的计算结果)

view plain copy
hadoop fs -ls -R /output
hadoop fs -cat /output/4/part-r-00000

通过分析结果,我们可以清楚地看到A点距离各点的最短距离。

至此,实验就已经结束了。

mapreduce shortest way out的更多相关文章

  1. Giraph之SSSP(shortest path)单机伪分布运行成功

    所遇问题:Exception 1: Exception in thread "main" java.lang.IllegalArgumentException: "che ...

  2. Hadoop MapReduce编程 API入门系列之最短路径(十五)

    不多说,直接上代码. ======================================= Iteration: 1= Input path: out/shortestpath/input. ...

  3. Mapreduce的文件和hbase共同输入

    Mapreduce的文件和hbase共同输入 package duogemap;   import java.io.IOException;   import org.apache.hadoop.co ...

  4. mapreduce多文件输出的两方法

    mapreduce多文件输出的两方法   package duogemap;   import java.io.IOException;   import org.apache.hadoop.conf ...

  5. mapreduce中一个map多个输入路径

    package duogemap; import java.io.IOException; import java.util.ArrayList; import java.util.List; imp ...

  6. Hadoop 中利用 mapreduce 读写 mysql 数据

    Hadoop 中利用 mapreduce 读写 mysql 数据   有时候我们在项目中会遇到输入结果集很大,但是输出结果很小,比如一些 pv.uv 数据,然后为了实时查询的需求,或者一些 OLAP ...

  7. [Hadoop in Action] 第5章 高阶MapReduce

    链接多个MapReduce作业 执行多个数据集的联结 生成Bloom filter   1.链接MapReduce作业   [顺序链接MapReduce作业]   mapreduce-1 | mapr ...

  8. MapReduce

    2016-12-21  16:53:49 mapred-default.xml mapreduce.input.fileinputformat.split.minsize 0 The minimum ...

  9. 使用mapreduce计算环比的实例

    最近做了一个小的mapreduce程序,主要目的是计算环比值最高的前5名,本来打算使用spark计算,可是本人目前spark还只是简单看了下,因此就先改用mapreduce计算了,今天和大家分享下这个 ...

随机推荐

  1. WC集训DAY2笔记 组合计数 part.1

    目录 WC集训DAY2笔记 组合计数 part.1 基础知识 组合恒等式 错排数 卡特兰数 斯特林数 伯努利数 贝尔数 调和级数 后记 补完了几天前写的东西 WC集训DAY2笔记 组合计数 part. ...

  2. 一步一步解决centos6.5配置无线网卡的问题

    1.配置本地yum源 [local] name=local baseurl=file:///mnt/cdrom enable=1 gpgcheck=0 2.安装libnl rpm -ivh /mnt/ ...

  3. Vue增强

    1. Vue事件 语法:使用v-on指令注册事件 <标签 v-on:事件句柄="表达式或者事件处理函数"></标签> 简写方式:<标签 @事件句柄=& ...

  4. react-native run-ios “Could not find iPhone X simulator”

    问题 这个问题发生在旧的RN版本(0.57,0.58(<0.58.4),-)和Xcode 10.3中,其中可用模拟器的名称得到了一些调整 在文件node_modules/@react nativ ...

  5. opencv图像倾斜校正和切边

    #include<opencv2/opencv.hpp> #include<iostream> #include<cmath> using namespace st ...

  6. Java之数据库表字段有关键字报错java.sql.SQLSyntaxErrorException

    前两天在开发中遇到一个坑,本来我在快乐的做着增删改查,然后悲剧发生了,在查询数据库的过程中,报了java.sql.SQLSyntaxErrorException: 经过排查,是因为数据库表字段中存在关 ...

  7. Azure 上通过Automation 实现定时开关虚拟机

    更多内容,请关注公众号: Azure Automation 可以提供一些自动化的功能,比如我们可以指定在每天早上6点开启虚拟机,每天晚上8点关闭虚拟机.同时还提供一些基于监控参数的自动化配置.今天的主 ...

  8. 搭建ES集群

    服务版本选择 TEG的ctsdb当前最高版本采用的是es的6.4.3版本,为了日后与ctsdb衔接方便,部署开源版es时也采用该版本.6.4.3版本的es依赖的jdk版本要求在8u181以上,测试环境 ...

  9. EXCEPTION_ACCESS_VIOLATION(0xc0000005)

    EXCEPTION_ACCESS_VIOLATION(0xc0000005)eclipse.ini中添加:-XX:CompileCommand=exclude,org.eclipse.jdt.inte ...

  10. win10,7 80端口被占用的检测和解决方法

    这是一篇关于检测windows7和windows10系统“80端口”被哪个程序占用和怎么解决的小教程.此处用windows10作为范例 1.得到占用该端口的PID ①打开运行(快捷键win+R)(也可 ...