第一个Map-Reduce程序

本文详细介绍了使用 Hadoop 进行 MapReduce 数据处理的全过程,包括开发环境搭建、数据准备、Eclipse 配置、编写 Mapper 和 Reducer 代码、作业启动及输出结果分析。
1. 开发环境
=========

hadoop:

Hadoop 1.1.2
Subversion https://svn.apache.org/repos/asf/hadoop/common/branches/branch-1.1 -r 1440782
Compiled by hortonfo on Thu Jan 31 02:08:44 UTC 2013
From source with checksum c720ddcf4b926991de7467d253a79b8b

java:

java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.5) (6b27-1.12.5-0ubuntu0.12.04.1)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)


os:

Distributor ID:	Ubuntu
Description:	Ubuntu 12.04.2 LTS
Release:	12.04
Codename:	precise


eclipse:

Eclipse Platform

Version: 3.7.2
Build id: I20110613-1736



2. 数据准备
=========


要做map-reduce,得先准备点数据。


在这个例子中,我产生了1亿条,1000个学生的考试成绩数据,学生的学号是从1 - 1000,考试成绩的范围是0 - 100


用php搞个小脚本来搞定


<?php
	$i = 0;
	$nRows = 10000000;
	$fileData = fopen("Score.data", "a+");
	if(!$fileData)
		die("Can't open file!\n");
	for(; $i < $nRows; $i++)
	{
		$nNumber = rand(1, 1000);
		$nScore = rand(0, 100);
		$strLine = $nNumber."\t".$nScore."\n";
		fputs($fileData, $strLine);
	}
	fclose($fileData);
?>


3. 配置eclipse
=========

用hadoop搞map-reduce自然要用java,用java自然要用eclipse


eclipse是有hadoop map-reduce插件的,但是那个插件兼容的版本已经太老了,因此如果你用了新版的eclipse,还得自己配一下hadoop的包。


hadoop的包在ubuntu上安装在


/usr/share/hadoop

该路径下有一系列jar包(包括lib的子目录里等),导入到工程中,其中一般有用的是hadoop-core-1.1.2.jar这个包,基本上都要导入


4. 写个mapper

=========

mapper在我们求平均分的例子中是将每一行数据拆分成<键:学号,值:分数>的对以交给reducer使用
import java.io.IOException;
import java.util.StringTokenizer;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.Mapper;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reporter;


public class CAvgScoreMapper implements Mapper<LongWritable, Text, Text, IntWritable>
{
	//Mapper<LongWritable, Text, Text, IntWritable>是映射器接口,模板参数:
	//LongWritable是输入给映射器的Key(一般是文件的偏移量)
	//Text是输入给映射器的键值对中的值,一般是每一行文件的内容,
	//Text是输出给归约器的键, 在此学号我们认为是字符串数据
	//IntWritable是输出给归约器的值,在此是成绩,因此是整数
	@Override
	public void configure(JobConf objJobConfig)
	{
		//这个函数将作业启动时的job配置对象传入
		
	}

	@Override
	public void close() throws IOException
	{return;
		//目前没啥用处,不用管
		
	}

	@Override
	public void map(LongWritable lKey, Text txtLine, OutputCollector<Text, IntWritable> ReducerInput, Reporter objReporter) 
			throws IOException 
	{
		//这是映射器的映射函数,在此将数据的每一行拆成学号:成绩的对
		try
		{
			String strLine = txtLine.toString(); //这个函数中txtLine的输入就恰是每一行数据.
			if(strLine.length() < 3) return; //正常数据至少有3个字符:学号一个字符,制表符一个字符,分数一个字符
			StringTokenizer objToken = new StringTokenizer(strLine, "\t");
			String strPair[] = new String[2];
			int i = 0;
			for(; (i < 2) && objToken.hasMoreTokens(); i++) //分解每一行的数据,构成键值对
			{
					strPair[i] = objToken.nextToken(); 
			}
			if(i < 2) return; //行数据分解的有问题
			int nScore = Integer.parseInt(strPair[1]);
			ReducerInput.collect(new Text(strPair[0]), new IntWritable(nScore));
		}
		catch(Exception expError)
		{
			return;
		}
	}
}


    


5. 写个reducer

=========

reducer从mapper收到整理好的键值对,其中键是每一个学生的学号,值是一个列表,里面有这个学生的所有成绩
import java.io.IOException;
import java.util.Iterator;

import org.apache.hadoop.io.FloatWritable;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reducer;
import org.apache.hadoop.mapred.Reporter;


