大数据实验3.2

二、开发MR程序清洗电商评论数据

1.数据清洗概述

数据清洗是对数据进行重新审查和校验的过程,目的在于删除重复信息、纠正存在的错误,并提供数据一致性。

数据清洗从名字上也看的出就是把“脏”的“洗掉”,指发现并纠正数据文件中可识别的错误的最后一道程序,包括检查数据一致性,处理无效值和缺失值等。因为数据仓库中的数据是面向某一主题的数据的集合,这些数据从多个业务系统中抽取而来而且包含历史数据,这样就避免不了有的数据是错误数据、有的数据相互之间有冲突,这些错误的或有冲突的数据显然是我们不想要的,称为“脏数据”。我们要按照一定的规则把“脏数据”“洗掉”,这就是数据清洗。而数据清洗的任务是过滤那些不符合要求的数据,将过滤的结果交给业务主管部门,确认是否过滤掉还是由业务单位修正之后再进行抽取。不符合要求的数据主要是有不完整的数据、错误的数据、重复的数据三大类。数据清洗是与问卷审核不同,录入后的数据清洗一般是由计算机而不是人工完成。

2.解析Json

通过爬虫,我们可以得到一些Json形式的数据文件。

但是Json文件,内容格式比较混乱。所以还需要进一步清洗,提取出有用的信息。

上一节,演示了使用代码格式化工具http://tool.oschina.net/codeformat/json,对Json评论进行格式化的过程。

格式化后的代码,显得结构更加明显清晰

例如,comments中详细内容:

view plain "copy

  1. id": 10432588299,  
  2. guid": "6c1d83b1-ac45-4189-a041-774eaff87df9",  
  3. content": "割手,相当的割手,无语了",  //评论内容 √  
  4. creationTime": "2017-05-22 23:37:24", //写评论的时间 √  
  5. isTop": false,                        //是否置顶  
  6. referenceTime": "2017-05-20 18:35:11",//收货时间 √  
  7. firstCategory": 9987,                 //第一分类 √  
  8. secondCategory": 653,                 //第二分类 √  
  9. thirdCategory": 655,                  //第三分类 √  
  10. replyCount": 0,  
  11. score": 3,                            //打分 √  
  12. nickname": "j***柜",                  //昵称  √  
  13. userClient": 2,  
  14. productColor": "碳黑色",  
  15. productSize": "32GB",  
  16. userLevelName": "金牌会员",           //会员级别 √  
  17. plusAvailable": 0,  
  18. productSales": [  
  19.    {  
  20.        "dim": 3,  
  21.        "saleName""选择套装",  
  22.        "saleValue""官方标配"  
  23.    }  
  24. ,  
  25. userClientShow": "来自京东iPhone客户端",//评论设备  
  26. isMobile": true,                       //是否移动端  
  27. days": 2,                              //评论时间距【收货/下单】时间多长时间  
  28. afterDays": 0  

在这段Json中,对我们有用的是,如下一些字段

view plain "copy

  1. "id": 10432588299,  
  2. "guid""6c1d83b1-ac45-4189-a041-774eaff87df9",  
  3. "content""割手,相当的割手,无语了",   //评论内容 √  
  4. "creationTime""2017-05-22 23:37:24",  //写评论的时间 √  
  5. "isTop"false,                         //是否置顶  
  6. "referenceTime""2017-05-20 18:35:11"//收货时间 √  
  7. "score": 3,                             //打分 √  
  8. "nickname""j***柜",                   //昵称  √  
  9. "userLevelName""金牌会员",            //会员级别 √  
  10. "userClientShow""来自京东iPhone客户端",//评论设备  
  11. "isMobile"true,                       //是否移动端  
  12. "days": 2,                              //评论时间距【收货/下单】时间多长时间  

当然,判断字段是否对我们有用,判断依据是根据需求来定的。后续做的一些需求,会用到哪些字段,此处就会采集哪些字段。

这一节我们会使用MapReduce,对大量的Json文件,进行清洗,以得到结构化的文本文件。

3.搭建解析框架

1.切换目录到/data/目录下,创建名为edu2的目录

view plain "copy

  1. cd /data/  

view plain "copy

  1. mkdir /data/edu2  

2.切换目录到/data/edu2目录下,使用wget命令,下载项目所依赖的lib包

view plain "copy

  1. cd /data/edu2  

view plain "copy

  1. wget http://59.64.78.41:60000/allfiles/edu2/hadoop2lib.tar.gz  

view plain "copy

  1. wget http://59.64.78.41:60000/allfiles/edu2/fastjson-1.2.31.jar  

