• 先看一下目录结构

这里是job接口,负责参数的传递和定时的调用

下面的图是MR 程序相关的目录图片,其中MR的入口程序负责读取数据,并指定对应的Map、Reduce程序。

  • 程序的流程

首先简单的说一下,整体的流程:

  1. 首先是一个Job(定时任务),定时调用 入口程序,拼装参数。
  2. job调用 MR的入口程序,入口程序获得job传入的参数,根据参数获得所需的数据;可以去Hbase、mysql、HDFS中获取数据;这个文件会配置job名、要调用的Mapper、Reduce,添加需要的jar包
  3. 数据传入Mapper程序,Mapper程序进行数据的整合,整合完成的数据会变成:key:{value1,value2,value3,...}这个样子,所以传入Reduce的value应该是一个可迭代的参数(在这里坑了一会)。Mapper将所有的数据整合完成后,会进入Reduce程序
  4. Reduce程序,接受参数,参数类型要和Mapper的返回类型是一样的;values 的入参是 一个可迭代的类型,泛型必须与Mapper的value返回类型一致。然后根据需求进行处理。
  • 上代码

Job程序:

package com.sky.cy.mapreduce.dispatch;

import com.sky.cy.mapreduce.util.BasicMapreduceJob;
import com.ssports.util.LogFormat;
import com.ssports.util.ToolUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component; import java.util.Date; /**
* @描述:
* @文件名: UserActionRecordStatistJob
* @创建人: YangLianjun
* @创建时间: 2019/4/2 9:58
* @修改人:
* @修改备注: Copyright 北京和信金谷科技有限公司 2019/4/2
*/
@Component
public class UserActionRecordStatistJob extends BasicMapreduceJob {
public static Log log = LogFactory.getLog(UserActionRecordStatistJob.class);
@Override
public String[] preProcessJob(String... args) {
log.info(LogFormat.formatMsg("UserActionRecordStatistJob.preProcessJob","","UserActionRecordStatistJob is start"));
String statTimeStr = "";
if (args != null && args.length == 1) {
statTimeStr = args[0];
} else {
Date date = ToolUtil.addDay(new Date(), -1);
String statTime = ToolUtil.getDateStr(date, "yyyyMMdd");
// String statTime = "20190401";
log.info(LogFormat.formatMsg("UserActionRecordStatistJob.preProcessJob","statTime:"+statTime,""));
statTimeStr = statTime;
} String[] retArgs = new String[2];
// 这个参数是指定哪个 MR入口程序
retArgs[0] = "com.sky.cy.mapreduce.job.UserActionRecordStatistMR" ;
retArgs[1] = statTimeStr;
return retArgs;
}
}

MR入口程序,负责数据的读取,指定对应的Map、Reduce程序:

package com.sky.cy.mapreduce.job;

