MapReduce编程--1.统计用户上网流量DataCount

本文介绍如何使用MapReduce技术统计用户上网数据的上行流量、下行流量及总流量。通过自定义Writable数据类型DataBean对数据进行封装,实现数据的高效处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据原型:
这里写图片描述

行数据原型格式释义:

(访问日期)(手机号)(mac地址)(ip地址)(网站名称)(网站类型)(上行流量)(下行流量)(运行状态码)

需求:
将以上数据进行抽取统计,统计每个用户一天内上网数据的上行流量、下行流量和总流量(注意:用户一天之内很可能有多条上网记录)

1.1 使用自定义Writable数据类型—DataBean作为统一的数据类型对数据进行封装


为什么要进行封装?
  因为要统计的项目很多,而mapreduce一次只能输出一个类型的数据,所以我们需要将(手机号、上行流量、下行流量、总流量)封装起来。
其中要注意的细节:
  1.自定义数据类型,需要像 LongWritable、Text一样实现Writable接口
  2.定义成员变量,生成 getter setter方法
  3.添加一个有参构造函数,目的是为了方便对象的初始化
  4.同时别忘了添加默认的无参构造方法
  5.*重写序列化方法 write(DataOutput out )
  6.*重写反序列化方法 readFields(DataInput in )
  !!!注意:
    a. 序列化与反序列化的输出顺序一定要一致
    b. 参数个数一定要一致,有多少输出成员变量,就有多少输入成员变量
  7.如果有需要,重写该自定义类的toString()方法,便于输出到文件中去
  

1.2 自定义数据类型的具体定义过程 举例如下:

  定义DataBean类,属性:用户手机,上行流量,下行流量,总流量 产生getter和setter方法,其中总流量的有参构造方法中定义为 上行+下行

public class FlowBean implements Writable {

    /*
     *成员变量
     */
    private String phoneNB;//手机号
    private long up_flow;//上行流量
    private long down_flow;//下行流量
    private long sum_flow;//总流量

    //在反序列化时,反射机制需要调用无参构造方法,所以显式定义了一个无参构造方法
    public FlowBean() {
        super();
    }
    //为了对象数据的初始化方便,加入一个带参的构造函数
    public FlowBean(String phoneNB, long up_flow, long down_flow) {
        super();
        this.phoneNB = phoneNB;
        this.up_flow = up_flow;
        this.down_flow = down_flow;
        this.sum_flow = up_flow+down_flow;
    }

    // getters and setters
    public String getPhoneNB() {
        return phoneNB;
    }

    public void setPhoneNB(String phoneNB) {
        this.phoneNB = phoneNB;
    }

    public long getUp_flow() {
        return up_flow;
    }

    public void setUp_flow(long up_flow) {
        this.up_flow = up_flow;
    }

    public long getDn_flow() {
        return down_flow;
    }

    public void setDn_flow(long dn_flow) {
        this.down_flow = dn_flow;
    }

    public long getSum_flow() {
        return sum_flow;
    }

    public void setSum_flow(long sum_flow) {
        this.sum_flow = sum_flow;
    }

    //重写序列化方法
    @Override
    public void write(DataOutput out) throws IOException {
        out.writeUTF(phoneNB);
        out.writeLong(up_flow);
        out.writeLong(down_flow);
        out.writeLong(sum_flow);
    }
    //重写反序列化方法
    @Override
    public void readFields(DataInput in) throws IOException {
        phoneNB = in.readUTF();
        up_flow = in.readLong();
        down_flow = in.readLong();
        sum_flow = in.readLong();
    }
    //重写toString方法
    @Override
    public String toString() {
        return ""+ up_flow+"\t"+down_flow+"\t"+sum_flow;
    }
}

1.3 Map-Reduce程序编写:

mapper类

public class FlowSumMapper extends Mapper<LongWritable, Text, Text, FlowBean>{

    //拿到日志中的一行数据,并切分成各个字段,,抽取出我们需要的字段
        //:手机号,上行流量、下行流量  接着封装成k-v发送出去
    @Override
    protected void map(LongWritable key, Text value, Context context)
            throws IOException, InterruptedException {
        //拿一行数据出来
        String line = value.toString();
        //切分
        String[] fields = StringUtils.split(line, '\t');

        //取出需要的字段
        String phoneNB = fields[1];
        long up_flow = Long.parseLong(fields[7]);
        long down_flow = Long.parseLong(fields[8]);

        //封装数据并输出
        context.write(new Text(phoneNB), new FlowBean(phoneNB,up_flow,down_flow));

    }
}

