Hadoop实战之MapReduce_02(idea远程提交MapReduce任务)

2 篇文章 0 订阅
1 篇文章 0 订阅

python运行简单的 MapReduce之 word count

  • 这里python运行就直接在虚机上编写脚本运行测试
  • 准备一份文档 word.txt 任意内容
a b c d e 
ab ab ab abb ac kk kk 
123
22332
434
3433
123
1
1
1
1
  • 准备执行脚本(类似于 java中的main方法,执行入口)
## hadoop 安装目录
HADOOP_CMD="/usr/local/src/hadoop/hadoop-2.10.0/bin/hadoop"  
## 找到hadoop-streaming 的jar包. hadoop支持多语言就是因为有hadoop-streaming. hadoop 1.x 和 hadoop2.x的hadoop-streaming地址不同,可自行百度
STREAM_JAR_PATH="/usr/local/src/hadoop/hadoop-2.10.0/share/hadoop/tools/lib/hadoop-streaming-2.10.0.jar"

## 上传本地文件时 输入本地文件
INPUT_FILE_PATH="/word.txt"
## 输出的haoop 目录
OUTPUT_PATH="/output"

$HADOOP_CMD jar $STREAM_JAR_PATH \
	-input $INPUT_FILE_PATH \
	-output $OUTPUT_PATH \
	-mapper "python map.py" \  ## 指定map阶段使用 map.py的脚本
	-reducer "python red.py" \
	-file ./map.py \    ## 这里file的意思是将本地的 map.py脚本上传到hadoop,让执行任务的datanode节点可以获取map执行脚本
	-file ./red.py
  • 编写mapper map.py
#!/usr/local/bin/python

import sys

# 从标准读入 即 行读,这里对word.txt 标准读入,循环第一次即读入 a b c d e
for line in sys.stdin:
	ss = line.strip().split(' ')
	for s in ss:
		if s.strip() != "":
			print "%s\t%s" % (s, 1) 

执行完成后会生成 <k,v>格式的数据,由于输出时加了 \t 制表符 ,格式例如

a   1
b   1
c   1
d   1
e   1
  • 编写reducer red.py
import sys

cur_word = None
sum = 0

#  同样行读入map输出的数据,制表符切割,得到 k,v 。 计数后返回则为word count结果
for line in sys.stdin:
	ss = line.strip().split('\t')
	if len(ss) != 2:
		continue
	word, count = ss
	
	if cur_word == None:
		cur_word = word
	if cur_word != word:
		print "%s\t%s" % (cur_word, sum)
		sum = 0
		cur_word = word
	sum += int(count)

# print的数据会写入指定的 output 目录生成结果
print "%s\t%s" % (cur_word, sum)
  • 运行,执行run.sh
先放开脚本权限 
chmod +x run.sh

./run.sh  

会有日志显示运行进度,完成后查看结果
hadoop fs -ls /output    

可以得到两个文件,分别是
_SUCCESS  # 结果状态
part-r-00000 # 输出结果

查看结果
hadoop fs -text /output/part-r-00000   得到如下结果

a 1
ab 3
b 1
c 1
····

  • python 本地运行在实际中不太方便,很多时候项目很大,因此这种方式可以用于开发时抽离业务,自己mock数据,只测试一下map reduce的逻辑正确性。并且程序也可以通过linux的cat sort 等命令结合 自己编写脚本直接验证逻辑,可以在运行mapReduce之前运行一下以下命令测试数据结果
上述脚本中逻辑简要流程如下  准备文档  ——》 执行map,从文档中标准读入,处理 -》 执行reduce,获取map处理后的数据 -》 输出到 hdfs 指定目录
因此可以简化为

cat word.txt | python map.py | sort -k1rn | python red.py -> result.txt

因为map执行后,hadoop会默认排序一次,所以这里使用sort 命令模拟 hadoop Shuffle阶段的排序 
使用这种方式可以快速检测自己编写的mapreduce的一些逻辑性问题,可以极大避免在执行hadoop job后因为一些基本问题而造成的资源浪费,节约时间


  • 上述方式即简单的在虚机内使用python方式运行map reduce。举一反三,map 和 reduce 可以根据自己业务需求自定义编写,其中run.sh 的配置可以看参数配置部分内容

参数配置

  • 设置map和reduce个数
