【HADOOP】关于MapReduce中的reduce参数中的Text重复值问题

说明

在一次Mapreduce任务处理中,碰到了一个有趣的问题,关于在reduce过程中 Iterable<Text>获取值的问题。

问题重现

待处理的文本文件内容:

20012	小明
20015	小红
20012	王伟
20013	刘浩
20015	王明
20015	王亮
20015	曾仓
20012	刘工

目标代码:

protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException{
	// 需求 获取valius的Text值,保存在list中
	...
}

看几个错误示例:

@Override
    protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException{
        logger.info("====================reduce@ key:"+key.toString());
        List<Text> texts = Lists.newArrayList(values);
        for (Text text : texts) {
            logger.info("=========================reduce text: "+text);
        }
        logger.info("-------------------------------------------------");
        context.write(key, null);
    }

打印结果是什么?反正我是第一次就弄错了。

[INFO ] 2019-04-25 20:01:57,138 mapred.skip.on is deprecated. Instead, use mapreduce.job.skiprecords
[INFO ] 2019-04-25 20:01:57,138 ====================reduce@ key:20012
[INFO ] 2019-04-25 20:01:57,138 =========================reduce text: 20012	小明
[INFO ] 2019-04-25 20:01:57,138 =========================reduce text: 20012	小明
[INFO ] 2019-04-25 20:01:57,138 =========================reduce text: 20012	小明
[INFO ] 2019-04-25 20:01:57,138 -------------------------------------------------
[INFO ] 2019-04-25 20:01:57,138 ====================reduce@ key:20013
[INFO ] 2019-04-25 20:01:57,138 =========================reduce text: 20013	刘浩
[INFO ] 2019-04-25 20:01:57,138 -------------------------------------------------
[INFO ] 2019-04-25 20:01:57,138 ====================reduce@ key:20015
[INFO ] 2019-04-25 20:01:57,138 =========================reduce text: 20015	小红
[INFO ] 2019-04-25 20:01:57,138 =========================reduce text: 20015	小红
[INFO ] 2019-04-25 20:01:57,138 =========================reduce text: 20015	小红
[INFO ] 2019-04-25 20:01:57,138 =========================reduce text: 20015	小红
[INFO ] 2019-04-25 20:01:57,138 -------------------------------------------------
[INFO ] 2019-04-25 20:01:57,154 Task:attempt_local1219496750_0001_r_000000_0 is done. And is in the process of committing

这个就是结果。。。。。。没错存储在list中的值都变成了存进去的最后一个值。

再看个示例:

@Override
    protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException{
        logger.info("====================reduce@ key:"+key.toString());
        // 这里换成了iterator
        List<Text> texts = Lists.newArrayList(values.iterator());
        for (Text text : texts) {
            logger.info("=========================reduce text: "+text);
        }
        logger.info("-------------------------------------------------");
        context.write(key, null);
    }

结果和上面是一样的。。。。都是重复值

那我不用工具类了,自己写总可以了吧。

@Override
    protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException{
        logger.info("====================reduce@ key:"+key.toString());
        List<Text> texts = new ArrayList<Text>();
        // 存贮text
        for (Text value : values) {
            texts.add(value);
        }
        // 输出
        for (Text text : texts) {
            logger.info("=========================reduce text: "+text);
        }
        logger.info("-------------------------------------------------");
        context.write(key, null);
    }

可是最终结果,都是一样的。

其实这三种代码,归根结底都是第三种代码。呢么为什么呢?为什么都是重复的最后一个放进去的值呢?

那我们再看另一种代码:

@Override
    protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException{
        logger.info("====================reduce@ key:"+key.toString());
        List<Text> texts = new ArrayList<Text>();
        // 存贮text
        for (Text value : values) {
            texts.add(new Text(value)); // texts.add(new Text(value.toString()));
        }
        // 输出
        for (Text text : texts) {
            logger.info("=========================reduce text: "+text);
        }
        logger.info("-------------------------------------------------");
        context.write(key, null);
    }

注意看texts.add(new Text(value)); // texts.add(new Text(value.toString()));这一句。
结果如下:

[INFO ] 2019-04-25 20:14:25,189 ====================reduce@ key:20012
[INFO ] 2019-04-25 20:14:25,189 =========================reduce text: 20012	刘工
[INFO ] 2019-04-25 20:14:25,189 =========================reduce text: 20012	王伟
[INFO ] 2019-04-25 20:14:25,189 =========================reduce text: 20012	小明
[INFO ] 2019-04-25 20:14:25,189 -------------------------------------------------
[INFO ] 2019-04-25 20:14:25,189 ====================reduce@ key:20013
[INFO ] 2019-04-25 20:14:25,189 =========================reduce text: 20013	刘浩
[INFO ] 2019-04-25 20:14:25,189 -------------------------------------------------
[INFO ] 2019-04-25 20:14:25,189 ====================reduce@ key:20015
[INFO ] 2019-04-25 20:14:25,189 =========================reduce text: 20015	曾仓
[INFO ] 2019-04-25 20:14:25,189 =========================reduce text: 20015	王亮
[INFO ] 2019-04-25 20:14:25,189 =========================reduce text: 20015	王明
[INFO ] 2019-04-25 20:14:25,189 =========================reduce text: 20015	小红
[INFO ] 2019-04-25 20:14:25,189 -------------------------------------------------

和上面完全不一样,这才是正确的结果!!!!
所以在reduce过程中一定要实例化Text

PS:下面的都是我的猜测,当不了真。

当你遍历一个Iterable<Text>时,如果遍历到一半跳出循环,在重新开一个循环的时候就会发现只循环了剩下的一半数据,像是个堆栈,至于为什么还得看源码,看书 等我看到了再补吧。

至于原因,小弟才疏学浅,尚不得知,不过应该和引用到了同一个地址的问题原理差不多吧。不当之处,请指正!谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值