MapReduce 一直报自定义对象类型转换异常 Caused by: java.lang.ClassCastException: class com.xxx.BrowserBean

错误:

在这里插入图片描述

原题数据文件和题目要求

链接:https://pan.baidu.com/s/1FKcCVbwv30Q7roxZCJX8dw 
提取码:6zja 
题目要求:
使用MR求每个浏览器的数量,过滤掉状态码大于400的数据,或者状态码为空的数据,要求用对象封装数据,输出浏览器和数量
数据说明:
data[0] 用户ip,0
data[1] 客户端用户名
data[3]请求时间
data[5] 请求方法
data[6] 请求页面
data[7] http协议信息
data[8] 返回的状态码
data[9] 发送的页面字节数
data[10]  从什么页面跳转进来
date[11]  浏览器

自定义Bean对象代码如下:

import org.apache.hadoop.io.Writable;

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


/**
 * 
 * 自定义对象只对用到的数据进行了封装
 */
public class BrowserBean implements Writable {
	//状态码
    private Integer status;
    //浏览器名称
    private String browser;

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeInt(status);
        out.writeUTF(browser);
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        this.status = in.readInt();
        this.browser = in.readUTF();
    }

    @Override
    public String toString() {
        return "BrowserBean{" +
                "status=" + status +
                ", browser='" + browser + '\'' +
                '}';
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getBrowser() {
        return browser;
    }

    public void setBrowser(String browser) {
        this.browser = browser;
    }

    public BrowserBean() {
    }

    public BrowserBean(Integer status, String browser) {
        this.status = status;
        this.browser = browser;
    }

    public Integer getStatus() {
        return status;
    }
}

Mapper端代码

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

public class BrowserMapper extends Mapper<LongWritable, Text,BrowserBean,LongWritable> {
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//把value的值转化为字符串
        String s = value.toString();
        //清除空行
        if (!s.isEmpty()) {
        	//对数据进行切分
            String[] split = s.split(" ");
            //判断状态码是否为空
            boolean empty = split[8].isEmpty();
   			//如果不为空执行以下步骤
            if (!empty) {
                int i = Integer.parseInt(split[8]);
                //判断状态码是否小于等于400
                if (i <= 400) {
                    //如果状态码小于等于400就把对象和 1 输出
                    if (split.length > 11) {
                    	//如果浏览器名不为空  或者不为无效数据 "-"  就执行
                        boolean b = !split[11].isEmpty() && !split[11].equals("\"-\"");
						if (b){
                       	    //把数据封装到对象
                      	 	BrowserBean browserBean = new BrowserBean(i, split[11]);
                      	 	//输出结果
                        	context.write(browserBean, new LongWritable(1)); 	
						}
                    }
                }
            }
        }
    }
}

Reducer 端代码

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

public class BrowserReducer extends Reducer<BrowserBean, LongWritable,Text, LongWritable> {
    @Override
    protected void reduce(BrowserBean key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
        //定义计数器
        long count =0 ;
        for (LongWritable value : values) {
        	//计算总和
            count += value.get();
            //获取浏览器名
            String browser = key.getBrowser();
            //输出浏览器名 和 数量
            context.write(new Text(browser), new LongWritable(count));
        }
    }
}

Driver(Runner)端代码

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;


public class BrowserDriver extends Configured implements Tool {
    @Override
    public int run(String[] args) throws Exception {
        //示例一个job
        Configuration c = new Configuration();
        Job j = Job.getInstance(c, "BrowserDriver");

        //设置map类和reduce类
        j.setMapperClass(BrowserMapper.class);
        j.setReducerClass(BrowserReducer.class);

        //设置输出类 和 读取类
        j.setOutputFormatClass(TextOutputFormat.class);
        j.setInputFormatClass(TextInputFormat.class);

        //设置mapper 的输出类型
        j.setMapOutputKeyClass(BrowserBean.class);
        j.setMapOutputValueClass(LongWritable.class);

        //设置reducer 的输出类型
        j.setOutputKeyClass(Text.class);
        j.setOutputValueClass(LongWritable.class);

        //设置读取 和输出路径
        TextInputFormat.addInputPath(j, new Path("C:\\Users\\dell\\Desktop\\练习题\\access.log"));
        TextOutputFormat.setOutputPath(j, new Path("C:\\Users\\dell\\Desktop\\test1"));

        //获取执行之后的结果
        boolean b = j.waitForCompletion(true);
        //成功则 返回 0 , 失败返回 1
        return b ? 0 : 1;
    }

    public static void main(String[] args) throws Exception {
        //进行方法调用
        ToolRunner.run(new BrowserDriver(), args);
    }
}

报错分析:

经过排查一开始以为是自定义Bean对象的问题,在Bean对象中进行了反复的检查发现Bean对象中并没有出现任何的问题,于是进行了进一步的排查,在调用Bean对象的地方进行修改,终于发现是Mapper端输出值的问题.

报错原因:

哈希算法无法对只实现了Writable接口的自定义Bean 对象进行运算,导致partition阶段分区报错

解决方法:

方法一:修改mapper 输出的key值
方法二(推荐使用):如果要把mapper输出的类型key为自定义对象必须实现 WritableComparable<T>接口
修改之后代码如下:

import org.apache.hadoop.io.WritableComparable;

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


/**
 * 
 * 自定义对象只对用到的数据进行了封装
 */
public class BrowserBean implements WritableComparable<BrowserBean> {
	//状态码
    private Integer status;
    //浏览器名称
    private String browser;

	@Override
    public int compareTo(BrowserBean o) {
        return 0;
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeInt(status);
        out.writeUTF(browser);
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        this.status = in.readInt();
        this.browser = in.readUTF();
    }

    @Override
    public String toString() {
        return "BrowserBean{" +
                "status=" + status +
                ", browser='" + browser + '\'' +
                '}';
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getBrowser() {
        return browser;
    }

    public void setBrowser(String browser) {
        this.browser = browser;
    }

    public BrowserBean() {
    }

    public BrowserBean(Integer status, String browser) {
        this.status = status;
        this.browser = browser;
    }

    public Integer getStatus() {
        return status;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值