//控制reduce个数
-jobconf mapred.reduce.tasks=2 
//map个数由文件决定,输入压缩文件数量即map个数
  • 输出压缩
// 是否打开压缩开关
-jobconf "mapred.compress.map.output=true" \ 
// 指定压缩算法
-jobconf "mapred.map.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec" \

// 输出为压缩
-jobconf "mapred.output.compress=true" \
// 指定输出的压缩格式
-jobconf "mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec" \ 

  • 全局排序
-jobconf stream.num.map.output.key.fields=2 \
-jobconf num.key.fields.for.partition=1 \
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner

java运行之idea远程提交任务到hadoop集群

  • 上面说了在虚机内直接写脚本方式,大部分同学使用java开发。Java开发后有两种方式运行项目
  • 第一种是编写完成后将项目打成jar包,上传到集群中,使用命令
hadoop jar mydemo.jar hdfs://master:9000/input/word/txt(input文件地址) hdfs://master:9000/out(输出文件地址)
  • 第二种是远程提交到hadoop集群上运行,这里主要叙述
    1). 第一步,使用开发工具(eclipse或者idea)创建一个maven项目,我还使用了SpringBoot,引入maven依赖

            <dependency>
                <groupId>org.apache.hadoop</groupId>
                <artifactId>hadoop-hdfs</artifactId>
                <version>2.10.0</version>
            </dependency>
            <dependency>
                <groupId>org.apache.hadoop</groupId>
                <artifactId>hadoop-client</artifactId>
                <version>2.10.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.hadoop</groupId>
                <artifactId>hadoop-mapreduce-client-core</artifactId>
                <version>2.10.0</version>
            </dependency>
            <dependency>
                <groupId>org.apache.hadoop</groupId>
                <artifactId>hadoop-common</artifactId>
                <version>2.10.0</version>
            </dependency>
     
    

    2). 第二步,编写mapper

         package com.hadoop.demo.mapreduce.job.wordcount;
         
         import org.apache.hadoop.io.IntWritable;
         import org.apache.hadoop.io.LongWritable;
         import org.apache.hadoop.io.Text;
         import org.apache.hadoop.mapreduce.Mapper;
         
         import java.io.IOException;
           
         public class MyMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
             @Override
             protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
                 String item = value.toString();
                 String[] items = item.split(" ");
                 if (items.length >= 1) {
                     for (String s : items) {
                         context.write(new Text(s), new IntWritable(1));
                     }
                 }
             }
         }
    
    

    3). 编写reduce

         package com.hadoop.demo.mapreduce.job.wordcount;
         
         import org.apache.hadoop.io.IntWritable;
         import org.apache.hadoop.io.Text;
         import org.apache.hadoop.mapreduce.Reducer;
         
         import java.io.IOException;
           
         public class MyReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
             @Override
             protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
                 int sum = 0;
                 for (IntWritable i : values) {
                     sum ++;
                 }
                 context.write(key, new IntWritable(sum));
             }
         }
    

    4). 编写启动类

         package com.hadoop.demo.mapreduce.job.wordcount;
         
         
         import com.hadoop.demo.mapreduce.job.FileUpload.UploadFile;
         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;
         
         import java.io.IOException;
         import java.util.Properties;
         
         public class Main {
         
         
             public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
         
         
                 Properties properties = System.getProperties();
                 properties.setProperty("HADOOP_USER_NAME", "root");
                 Configuration configuration = new Configuration(true);
                 Job job = Job.getInstance(configuration, "word count demo");
         
         //        configuration.set("mapreduce.job.jar", "/Users/liujun/Documents/javaPro/mapreduce/out/artifacts/mapreduce_jar/mapreduce.jar");
         
                 // 放到nameNode下执行时要把上面一句改成下面这句!!不然找不到target文件夹,会报错。
                 job.setJarByClass(Main.class);
         
                 job.setMapperClass(MyMapper.class);
                 job.setReducerClass(MyReducer.class);
         
                 job.setOutputKeyClass(Text.class);
                 job.setOutputValueClass(IntWritable.class);
         
         
         
                 //job 的相关方法api http://hadoop.apache.org/docs/current/api/org/apache/hadoop/mapreduce/Job.html
         
                 UploadFile uploadFile = new UploadFile();
                 String path = uploadFile.upload();
                 if (path != null) {
         
                     FileInputFormat.addInputPath(job, new Path(path));
                     FileOutputFormat.setOutputPath(job, new Path("hdfs://192.168.0.2:9000/mytest/word_count2"));
         
                     System.exit(job.waitForCompletion(true) ? 0 : 1);
                 }
         
             }
         
         
         }
    
    

    5). 将集群上hadoop/etc 目录下的 core-site.xml , mapred-site.xml, yarn-site.xml 三个配置文件复制到Java项目的Resource目录下,目录如下
    在这里插入图片描述
    6). 修改core-site.xml

         <configuration>
         	<property>
         		<name>fs.defaultFS</name>
         		<value>hdfs://192.168.0.2:9000</value> <!-- 集群 hdfs 地址-->
         	</property>
         	<property>
         		<name>hadoop.tmp.dir</name>
         		<value>file:/usr/local/src/hadoop/hadoop-2.10.0/tmp</value> <!-- 运行job时数据临时存放区 -->
         	</property>
         	<property>
         		<name>mapred.jar</name>
         		<value>/Users/liujun/Documents/javaPro/mapreduce/out/artifacts/mapreduce/mapreduce.jar</value>  <!-- 本地项目打包地址,远程提交需要将本地项目打成jar包上传到hdfs,让datanode可以使用这个jar运行程序处理数据 -->
         	</property>
         </configuration>
    

    7). 修改 mapred-site.xml

         <configuration>
         	<property>
         		<name>mapreduce.framework.name</name>
         		<value>yarn</value>
         	</property>
         	<property>
         		<name>mapred.remote.os</name>
         		<value>Linux</value>
         	</property>
         
         
         	<property>
         		<name>mapreduce.app-submission.cross-platform</name>
         		<value>true</value>
         	</property>
         
         	<!--如果远程集群有开启历史任务服务,则继续配置如下参数,以使得你在本地递交的job,在远程YARN web管理界面也能查询到-->
         	<property>
         		<name>mapreduce.jobhistory.address</name>
         		<value>192.168.0.2:10020</value> <!--配置为远端服务地址-->
         	</property>
         	<property>
         		<name>mapreduce.jobhistory.webapp.address</name>
         		<value>192.168.0.2:19888</value> <!--配置为远端服务地址-->
         	</property>
         	<property>
         		<name>mapreduce.jobhistory.intermediate-done-dir</name>
         		<value>/mr-history/tmp</value> <!--该目录为远端HDFS上的实际存放历史作业的目录地址,按实际配置-->
         	</property>
         	<property>
         		<name>mapreduce.jobhistory.done-dir</name>
         		<value>/mr-history/done</value> <!--该目录为远端HDFS上的实际存放历史作业的目录地址,按实际配置-->
         	</property>
         </configuration>
    

    8). 修改 yarn-site.xml ,以下ip均为集群主节点ip地址,自行修改为自己的即可

         <configuration>
         	<property>
         		<name>yarn.nodemanager.aux-services</name>
         		<value>mapreduce_shuffle</value>
         	</property>
         	<property>
         		<name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>
         		<value>org.apache.hadoop.mapred.ShuffleHandler</value>
         	</property>
         	<property>
         		<name>yarn.resourcemanager.address</name>
         		<value>192.168.0.2:8032</value>
         	</property>
         	<property>
         		<name>yarn.resourcemanager.scheduler.address</name>
         		<value>192.168.0.2:8030</value>
         	</property>
         	<property>
         		<name>yarn.resourcemanager.resource-tracker.address</name>
         		<value>192.168.0.2:8035</value>
         	</property>
         	<property>
         		<name>yarn.resourcemanager.admin.address</name>
         		<value>192.168.0.2:8033</value>
         	</property>
         	<property>
         		<name>yarn.resourcemanager.webapp.address</name>
         		<value>192.168.0.2:8088</value>
         	</property>
         </configuration>
    

    9). 项目配置打包,这里使用idea, eclipse的打包配置自行百度

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    10). 直接运行启动类,即可完成mapreduce的任务提交,可以在集群中查看输出文档,也可以在 http://192.168.0.2:8088/cluster 下查看job运行状态

java 项目远程提交方式demo的github地址

  • https://github.com/mrLjun/mapreduce.git
  • demo 包含更多例如远程提交文件到hdfs等代码例子
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值