import com.sky.cy.mapreduce.job.mapper.UserActionRecordMapper;
import com.sky.cy.mapreduce.job.mapper.UserActionRecordStatistMapper;
import com.sky.cy.mapreduce.job.reducer.UserActionRecordReducer;
import com.sky.cy.mapreduce.job.reducer.UserActionRecordStatistReducer;
import com.sky.cy.mapreduce.util.BasicMapreduce;
import com.ssports.util.LogFormat;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.*;
import org.apache.hadoop.hbase.mapreduce.MultiTableOutputFormat;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job; import java.io.IOException; /**
* @描述:
* @文件名: UserActionRecordStatistMR
* @创建人: YangLianjun
* @创建时间: 2019/4/2 14:47
* @修改人:
* @修改备注: Copyright 北京和信金谷科技有限公司 2019/4/2
*/
public class UserActionRecordStatistMR extends BasicMapreduce {
public static final Log LOG = LogFactory.getLog(UserActionRecordStatistMR.class); public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
LOG.info(LogFormat.formatMsg("UserActionRecordStatistMR.main","","start ..."));
init();
String statTime = args[0];
// 将日期作为查询条件
Filter filter = new SingleColumnValueFilter(Bytes.toBytes("f"),Bytes.toBytes("stat_time"), CompareFilter.CompareOp.EQUAL,Bytes.toBytes(statTime)) ;
Scan scan = new Scan();
scan.setFilter(filter); Configuration configuration = defaultHbaseConfiguration();
configuration.set("statTime",statTime); Job job = Job.getInstance(configuration, "UserActionRecordStatistMR"); TableMapReduceUtil.initTableMapperJob(UserActionRecordStatistMR.Constants.HBASE_FILTER_TABLE, scan, UserActionRecordStatistMapper.class, Text.class, Text.class, job);
job.setReducerClass(UserActionRecordStatistReducer.class);
job.setNumReduceTasks(1);
job.setOutputFormatClass(MultiTableOutputFormat.class);
//添加mysql驱动包
job.addFileToClassPath(new Path(UserActionMR.Constants.MYSQL_JAR_PATH));
//添加spring的jar
job.addFileToClassPath(new Path(ActionFilterStatistMR.Constants.SPRING_CONTEXT_JAR_PATH));
job.addFileToClassPath(new Path(ActionFilterStatistMR.Constants.SPRING_TX_JAR_PATH));
job.addFileToClassPath(new Path(ActionFilterStatistMR.Constants.SPRING_AOP_JAR_PATH));
job.addFileToClassPath(new Path(ActionFilterStatistMR.Constants.SPRING_BEAN_HADOOP_PATH));
job.addFileToClassPath(new Path(ActionFilterStatistMR.Constants.SPRING_DATA_HADOOP_PATH)); job.waitForCompletion(true); } public static class Constants {
//需要获取的hbase数据的表名
public static final String HBASE_FILTER_TABLE = "sky_user_action_record";
} }

Map程序:

 package com.sky.cy.mapreduce.job.mapper;

 import com.sky.cy.mapreduce.util.HbaseUtil;
import com.sky.cy.mapreduce.util.RegexUtil;
import com.ssports.util.LogFormat;
import com.ssports.util.SpringHelper;
import com.ssports.util.ToolUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.io.Text; import java.io.IOException; /**
* @描述:
* @文件名: UserActionRecordStatistMapper
* @创建人: YangLianjun
* @创建时间: 2019/4/2 14:46
* @修改人:
* @修改备注: Copyright 北京和信金谷科技有限公司 2019/4/2
*/
public class UserActionRecordStatistMapper extends TableMapper<Text, Text> {
private static final Log log = LogFactory.getLog(UserActionRecordStatistMapper.class);
public static final String FAMILY_F = "f"; protected void map(ImmutableBytesWritable key, Result result, Context context) throws IOException, InterruptedException {
log.info(LogFormat.formatMsg("UserActionRecordStatistMapper.map", "", "mapper start ..."));
String userId = HbaseUtil.getValue(FAMILY_F, "user_id", result);
String actionName = HbaseUtil.getValue(FAMILY_F,"action_name",result) ;
String actionId = HbaseUtil.getValue(FAMILY_F,"action_id",result) ;
String statTime = context.getConfiguration().get("statTime");
String keyOut = userId + ":" + statTime;
log.info(LogFormat.formatMsg("UserActionRecordStatistMapper.map", "keyOut:"+keyOut, ""));
Text text = new Text(keyOut);
String valueOut = actionId + ":"+actionName;
log.info(LogFormat.formatMsg("UserActionRecordStatistMapper.map", "valueOut:"+valueOut, ""));
Text value = new Text(valueOut);
context.write(text, value);
log.info(LogFormat.formatMsg("UserActionRecordStatistMapper.map", "", "mapper end ..."));
}
}

Reduce程序:

package com.sky.cy.mapreduce.job.reducer;

