MapReduce实战(五)

需求:

利用MapReduce程序,实现SQL语句中的join关联查询。

订单数据表order:

id date pid amount
1001 20150710 P0001 2
1002 20150710 P0001 3
1002 20150710 P0002 3
1003 20150710 P0003 4

商品信息表product:

pid pname category_id price
P0001 小米6 1000 2499
P0002 锤子T3 1001 2500
P0003 三星S8 1002 6999

假如数据量巨大,两表的数据是以文件的形式存储在HDFS中,需要用mapreduce程序来实现一下SQL查询运算:

select  a.id,a.date,b.name,b.category_id,b.price from t_order a join t_product b on a.pid = b.id

分析:

通过将关联的条件作为map输出的key,将两表满足join条件的数据并携带数据所来源的文件信息,发往同一个reduce task,在reduce中进行数据的串联。

实现:

首先,我们将表中的数据转换成我们需要的格式:

order.txt:

1001,20150710,P0001,2
1002,20150710,P0001,3
1002,20150710,P0002,3
1003,20150710,P0003,4

product.txt:

P0001,小米6,1000,2499
P0002,锤子T3,1001,2500
P0003,三星S8,1002,6999

并且导入到HDFS的/join/srcdata目录下面。

因为我们有两种格式的文件,所以在map阶段需要根据文件名进行一下判断,不同的文案进行不同的处理。同理,在reduce阶段我们也要针对同一key(pid)的不同种类数据进行判断,是通过判断id是否为空字符串进行判断的。

InfoBean.java:

package com.darrenchan.mr.bean;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.apache.hadoop.io.Writable;

/**
 * id date pid amount pname category_id price
 *
 * @author chenchi
 *
 */
public class InfoBean implements Writable {
    private String id;// 订单id
    private String date;
    private String pid;// 产品id
    private String amount;
    private String pname;
    private String category_id;
    private String price;

    public InfoBean() {

    }

    public InfoBean(String id, String date, String pid, String amount, String pname, String category_id, String price) {
        super();
        this.id = id;
        this.date = date;
        this.pid = pid;
        this.amount = amount;
        this.pname = pname;
        this.category_id = category_id;
        this.price = price;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getPid() {
        return pid;
    }

    public void setPid(String pid) {
        this.pid = pid;
    }

    public String getAmount() {
        return amount;
    }

    public void setAmount(String amount) {
        this.amount = amount;
    }

    public String getPname() {
        return pname;
    }

    public void setPname(String pname) {
        this.pname = pname;
    }

    public String getCategory_id() {
        return category_id;
    }

    public void setCategory_id(String category_id) {
        this.category_id = category_id;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "InfoBean [id=" + id + ", date=" + date + ", pid=" + pid + ", amount=" + amount + ", pname=" + pname
                + ", category_id=" + category_id + ", price=" + price + "]";
    }

    /**
     * id date pid amount pname category_id price
     */
    @Override
    public void readFields(DataInput in) throws IOException {
        id = in.readUTF();
        date = in.readUTF();
        pid = in.readUTF();
        amount = in.readUTF();
        pname = in.readUTF();
        category_id = in.readUTF();
        price = in.readUTF();
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeUTF(id);
        out.writeUTF(date);
        out.writeUTF(pid);
        out.writeUTF(amount);
        out.writeUTF(pname);
        out.writeUTF(category_id);
        out.writeUTF(price);
    }

}

Join.java:

package com.darrenchan.mr.join;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
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.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import com.darrenchan.mr.bean.InfoBean;

public class Join {
    /**
     * Mapper类
     * @author chenchi
     *
     */
    public static class JoinMapper extends Mapper<LongWritable, Text, Text, InfoBean>{
        //提前在这里new一个对象,剩下的就是改变它的值,不至于在map方法中创建出大量的InfoBean对象
        InfoBean infoBean = new InfoBean();
        Text text = new Text();//理由同上
        @Override
        protected void map(LongWritable key, Text value, Context context)
                throws IOException, InterruptedException {
            //首先,要判断文件名称,读的是订单数据还是商品数据
            FileSplit inputSplit = (FileSplit) context.getInputSplit();
            String name = inputSplit.getPath().getName();//文件名称
            if(name.startsWith("order")){//来自订单数据
                String line = value.toString();
                String[] fields = line.split(",");
                String id = fields[0];
                String date = fields[1];
                String pid = fields[2];
                String amount = fields[3];

                infoBean.setId(id);
                infoBean.setDate(date);
                infoBean.setPid(pid);
                infoBean.setAmount(amount);
                //对于订单数据来说,后面三个属性都置为""
                //之所以不置为null,是因为其要进行序列化和反序列化
                infoBean.setPname("");
                infoBean.setCategory_id("");
                infoBean.setPrice("");

                text.set(pid);
                context.write(text, infoBean);
            }else{//来自商品数据
                String line = value.toString();
                String[] fields = line.split(",");
                String pid = fields[0];
                String pname = fields[1];
                String category_id = fields[2];
                String price = fields[3];

                infoBean.setPname(pname);
                infoBean.setCategory_id(category_id);
                infoBean.setPrice(price);
                infoBean.setPid(pid);
                //对于订单数据来说,后面三个属性都置为""
                //之所以不置为null,是因为其要进行序列化和反序列化
                infoBean.setId("");
                infoBean.setDate("");
                infoBean.setAmount("");

                text.set(pid);
                context.write(text, infoBean);
            }
        }
    }