reducer类

public class FlowSumReducer extends Reducer<Text, FlowBean, Text, FlowBean> {

    //框架每传递一组数据<1387788654,{FlowBean,FlowBean,FlowBean...}>调用一次reduce方法
        //reduce中的业务逻辑是遍历values,然后进行累加求和后输出
    protected void reduce(Text key, Iterable<FlowBean> value, Context context) 
            throws java.io.IOException ,InterruptedException {
        long up_flow_counter = 0;
        long down_flow_counter = 0;

        for(FlowBean b : value){
            up_flow_counter += b.getUp_flow();
            down_flow_counter += b.getDn_flow();
        }
        //写出时,value是一个FlowBean对象,因为要写到文件中去,所以要重写其toString()方法
        context.write(key, new FlowBean(key.toString(),up_flow_counter,down_flow_counter));
    };
}

mapreduce运行类:

public class FlowSumRunner extends Configured implements Tool {

    @Override
    public int run(String[] args) throws Exception {

        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);

        job.setJarByClass(FlowSumRunner.class);

        job.setMapperClass(FlowSumMapper.class);
        job.setReducerClass(FlowSumReducer.class);

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

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(FlowBean.class);

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

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

    public static void main(String[] args) throws Exception {
        //官方推荐的写法
        ToolRunner.run(new Configuration(),new FlowSumRunner(),args);
        System.exit(0);
    }
}

1.4 运行该任务

打包项目,导出到/root/examples.jar
上传源数据文件,到/data.doc目录下

在 /root !!目录下运行如下命令:
这里写图片描述

注意事项:
运行前先检查是否已经存在该输出目录,如果有的话,删除后再运行MR例程

执行结果:
13480253104 180 180 360
13502468823 7335 110349 117684
13560436666 1116 954 2070
13560439658 2034 5892 7926
13602846565 1938 2910 4848
13660577991 6960 690 7650
13719199419 240 0 240
13726230503 2481 24681 27162
13726238888 2481 24681 27162
13760778710 120 120 240
13826544101 264 0 264
13922314466 3008 3720 6728
13925057413 11058 48243 59301
13926251106 240 0 240
13926435656 132 1512 1644
15013685858 3659 3538 7197
15920133257 3156 2936 6092
15989002119 1938 180 2118
18211575961 1527 2106 3633
18320173382 9531 2412 11943
84138413 4116 1432 5548

和源数据进行对比,以上结果是正确的