hadoop2lib.tar.gz压缩包,解压缩。

view plain "copy

  1. tar -xzvf hadoop2lib.tar.gz  

3.打开eclipse,新建Java Project

将项目命名为qingxi2

4.右键项目名,新建一个目录,命名为libs用于存储项目依赖的jar包

/data/edu2/hadoop2lib目录下,所有的jar包,拷贝到项目下的libs目录下。

/data/edu2/目录下,fastjson-1.2.31.jar,拷贝到项目下的libs目录下。

选中libs下,所有的jar文件,依次点击“Build Path” => "Add to Build Path"

5.右键src,点击 "New" => "Package",新建一个包

将包命名为my.mr

右键包名,依次点击“New” => “Class”

并将类命名为QingXiJson

这样清洗过程的框架搭建完毕,下面开始编写代码实现功能。

4.编写MapReduce代码

1.执行jps,查看hadoop相关进程是否已经启动。

view plain "copy

  1. jps  

若未启动,则需启动hadoop

view plain "copy

  1. cd /apps/hadoop/sbin  

view plain "copy

  1. ./start-all.sh  

2.切换目录到/data/edu2目录下,使用wget命令,下载爬取到的电商评论数据。

view plain "copy

  1. cd /data/edu2  

view plain "copy

  1. wget http://59.64.78.41:60000/allfiles/edu2/club.jd.com.tgz  

club.jd.com.tgz解压缩

view plain "copy

  1. tar -xzvf club.jd.com.tgz  

hdfs上创建目录,名为/myedu2,并将/data/edu2/club.jd.com下的数据,上传到hdfs中。

