使用MapReduce进行数据准备时发生数据缺失解决方法

项目要求

使用IDEA编写Mapreduce代码将HDFS中的数据读取并处理再上传至HDFS

数据示例

数据及数据类型如下表所示

字段

备注

详细描述

video id

视频唯一id

11位字符串

uploader

视频上传者

上传视频的用户名String

age

视频年龄

视频在平台上的整数天

category

视频类别

上传视频指定的视频分类

length

视频长度

整形数字标识的视频长度

views

观看次数

视频被浏览的次数

rate

视频评分

满分5分

ratings

流量

视频的流量,整型数字

conments

评论数

一个视频的整数评论数

related ids

相关视频id

相关视频的id,最多20个

实际数据展示

代码编写

package videodata;

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

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class VideoMap extends Mapper<Object, Text, Text, NullWritable> {
    public void map(Object key, Text value,Context context) throws IOException, InterruptedException {
            String line = value.toString();
            StringTokenizer tokenizer = new StringTokenizer(line, "\t");
            List<String> list = new ArrayList<>();
            while (tokenizer.hasMoreTokens()) {
                String video_id = tokenizer.nextToken();
                String uploader = tokenizer.nextToken();
                String age = tokenizer.nextToken();
                String category = tokenizer.nextToken();
                String length = tokenizer.nextToken();
                String view_count = tokenizer.nextToken();
                String rate = tokenizer.nextToken();
                String ratings = tokenizer.nextToken();
                String comments = tokenizer.nextToken();
                list.add(video_id);
                list.add(uploader);
                list.add(age);
                list.add(category);
                list.add(length);
                list.add(view_count);
                list.add(rate);
                list.add(ratings);
                list.add(comments);
                while (tokenizer.hasMoreTokens()) {
                    String[] relate_id = new String[]{tokenizer.nextToken()};
                    for (int i = 0; i < relate_id.length; i++) {
                        list.add(relate_id[i]);
                    }
                }
                String result = String.join(",", list);
                context.write(new Text(result), NullWritable.get());
            }
        
        }
    }

运行过后控制台报错:

观察错误,发现其原因是map任务读取到到某一行时停止,分析得出可能是原始数据中发生了数据丢失导致字段无法读入,在代码重写map方法之前添加一个变量i并将其初始化,并在循环外添加System.out.println(i++)代码,目的是map任务进行到第几行数据打印出来,这样就可以轻松找到原始数据是哪一行发生了错误。

缺少字段的数据:

找到原始数据对比可知原来是原始数据中的字段发生了缺失,于是观察数据并重新编写能将原始数据进行清洗的代码,在读取原始数据之前加一条判断语句来判断该行数据是否完整,以此来进行数据清洗。

代码优化

package videodata;

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

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class VideoMap extends Mapper<Object, Text, Text, NullWritable> {
    int i = 1;
    public void map(Object key, Text value,Context context) throws IOException, InterruptedException {
        String line = value.toString();
        if (line.length() >= 13) {
            StringTokenizer tokenizer = new StringTokenizer(line, "\t");
            List<String> list = new ArrayList<>();
            System.out.println(i++);
            while (tokenizer.hasMoreTokens()) {
                String video_id = tokenizer.nextToken();
                String uploader = tokenizer.nextToken();
                String age = tokenizer.nextToken();
                String category = tokenizer.nextToken();
                String length = tokenizer.nextToken();
                String view_count = tokenizer.nextToken();
                String rate = tokenizer.nextToken();
                String ratings = tokenizer.nextToken();
                String comments = tokenizer.nextToken();
                list.add(video_id);
                list.add(uploader);
                list.add(age);
                list.add(category);
                list.add(length);
                list.add(view_count);
                list.add(rate);
                list.add(ratings);
                list.add(comments);
                while (tokenizer.hasMoreTokens()) {
                    String[] relate_id = new String[]{tokenizer.nextToken()};
                    for (int i = 0; i < relate_id.length; i++) {
                        list.add(relate_id[i]);
                    }
                }
                String result = String.join(",", list);
                context.write(new Text(result), NullWritable.get());
            }
        }
    }
}

将数据清洗后的数据数量与原始数据的数量进行对比:

从上图中可以看出小部分数据清洗的结果与原始数据的差别还是有很大出入的,如果一个一个数据进行清洗,未免有些麻烦。

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值