import com.sky.cy.log.base.dao.SkyUserActionRecordStatistMapper;
import com.ssports.util.LogFormat;
import com.ssports.util.SpringHelper;
import com.ssports.util.ToolUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.mapreduce.TableReducer;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text; import java.io.IOException;
import java.util.*; /**
* @描述:
* @文件名: UserActionRecordStatistReducer
* @创建人: YangLianjun
* @创建时间: 2019/4/2 14:47
* @修改人:
* @修改备注: Copyright 北京和信金谷科技有限公司 2019/4/2
*/
public class UserActionRecordStatistReducer extends TableReducer<Text, Text, NullWritable> {
private static final Log log = LogFactory.getLog(UserActionRecordStatistReducer.class);
private static final Integer ALL = 1 ; // 统计状态,全部统计 protected void setup(Context context) throws IOException, InterruptedException {
SpringHelper.init("classpath*:spring/*.xml");
} protected void reduce(Text key, Iterable<Text> values, Context context){
log.info(LogFormat.formatMsg("UserActionRecordStatistReducer.reduce","","start ..."));
String keyRow = new String(key.getBytes());
String[] keys = keyRow.split(":");
String userId = keys[0] ;
log.info(LogFormat.formatMsg("UserActionRecordStatistReducer.reduce","userId:"+userId,""));
String statTime = keys[1] ;
log.info(LogFormat.formatMsg("UserActionRecordStatistReducer.reduce", "key:"+keyRow, ""));
List<String> actionList = new ArrayList<>();
for (Text value : values) {
log.info(LogFormat.formatMsg("UserActionRecordStatistReducer.reduce", "value:"+value.toString(), ""));
actionList.add(value.toString()) ;
}
SkyUserActionRecordStatistMapper mapper = SpringHelper.getBean("skyUserActionRecordStatistMapper") ;
com.sky.cy.log.base.bean.SkyUserActionRecordStatistEntity entity = new com.sky.cy.log.base.bean.SkyUserActionRecordStatistEntity() ; Set<String> uniqueSet = new HashSet<>(actionList) ;
for (String s : uniqueSet) {
String actionId = s.split(":")[0] ;
log.info(LogFormat.formatMsg("UserActionRecordStatistReducer.reduce","actionId:"+actionId,""));
String actionName = s.split(":")[1] ;
int actionNumber = Collections.frequency(actionList, s) ; //统计出来数量
entity = mapper.selectTotalByIdAndType(userId,actionId,ALL) ; //查询全部统计 的信息
if (null == entity){ //不存在 这个信息,插入
log.info(LogFormat.formatMsg("UserActionRecordStatistReducer.reduce","","insert start ..."));
com.sky.cy.log.base.bean.SkyUserActionRecordStatistEntity entity1 = new com.sky.cy.log.base.bean.SkyUserActionRecordStatistEntity() ;
entity1.setUserId(userId);
entity1.setActionId(actionId);
entity1.setActionName(actionName);
entity1.setStatistTotal(actionNumber);
entity1.setStatistTime(statTime);
entity1.setStatistType(ALL);
int insert = mapper.insertSelective(entity1) ;
log.info(LogFormat.formatMsg("UserActionRecordStatistReducer.reduce","insert number:"+insert,""));
}else { //存在,进行更新
log.info(LogFormat.formatMsg("UserActionRecordStatistReducer.reduce","","update start..."));
int update = mapper.updateTotalAndDays(userId,actionId,actionNumber,ALL) ; //更新
log.info(LogFormat.formatMsg("UserActionRecordStatistReducer.reduce","update number:"+update,"update end..."));
}
} }
}

说明:

利用集群进行整合、计算、归纳,本身是一个特别复杂的事情,Hadoop中的MR框架可以让我们从复杂的操作中解脱出来,只关注于逻辑本身,无疑是程序员的福音。只要理解了MR的流程和基本的运作原理,就可以像写java程序那样简单的对数据进行处理,但是却比单机的java程序效率高得多。当然既然使用到了MR,数据量应该是巨大的,如果只是对单机mysql中的数据进行统计与计算,建议还是使用普通的方式,毕竟最适合自己才是最好的!!!