view plain "copy

  1. hadoop fs -mkdir -p /myedu2/in  
  2. hadoop fs -put /data/edu2/club.jd.com/* /myedu2/in  

*此处也可以将自己爬取到的电商评论数据,上传到hdfs上。

3.代码所实现的需求,是使用MapReduce解析Json文件,最终输出格式化的文本文件。

首先来看MapReduce通用的框架结构样式。

view plain "copy

  1. public class QingXiJson {  
  2.     public static void main(String[] args) throws IOException,  
  3.                 ClassNotFoundException, InterruptedException {  
  4.     }  
  5.     public static class doMapper extends Mapper<Object, Text, Text, Text> {  
  6.         @Override  
  7.         protected void map(Object key, Text value, Context context)  
  8.                     throws IOException, InterruptedException {  
  9.         }  
  10.     }  
  11.   
  12.     public static class doReducer extends Reducer<Text, Text, Text, Text>{  
  13.         @Override  
  14.         protected void reduce(Text key, Iterable<Text> values, Context context)  
  15.     throws IOException, InterruptedException {  
  16.     }  
  17.     }  
  18.     }  

通过分析可以知道,此处只用Map任务即可实现具体功能,所以可以省去Reduce任务。

4.Main主函数。这里的main函数也是通用的结构

view plain "copy

  1. public static void main(String[] args) throws IOException,  
  2.             ClassNotFoundException, InterruptedException {  
  3.     Job job = Job.getInstance();  
  4.     job.setJobName("QingXiJson");  
  5.     job.setJarByClass(QingXiJson.class);  
  6.   
  7.     job.setMapperClass(doMapper.class);  
  8.     //job.setReducerClass(doReducer.class);  
  9.     job.setOutputKeyClass(Text.class);  
  10.     job.setOutputValueClass(Text.class);  
  11.     Path in = new Path("hdfs://localhost:9000//myedu2/in");  
  12.     Path out = new Path("hdfs://localhost:9000//myedu2/out/1");  
  13.     FileInputFormat.addInputPath(job, in);  
  14.     FileOutputFormat.setOutputPath(job, out);  
  15.     System.exit(job.waitForCompletion(true) ? 0 : 1);  
  16. }  

①定义Job

②设置Job参数

③设置Map任务

④设置Reduce任务

⑤定义任务的输出类型

⑥设置任务的输入输出目录

⑦提交执行

5.再来看Map任务,实现Map任务,必须继承org.apache.hadoop.mapreduce.Mapper类,并重写类里的map方法。

每个json文件,包含一条Json文本数据。通过map任务,取得文件里的数据,并通过fastjson类,对json文件进行解析,获取json中的字段。

最终使用StringBuilder类,将相关字段以‘\t’分隔拼接成一行,进行输出。

view plain "copy

  1. public static class doMapper extends Mapper<Object, Text, Text, Text> {  
  2.     @Override  
  3.     protected void map(Object key, Text value, Context context)  
  4.             throws IOException, InterruptedException {  
  5.         String initJsonString = value.toString();  
  6.         JSONObject initJson = JSONObject.parseObject(initJsonString );  
  7.         if (!initJsonString.contains("productCommentSummary") && !initJsonString.contains("comments")) {  
  8.             return;  
  9.         }  
  10.   
  11.         JSONObject myjson = initJson.getJSONObject("ten");  
  12.   
  13.         JSONObject productCommentSummary = myjson.getJSONObject("productCommentSummary");  
  14.         String productId       = productCommentSummary.get("productId").toString();  
  15.         String commentCount    = productCommentSummary.get("commentCount").toString();  
  16.         String goodCount       = productCommentSummary.get("goodCount").toString();  
  17.         String generalCount    = productCommentSummary.get("generalCount").toString();  
  18.         String poorCount       = productCommentSummary.get("poorCount").toString();  
  19.         String goodRateShow    = productCommentSummary.get("goodRateShow").toString();  
  20.         String generalRateShow = productCommentSummary.get("generalRateShow").toString();  
  21.         String poorRateShow    = productCommentSummary.get("poorRateShow").toString();  
  22.         /* comments 包括十条评论 */  
  23.         JSONArray comments = myjson.getJSONArray("comments");  
  24.         for (int i = 0; i < comments.size(); i++) {  
  25.             JSONObject comment    = comments.getJSONObject(i);  
  26.             String guid           = comment.getString("guid");  
  27.             String content        = comment.getString("content").replace('\n'' ');  
  28.             String creationTime   = comment.getString("creationTime");  
  29.             String score          = comment.getString("score");  
  30.             String nickname       = comment.getString("nickname");  
  31.             String userLevelName  = comment.getString("userLevelName");  
  32.             String userClientShow = comment.getString("userClientShow");  
  33.             String isMobile       = comment.getString("isMobile");  
  34.             String days           = comment.getString("days");  
  35.             StringBuilder sb = new StringBuilder();  
  36.   
  37.             sb.append(productId);         sb.append("\t");  
  38.             sb.append(commentCount);      sb.append("\t");  
  39.             sb.append(goodCount);         sb.append("\t");  
  40.             sb.append(generalCount);      sb.append("\t");  
  41.             sb.append( poorCount );       sb.append("\t");  
  42.             sb.append( goodRateShow );    sb.append("\t");  
  43.             sb.append( generalRateShow ); sb.append("\t");  
  44.             sb.append( poorRateShow );    sb.append("\t");  
  45.             sb.append( guid );            sb.append("\t");  
  46.             sb.append( content );         sb.append("\t");  
  47.             sb.append( creationTime );    sb.append("\t");  
  48.             sb.append( score );           sb.append("\t");  
  49.             sb.append( nickname );        sb.append("\t");  
  50.             sb.append( userLevelName );   sb.append("\t");  
  51.             sb.append( userClientShow );  sb.append("\t");  
  52.             sb.append( isMobile );        sb.append("\t");  
  53.             sb.append( days );  
  54.             String result = sb.toString();  
  55.             context.write(new Text(result), new Text(""));  
  56.         }  
  57.     }  
  58. }  

6.此外实验代码需要导入的依赖包如下:

view plain "copy

  1. import java.io.IOException;  
  2. import org.apache.hadoop.fs.Path;  
  3. import org.apache.hadoop.io.Text;  
  4. import org.apache.hadoop.mapreduce.Job;  
  5. import org.apache.hadoop.mapreduce.Mapper;  
  6. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  7. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  8. import com.alibaba.fastjson.JSONArray;  
  9. import com.alibaba.fastjson.JSONObject;  

5.执行测试

1.在mapreduce类中,右键,Run As => Run on Hadoop,将任务提交到hadoop中执行

2,等待任务执行完毕。切换目录到/data/edu2/下,并在命令行界面,输入脚本,查看hdfs上/myedu2/out是否有内容输出

view plain "copy

  1. cd /data/edu2/  

view plain "copy

  1. hadoop fs -ls -R /myedu2/out  

若有输出,则将hdfs输出内容,下载到linux本地

view plain "copy

  1. hadoop fs -get /myedu2/out/1/*  

使用vim或cat查看下载到的文件内容,可以看到结构比较清晰

view plain "copy

  1. cat part-r-00000  

3,若未在hdfs上,查看到输出结果,可以通过log日志排错。将/apps/hadoop/etc/hadoop/log4j.properties文件,拷贝到mapreduce项目的根目录下

可以看到在eclipse的console界面有执行过程的输出。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值