public class CAvgScoreReducer implements Reducer<Text, IntWritable, Text, FloatWritable>
{
	//Reducer<Text, IntWritable, Text, FloatWritable>是归约器的接口,模板参数:
	//Text 从映射器收来的参数,这里是字符串(学号)
	//IntWritable 从映射收来的参数,这里是整数(分数)
	//Text 向结果输出的键,这里是字符串(学号)
	//FloatWritable 向结果输出的值,这里是浮点(平均分)
	@Override
	public void configure(JobConf objJobConf)
	{
		//这个函数将作业启动时的job配置对象传入
		
	}

	@Override
	public void close() throws IOException
	{
		//目前没啥用处,不用管
		
	}

	@Override
	public void reduce(Text nNumber, Iterator<IntWritable> arrScores, OutputCollector<Text, FloatWritable> objOutput, Reporter objReporter)
			throws IOException
	{
		try
		{
			//从分数中读取所有数据进行加合
			int nScoreCount = 0;
			long nTotal = 0;
			for(; arrScores.hasNext(); nScoreCount++)
			{
				nTotal += arrScores.next().get();
			}
			if(nScoreCount <= 0) //分数统计的有问题
				return;
			float fAvgScore = nTotal / nScoreCount;
			objOutput.collect(nNumber, new FloatWritable(fAvgScore)); //将平均分写入输出
		}
		catch(Exception expError)
		{
			return;
		}
	}
}

    


6. 写个作业启动器

=========

写好mapper和reducer后,还需要写一个能够启动作业的玩意

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.FileInputFormat;
import org.apache.hadoop.mapred.FileOutputFormat;
import org.apache.hadoop.mapred.JobClient;
import org.apache.hadoop.mapred.JobConf;



public class CAvgScoreApp
{
    public static void main(String arrArgvs[])
    {
        try
        {
            if(arrArgvs.length < 2)
            {
                System.out.println("Usage: AgvScore <input file> <output dir>");
                System.exit(-1);
            }
            JobConf objJobConfig = new JobConf(); //创建一个作业配置对象
            objJobConfig.setJobName("Get-Average-Score");
            FileInputFormat.addInputPath(objJobConfig, new Path(arrArgvs[0])); //作业的输入是一个文件
            FileOutputFormat.setOutputPath(objJobConfig, new Path(arrArgvs[1])); //设定作业是向文件输出,此处指定输出目录
            objJobConfig.setMapperClass(CAvgScoreMapper.class); //设定映射器类
            objJobConfig.setReducerClass(CAvgScoreReducer.class); //设定本作业归约器的名
            objJobConfig.setOutputKeyClass(Text.class); //设定映射器向归约器输出时,键的类型
            objJobConfig.setOutputValueClass(IntWritable.class); //设定映射器向归约器输出时,值的类型
            
            JobClient.runJob(objJobConfig); //运行任务
        }
        catch(Exception expError)
        {
            System.out.println(expError.getMessage());
            System.exit(-1);
        }
    }
}



7. 启动作业

=========

将程序封装成一个可执行的Jar包,然后在terminal

hadoop jar jar包名字 输入文件的名字 输出目录

即可,这里一定注意,是jar,不是-jar,原因参见我另一篇博文

下面是一个输出结果的例子

1	49.0
10	49.0
100	49.0
1000	50.0
101	50.0
102	49.0
103	49.0
104	49.0
105	49.0
106	50.0
107	49.0
108	49.0


当前,全球经济格局深刻调整,数字化浪潮席卷各行各业,智能物流作为现代物流发展的必然趋势和关键支撑,正迎来前所未有的发展机遇。以人工智能、物联网、大数据、云计算、区块链等前沿信息技术的快速迭代与深度融合为驱动,智能物流不再是传统物流的简单技术叠加,而是正在经历一场从自动化向智能化、从被动响应向主动预测、从信息孤岛向全面互联的深刻变革。展望2025年,智能物流系统将不再局限于提升效率、降低成本的基本目标,而是要构建一个感知更全面、决策更精准、执行更高效、协同更顺畅的智慧运行体系。这要求我们必须超越传统思维定式,以系统化、前瞻性的视角,全面规划和实施智能物流系统的建设。本实施方案正是基于对行业发展趋势的深刻洞察和对未来需求的精准把握而制定。我们的核心目标在于:通过构建一个集成了先进感知技术、大数据分析引擎、智能决策算法和高效协同平台的综合智能物流系统,实现物流全链路的可视化、透明化和智能化管理。这不仅是技术层面的革新,更是管理模式和服务能力的全面提升。本方案旨在明确系统建设的战略方向、关键任务、技术路径和实施步骤,确保通过系统化部署,有效应对日益复杂的供应链环境,提升整体物流韧性,优化资源配置效率,降低运营成本,并最终为客户创造更卓越的价值体验。我们致力于通过本方案的实施,引领智能物流迈向更高水平,为构建现代化经济体系、推动高质量发展提供强有力的物流保障。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值