    public static class JoinReducer extends Reducer<Text, InfoBean, InfoBean, NullWritable>{
        //订单数据中一个pid会有多条数据
        //商品数据中一个pid只有一条

        @Override
        protected void reduce(Text key, Iterable<InfoBean> values, Context context) throws IOException, InterruptedException {
            List<InfoBean> list = new ArrayList<InfoBean>();//存储订单数据中的多条
            InfoBean info = new InfoBean();//存储商品数据中的一条
            for (InfoBean infoBean : values) {
                if(!"".equals(infoBean.getId())){//来自订单数据
                    InfoBean infoBean2 = new InfoBean();
                    try {
                        BeanUtils.copyProperties(infoBean2, infoBean);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    list.add(infoBean2);
                }else{//来自商品数据
                    try {
                        BeanUtils.copyProperties(info, infoBean);
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
            for (InfoBean infoBean : list) {
                infoBean.setPname(info.getPname());
                infoBean.setCategory_id(info.getCategory_id());
                infoBean.setPrice(info.getPrice());

                context.write(infoBean, NullWritable.get());
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);

        job.setJarByClass(Join.class);

        job.setMapperClass(JoinMapper.class);
        job.setReducerClass(JoinReducer.class);

        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(InfoBean.class);

        job.setOutputKeyClass(InfoBean.class);
        job.setOutputValueClass(NullWritable.class);

        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }

}

注:这里有一个地方需要注意,就是reduce方法的Iterable<InfoBean> values,一定要new 新对象,不能直接赋值,因为迭代器的内容在不断变化。

执行指令:hadoop jar mywc.jar cn.darrenchan.hadoop.mr.wordcount.WCRunner /wc/src /wc/output

运行效果:

时间: 2024-08-03 03:34:59

MapReduce实战(五)的相关文章

System center 2012 R2 实战五、SCVMM2012R2介绍及安装

大家好,今天我来分享的是微软System center组件中第一个组件,SCVMM2012R2的安装,说起SCVMM2012R2,我还想与大家聊一聊,SCVMM2012R2在微软私有云中的作用. 我们知道,微软的私有云一共分为三个层,最底层,是基础架构层,基础架构层上面是服务标准与自动化流程,最上面的是应用管理层,那么什么是基础架构层,基础架构层在微软私有云中是干什么的呢,我先来跟大家说一说我的理解. 微软私有云基础架构层,在我看来,主要作用是,通过微软的云计算,改善企业的IT环境,将企业传统的

以MapReduce编程五步走为基础,说MapReduce工作原理

在之前的Hadoop是什么中已经说过MapReduce采用了分而治之的思想,MapReduce主要分为两部分,一部分是Map--分,一部分是Reduce--合 MapReduce全过程的数据都是以键值对的形式存在的如果你想了解大数据的学习路线,想学习大数据知识以及需要免费的学习资料可以加群:784789432.欢迎你的加入.每天下午三点开直播分享基础知识,晚上20:00都会开直播给大家分享大数据项目实战. 首先,我们假设我们有一个文件,文件中存了以下内容 hive spark hive hbas

C# Redis实战(五)

五.删除数据 在C# Redis实战(四)中讲述了如何在Redis中写入key-value型数据,本篇将讲述如何删除Redis中数据. 1.void Delete(T entity);删除函数的运用 [csharp] view plain copy using (var redisClient = RedisManager.GetClient()) { var user = redisClient.GetTypedClient<User>(); var newUser = new User {

MapReduce实战--倒排索引

本文地址:http://www.cnblogs.com/archimedes/p/mapreduce-inverted-index.html,转载请注明源地址. 1.倒排索引简介 倒排索引(Inverted index),也常被称为反向索引.置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射.它是文档检索系统中最常用的数据结构. 有两种不同的反向索引形式: 一条记录的水平反向索引(或者反向档案索引)包含每个引用单词的文档的列表. 一个单词的

【云计算】实战-五个Docker监控工具的对比

[实战]五个Docker监控工具的对比 您的评价:          收藏该经验     阅读目录 Docker Stats命令 CAdvisor Scout Data Dog Sensu Monitoring Framework 总结   这篇文章作者是Usman,他是服务器和基础架构工程师,有非常丰富的分布式构建经验.该篇文章主要分析评估了五种Docker监控工具,包括免费的和不 免费的:Docker Stats.CAdvisor.Scout.Data Dog以及Sensu.不过作者还是推荐

Hadoop之——MapReduce实战(一)

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/45956487 MapReduce概述      MapReduce是一种分布式计算模型,由Google提出,主要用于搜索领域,解决海量数据的计算问题. MR由两个阶段组成:Map和Reduce,用户只需要实现map()和reduce()两个函数,即可实现分布式计算,非常简单. 这两个函数的形参是key.value对,表示函数的输入信息. MR执行流程 MapReduce原理 执行

MapReduce实战(二)

需求: 基于上一道题,我想将结果按照总流量的大小由大到小输出. 思考: 默认mapreduce是对key字符串按照字母进行排序的,而我们想任意排序,只需要把key设成一个类,再对该类写一个compareTo(大于要比较对象返回1,等于返回0,小于返回-1)方法就可以了. 注:这里如果是实现java.lang.Comparable接口,最终报错,还是直接实现WritableComparable吧. FlowBean.java更改如下: package cn.darrenchan.hadoop.mr

Hadoop之——MapReduce实战(二)

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/45957715 MapReduce的老api写法 import org.apache.hadoop.fs.Path; import org.apache.hadoop.mapred.FileInputFormat; import org.apache.hadoop.mapred.FileOutputFormat; import org.apache.hadoop.mapred.Jo

MapReduce实战(六)

需求: 利用mapReduce实现类似微信好友中查找共同好友的功能.如下: A:B,C,D,F,E,OB:A,C,E,KC:F,A,D,ID:A,E,F,LE:B,C,D,M,LF:A,B,C,D,E,O,MG:A,C,D,E,FH:A,C,D,E,OI:A,OJ:B,OK:A,C,DL:D,E,FM:E,F,GO:A,H,I,J 求出哪些人两两之间有共同好友,及他俩的共同好友都是谁.比如:A,B:[C,E] 分析: 在利用MapReduce程序解答之前,我们不妨用单机程序练习一下,思路很简单,