MapReduce编程框架

MapReduce编程框架

大数据学习笔记03



一 、MapReduce思想

MapReduce思想在生活中处处可见。我们或多或少都曾接触过这种思想。MapReduce的思想核心是分而治之,充分利用了并行处理的优势。
即使是发布过论文实现分布式计算的谷歌也只是实现了这种思想,而不是自己原创。MapReduce任务过程是分为两个处理阶段:
Map阶段:Map阶段的主要作用是“分”,即把复杂的任务分解为若干个“简单的任务”来并行处理。
Map阶段的这些任务可以并行计算,彼此间没有依赖关系。
Reduce阶段:Reduce阶段的主要作用是“合”,即对map阶段的结果进行全局汇总。
再次理解MapReduce的思想

在这里插入图片描述

二、MapReduce编程规范及示例编写

2.1. Mapper类

用户自定义一个Mapper类继承Hadoop的Mapper类
Mapper的输入数据是KV对的形式(类型可以自定义)
Map阶段的业务逻辑定义在map()方法中
Mapper的输出数据是KV对的形式(类型可以自定义)
注意:map()方法是对输入的一个KV对调用一次!!
2.2 Reducer类
用户自定义Reducer类要继承Hadoop的Reducer类
Reducer的输入数据类型对应Mapper的输出数据类型(KV对)
Reducer的业务逻辑写在reduce()方法中
Reduce()方法是对相同K的一组KV对调用执行一次
2.3 Driver阶段
创建提交YARN集群运行的Job对象,其中封装了MapReduce程序运行所需要的相关参数入输入数据路径,输出数据路径等,也相当于是一个YARN集群的客户端,主要作用就是提交我们MapReduce程序运行。

三 、WordCount代码实现

需求
在给定的文本文件中统计输出每一个单词出现的总次数
输入数据:wc.txt;
输出:
具体步骤
按照MapReduce编程规范,分别编写Mapper,Reducer,Driver。

  1. 新建maven工程
    1. 导入hadoop依赖
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.9.2</version>
</dependency>
</dependencies>
<!--maven打包插件 -->
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin </artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

注意:以上依赖第一次需要联网下载!!

  1. 添加log4j.properties
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

整体思路梳理(仿照源码)
Map阶段:

  1. map()方法中把传入的数据转为String类型
  2. 根据空格切分出单词
  3. 输出<单词,1>

Reduce阶段:

  1. 汇总各个key(单词)的个数,遍历value数据进行累加
  2. 输出key的总数

Driver:

  1. 获取配置文件对象,获取job对象实例
  2. 指定程序jar的本地路径
  3. 指定Mapper/Reducer类
  4. 指定Mapper输出的kv数据类型
  5. 指定最终输出的kv数据类型
  6. 指定job处理的原始数据路径
  7. 指定job输出结果路径
  8. 提交作业

编写Mapper类

import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class WordcountMapper extends Mapper<LongWritable, Text, Text,
IntWritable>{
Text k = new Text();
IntWritable v = new IntWritable(1);
@Override
protected void map(LongWritable key, Text value, Context context) throws
IOException, InterruptedException {
// 1 获取一行
String line = value.toString();
// 2 切割
String[] words = line.split(" ");
// 3 输出
for (String word : words) {
k.set(word);
context.write(k, v);
}
}
}

编写Reducer类

import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class WordcountReducer extends Reducer<Text, IntWritable, Text,
IntWritable>{
int sum;
IntWritable v = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values,Context
context) throws IOException, InterruptedException {
// 1 累加求和
sum = 0;
for (IntWritable count : values) {
sum += count.get();
}
// 2 输出
   v.set(sum);
context.write(key,v);
}
}

编写Driver驱动类

import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class WordcountDriver {
public static void main(String[] args) throws IOException,
ClassNotFoundException, InterruptedException {
// 1 获取配置信息以及封装任务
Configuration configuration = new Configuration();
Job job = Job.getInstance(configuration);
// 2 设置jar加载路径
job.setJarByClass(WordcountDriver.class);
// 3 设置map和reduce类
job.setMapperClass(WordcountMapper.class);
job.setReducerClass(WordcountReducer.class);
// 4 设置map输出
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
// 5 设置最终输出kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 6 设置输入和输出路径
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// 7 提交
boolean result = job.waitForCompletion(true);
System.exit(result ? 0 : 1);
}
}