<think>我们正在解决Hadoop2.7.7运行MapReduce示例程序时出现的"找不到或无法加载主类"错误。根据引用[1]和[2],用户尝试运行示例程序(如pi或grep)时遇到问题。这个错误通常是由于Hadoop类路径配置不正确或示例JAR文件路径错误引起的。解决方案步骤:1.**确认JAR文件路径**:首先,确保你使用的JAR文件路径正确。在Hadoop2.7.7中,示例JAR文件通常位于:`$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar`使用绝对路径来运行命令,例如:```bashhadoopjar/path/to/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jarpi1010```2.**设置HADOOP_CLASSPATH**:如果类路径没有正确设置,Hadoop可能无法找到主类。可以尝试设置`HADOOP_CLASSPATH`环境变量,包含示例JAR文件所在的目录:```bashexportHADOOP_CLASSPATH=$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar```3.**检查Hadoop配置文件**:确保`mapred-site.xml`中配置了正确的框架名称(YARN):```xml<configuration><property><name>mapreduce.framework.name</name><value>yarn</value></property></configuration>```4.**重新初始化环境变量**:有时环境变量可能没有正确加载,尝试重新加载环境变量:```bashsource$HADOOP_HOME/etc/hadoop/hadoop-env.sh```5.**检查JAVA_HOME设置**:在`hadoop-env.sh`中确认`JAVA_HOME`设置正确(引用[3][4]):```bashexportJAVA_HOME=/usr/local/src/jdk1.8.0_381#替换为你的实际路径```6.**使用完整的类名**:如果上述方法无效,可以尝试使用完整的类名运行。例如,计算pi的类名为`org.apache.hadoop.examples.Pi`:```bashhadoopjar/path/to/hadoop-mapreduce-examples-2.7.7.jarorg.apache.hadoop.examples.Pi1010```7.**检查Hadoop服务状态**:确保HDFS和YARN服务已经启动:```bashstart-dfs.shstart-yarn.sh```8.**检查JAR文件完整性**:确认JAR文件没有损坏。可以通过列出JAR文件内容来检查:```bashjartf/path/to/hadoop-mapreduce-examples-2.7.7.jar|grepPi.class```应该能看到`org/apache/hadoop/examples/Pi.class`。9.**检查用户权限**:确保当前用户有权限执行Hadoop命令和访问JAR文件。如果以上步骤仍无法解决问题,请检查Hadoop日志(位于`$HADOOP_HOME/logs/`)以获取更详细的错误信息。相关问题:1.Hadoop中如何正确配置类路径?2.如何诊断Hadoop作业提交失败的原因?3.HadoopMapReduce示例程序有哪些常用示例?4.如何修复Hadoop中的类加载问题?</think>### 解决 Hadoop 2.7.7 MapReduce "找不到或无法加载主类" 错误 #### 🔍 问题原因分析 该错误通常由以下原因引起: 1. **JAR文件路径错误**:Hadoop无法定位示例程序JAR文件[^1][^2] 2. **类路径配置缺失**:Hadoop未正确加载MapReduce依赖库 3. **环境变量未生效**:`HADOOP_CLASSPATH`未包含必要路径 4. **JAR文件损坏**:下载或传输过程中文件损坏 #### ✅ 解决方案步骤 ##### 1. 验证JAR文件路径 ```bash # 检查示例JAR是否存在(注意版本号) ls $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar # 正确执行命令格式(使用绝对路径) hadoop jar /path/to/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar pi 10 10 ``` ##### 2. 配置全局类路径 编辑 `hadoop-env.sh` 添加类路径: ```bash vim $HADOOP_HOME/etc/hadoop/hadoop-env.sh ``` 添加以下配置(根据实际路径调整): ```bash export HADOOP_CLASSPATH=$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:$HADOOP_HOME/share/hadoop/mapreduce/*:$HADOOP_HOME/share/hadoop/common/* ``` ##### 3. 修复依赖库路径 在 `mapred-site.xml` 添加库路径配置: ```xml <property> <name>mapreduce.application.classpath</name> <value> $HADOOP_HOME/share/hadoop/mapreduce/*, $HADOOP_HOME/share/hadoop/mapreduce/lib/*, $HADOOP_HOME/share/hadoop/common/*, $HADOOP_HOME/share/hadoop/common/lib/* </value> </property> ``` ##### 4. 验证JAR文件完整性 ```bash # 检查文件MD5(应与官方一致) md5sum $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar # 重新下载损坏的JAR(从官方镜像) wget https://archive.apache.org/dist/hadoop/common/hadoop-2.7.7/hadoop-2.7.7.tar.gz tar -xzf hadoop-2.7.7.tar.gz --strip-components=2 hadoop-2.7.7/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar ``` ##### 5. 使用完整类名执行 ```bash hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar \ org.apache.hadoop.examples.Pi 10 10 ``` ##### 6. 检查服务状态 确保HDFS和YARN已启动: ```bash # 检查NameNode hdfs dfsadmin -report # 检查YARN资源管理器 yarn node -list ``` #### ⚠️ 注意事项 1. **权限问题**:确保执行用户对JAR文件有读取权限 2. **配置同步**:在集群环境下同步所有节点的配置文件 3. **环境变量生效**:修改后执行 `source $HADOOP_HOME/etc/hadoop/hadoop-env.sh` 4. **版本一致性**:确认命令中的JAR版本号与实际完全匹配 > 通过上述步骤可解决99%的类加载错误。若仍失败,检查 `$HADOOP_HOME/logs/userlogs/` 中的详细错误日志。 --- ### 相关问题 1. **如何验证Hadoop集群的MapReduce功能是否正常?** > 探讨MapReduce健康检查的标准流程 2. **Hadoop类路径冲突有哪些典型表现?如何解决?** > 分析类加载冲突的诊断方法与解决策略 3. **Hadoop 2.x与3.x的MapReduce API有何兼容性差异?** > 对比版本间API变化及迁移注意事项 4. **如何为自定义MapReduce作业配置依赖库?** > 解析作业依赖管理的三种实现方式 5. **Hadoop环境变量配置的最佳实践是什么?** > 探讨全局配置与作业级配置的优先级管理 [^1]: Hadoop示例程序执行方法 [^2]: MapReduce作业运行错误分析 [^3]: Hadoop类路径配置规范 [^4]: JAR文件完整性验证流程 [^5]: Hadoop服务状态检查方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值