MapReduce编写的正确姿势的更多相关文章

  1. (转)Git 提交的正确姿势:Commit message 编写指南

    Git 每次提交代码,都要写 Commit message(提交说明),否则就不允许提交. $ git commit -m "hello world" 上面代码的-m参数,就是用来 ...

  2. 开发函数计算的正确姿势 —— 使用 Fun Local 本地运行与调试

    前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算 ...

  3. Git 提交的正确姿势

    Git 提交的正确姿势:Commit message 编写指南 SCOP范围 middleware core config plugin test type范围 Git 每次提交代码,都要写 Comm ...

  4. IphoneX适配正确姿势

    IphoneX适配正确姿势 写在前面 距离18年9月iphonex发布以来已经快两年了(所以对于iphonex机型的头部刘海(sensor housing)和底部小黑条(Home Indicator) ...

  5. 判断是否为gif/png图片的正确姿势

    判断是否为gif/png图片的正确姿势 1.在能取到图片后缀的前提下 1 2 3 4 5 6 7 8 9 //假设这是一个网络获取的URL NSString *path = @"http:/ ...

  6. 在Linux(ubuntu server)上面安装NodeJS的正确姿势

    上一篇文章,我介绍了 在Windows中安装NodeJS的正确姿势,这一篇,我们继续来看一下在Linux上面安装和配置NodeJS. 为了保持一致,这里也列举三个方法 第一个方法:通过官网下载安装 h ...

  7. 程序员取悦女朋友的正确姿势---Tips(iOS美容篇)

    前言 女孩子都喜欢用美图工具进行图片美容,近来无事时,特意为某人写了个自定义图片滤镜生成器,安装到手机即可完成自定义滤镜渲染照片.app独一无二,虽简亦繁. JH定律:魔镜:最漂亮的女人是你老婆魔镜: ...

  8. ios监听ScrollView/TableView滚动的正确姿势

    主要介绍 监测tableView垂直滚动的舒畅姿势 监测scrollView/collectionView横向滚动的正确姿势 1.监测tableView垂直滚动的舒畅姿势 通常我们用KVO或者在scr ...

  9. 玩转 Ceph 的正确姿势

    玩转 Ceph 的正确姿势 本文先介绍 Ceph, 然后会聊到一些正确使用 Ceph 的姿势:在集群规模小的时候,Ceph 怎么玩都没问题:但集群大了(到PB级别),这些准则可是保证集群健康运行的不二 ...

随机推荐

  1. idea maven项目依赖项有红色波浪线

    在maven面板选中所有报错的maven项目,右键选择移除(remove),之后重新添加.

  2. linux tcpdump补充

    If they are going across the loopback interface, you may have to tell tcpdump to read that interface ...

  3. java代码优化29个点

    通过java代码规范来优化程序,优化内存使用情况,防止内存泄露 可供程序利用的资源(内存.CPU时间.网络带宽等)是有限的,优化的目的就是让程序用尽可能少的资源完成预定的任务.优化通常包含两方面的内容 ...

  4. 反射01 Class类的使用、动态加载类、类类型说明、获取类的信息

    0 Java反射机制 反射(Reflection)是 Java 的高级特性之一,是框架实现的基础. 0.1 定义 Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对 ...

  5. 新浪SAE高级开发者认证通过

    如题,新浪SAE高级开发者认证通过,申请的方式为提交开源项目地址,用的是如下的项目 http://jqext.sinaapp.com/ 之前该项目是部署在 mopaas 上的,在拿到高级开发者资格后迁 ...

  6. Luogu 4251 [SCOI2015]小凸玩矩阵

    BZOJ 4443 二分答案 + 二分图匹配 外层二分一个最小值,然后检验是否能选出$n - k + 1$个不小于当前二分出的$mid$的数.对于每一个$a_{i, j} \geq mid$,从$i$ ...

  7. IP命令的用法详解

    IP命令的用法详解 原创 2017-06-29 10:02:34 0932 摘自:http://www.php.cn/linux-371363.html ip命令是Linux下较新的功能强大的 ...

  8. [GO]数组的比较和赋值

    package main import "fmt" func main() { //支持比较,只支持==或!=,比较是不是每一个元素都一样,2个数据比较,数据类型要一样 a := ...

  9. HackSix 为ViewGroup的子视图添加悦目的动画效果

    1.默认情况下他,添加到viewGrop的子视图是直接显示出来的.有一个比较简单的方法可以为这个过程增加动画效果. 2.知识点:     给子视图添加动画效果就用:LayoutAnimationCon ...

  10. .net core 图片合并,图片水印,等比例缩小,SixLabors.ImageSharp

    需要引用 SixLabors.ImageSharp 和SixLabors.ImageSharp.Drawing 引用方法 NuGet包管理 添加程序包来源 https://www.myget.org/ ...