运行任务

  1. 本地模式
    直接Idea中运行驱动类即可
    idea运行需要传入参数:
    选择editconfiguration
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    注意本地idea运行mr任务与集群没有任何关系,没有提交任务到yarn集群,是在本地使用多线程
    方式模拟的mr的运行。

  2. Yarn集群模式
    把程序打成jar包,改名为wc.jar;上传到Hadoop集群
    选择合适的Jar包
    在这里插入图片描述
    准备原始数据文件,上传到HDFS的路径,不能是本地路径,因为跨节点运行无法获取数
    据!!
    启动Hadoop集群(Hdfs,Yarn)
    使用Hadoop 命令提交任务运行

hadoop jar  wc.jar com.lagou.wordcount.WordcountDriver  /user/lagou/input /user/lagou/output

总结

实现了mapreduce阶段的wordcount程序,主要了解mr的运行机制。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
假设销售数据已经按照一定格式存储在一个大型文本文件中,每一行表示一次销售记录,包含商品名称、销售价格和进货价格。可以按照以下步骤完成利润和销量的统计: 1. Map阶段:将每一行数据按照商品名称作为Key,将销售价格和进货价格作为Value,输出<Key, Value>对。 2. Reduce阶段:对于每一个Key,将其对应的所有记录的Value相加,得到该商品的总销售额和总进货成本。利用这两个值计算该商品的总利润和总销量。 3. 再次Map阶段:将每一个商品的名称作为Key,将其销售额和销量作为Value,输出<Key, Value>对。 4. 再次Reduce阶段:对于每一个Key,将其对应的所有记录的Value相加,得到该商品的总销售额和总销量。根据这两个值可以计算该商品的平均销售价格和平均进货价格,以及利润率和销售量。 5. 根据统计结果,选出利润最高和销量最好的商品。 示例代码如下(假设输入文件路径为input.txt,输出文件路径为output.txt): ```python from mrjob.job import MRJob from mrjob.step import MRStep class SalesAnalysis(MRJob): def steps(self): return [ MRStep(mapper=self.mapper_profit, reducer=self.reducer_profit), MRStep(mapper=self.mapper_sales, reducer=self.reducer_sales), MRStep(mapper=self.mapper_summary, reducer=self.reducer_summary), MRStep(mapper=self.mapper_top, reducer=self.reducer_top) ] def mapper_profit(self, _, line): fields = line.strip().split() product = fields[0] sales = float(fields[1]) cost = float(fields[2]) yield product, (sales, cost) def reducer_profit(self, product, values): total_sales = 0.0 total_cost = 0.0 for sale, cost in values: total_sales += sale total_cost += cost profit = total_sales - total_cost yield product, (total_sales, total_cost, profit) def mapper_sales(self, product, values): total_sales, total_cost, profit = values yield product, (total_sales, 1) def reducer_sales(self, product, values): total_sales = 0.0 total_count = 0 for sale, count in values: total_sales += sale total_count += count avg_price = total_sales / total_count yield product, (total_sales, total_count, avg_price) def mapper_summary(self, product, values): total_sales, total_count, avg_price = values yield None, (product, total_sales, total_count, avg_price) def reducer_summary(self, _, values): top_profit = ('', 0.0) top_sales = ('', 0) for product, total_sales, total_count, avg_price in values: profit_rate = total_sales / avg_price if profit_rate > top_profit[1]: top_profit = (product, profit_rate) if total_count > top_sales[1]: top_sales = (product, total_count) yield 'profit', top_profit[0] yield 'sales', top_sales[0] def mapper_top(self, category, product): yield category, product def reducer_top(self, category, products): top_product = max(products) yield category, top_product if __name__ == '__main__': SalesAnalysis.run() ``` 在命令行中执行以下命令即可运行程序: ```bash python sales_analysis.py input.txt -o output.txt ``` 输出文件output.txt中会包含利润最高和销量最好的商品名称。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值