JSON学习笔记-MR-phone_mapper

源码:

(源码来自网络)

package testDemo;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

/**
 * @Auther: lp
 * @Date: 2018/10/16 16:04
 * @Description:
 */

public class Phone_Map extends Mapper<LongWritable,Text,Text,NullWritable> {

    Text text = new Text();

    @Override
    protected void map(LongWritable key, Text value, Context context) {

        // 数据预处理
        String rawValue = PreProcessData(value.toString());

        try{

            // 解析JSON格式数据,从数据中获取需要的字段
            // 提取手机品牌名称
            String phoneBrand =  GetStringByName(rawValue, "phone_brand");

            // 提取手机屏幕尺寸
            String phoneSize = GetPhoneSize(rawValue);

            // 提取用户购买手机颜色

            String buyColor = GetPhoneColor(rawValue);

            System.out.println(buyColor);
            // 检查获取的数据,若为空,则认为是无效数据
            String[] params = {phoneBrand, phoneSize, buyColor};
            if(CheckData(params)){
                String outputData = GenerateOutputData(phoneBrand, buyColor, phoneSize);

                text.set(outputData);
                //System.out.println(text);
                context.write(text,NullWritable.get());
            }

        } catch (Exception e) {
            return;
        }
    }

    /**
     * 清洗特殊字符|和\r,清洗规则如下:
     * 1. 将|替换为-
     * 2. 将换行符删除
     * @param value
     * @return 处理完成的数据
     */
    private String PreProcessData(String value){

        String retValue = value;

        // 将|替换为-
        retValue = value.toString().replace('|', '-');

        // 将换行符删除
        retValue = retValue.toString().replaceAll("\\r\\t", "");

        return retValue;
    }

    /**
     * 解析JSON格式数据,根据数如参数从JSON中提取目标字符串
     * @param rawJson 原始JSON格式字符串
     * @param keysName 目标数据key名称
     * @return 提取到的字符串
     */
    private String GetStringByName(String rawJson, String keysName){

        JSONObject object = JSONObject.parseObject(rawJson);
        if(object.containsKey(keysName)){
            return object.getString(keysName).trim();
        }
        else{
            return "";
        }
    }

    /**
     * 获取手机屏幕尺寸数据
     * @param rawJson
     * @return 手机屏幕尺寸数据
     */
    private String GetPhoneSize(String rawJson){

        // 获取parameter参数数据
        String parameter = GetStringByName(rawJson, "parameter");

        // 解析为数组
        JSONArray arrParam = JSONArray.parseArray(parameter);

        String keyName = "主屏幕尺寸(英寸)";

        // 遍历数组,寻找目标数据
        for(int iIndex = 0; iIndex < arrParam.size(); iIndex++){
            String rawValue = GetStringByName(arrParam.get(iIndex).toString(), keyName);
            if("" == rawValue.trim()){
                continue;
            }
            else{
              return rawValue;
            }
        }

        return "";
    }
    /**
     *
     * @param rawValue
     * @return String
     */
    private String GetPhoneColor(String rawValue){

        String jsonComments = GetStringByName(rawValue, "comments");
        String buyColor = GetStringByName(jsonComments, "buy_color");

        // System.out.println(jsonComments);
        String[] arrColor = new String[]{"红","黑","白","金","蓝","黄","紫","绿","粉","银","灰","青"};
        int iIndex = 0;
        for ( ; iIndex < arrColor.length; iIndex++){
            if (buyColor.contains(arrColor[iIndex])){
                buyColor = arrColor[iIndex];
                break;
            }
        }
        if(arrColor.length == iIndex) {
            buyColor = "其他";
        }
        return buyColor;
    }

    /**
     * 检查获取到的数据是否存在空字符串
     * @param paramArr
     * @return 手机屏幕尺寸数据
     */
    private boolean CheckData(String[] paramArr){
        for(int iIndex = 0; iIndex < paramArr.length; iIndex++){
            if("" == paramArr[iIndex].trim()){
                return false;
            }
        }

        return true;
    }

    /**
     * 将数据按照要求的格式组装
     * @param phoneBrand
     * @param buyColor
     * @param phoneSize
     * @return 组装好的输出数据
     */
    private String GenerateOutputData(String phoneBrand,String buyColor,String phoneSize){
        return String.format("%s|%s|%s", phoneBrand, buyColor, phoneSize);
    }
}

分析笔记:

1.private String PreProcessData(String value)

对读取的数据进行预处理;
主要功能为将字符’|‘替换为’-’,将换行符删除;
函数参数为String类型的kv对中的value值;

首先先用一个String类型的retValue接受传进来的值value;
再通过replace()函数将’|‘替换成’-’,返回值传给retValue;
利用replaceAll()函数将特殊字符串’\r\t’删掉;//经证明,replace()函数也可以实现该效果
最后将处理好的retValue作为函数的返回值;

2.private String GetStringByName(String rawJson, String keysName)

通过kv对的key获取value,并将结果返回;
函数参数为String类型的JSON内容的字符串和String类型的key内容的字符串;

首先用把String类型的rawJson通过一个JSONObject类型的变量object接收一下;//方便进行json类型的操作
再利用containsKey()函数判断key的内容是否为存在,如果存在,就返回相应的value值;
如果不存在就返回空字符串;

3.private String GetPhoneSize(String rawJson)

获取其中一个key对应的数据;
函数的参数是String类型的JSON内容的字符串rawJson;

创建一个String类型的变量parameter,其值为key为parameter的kv对的value;
再创建一个JSONArray类型的变量arrParam,用来存储获取的parameter值;//JSONArray结果格式类似Python的列表
定义我们要寻找的kv对的key,并给他一个变量名为keyName;
对JSONArray进行循环,查看keyName对应的value是否为空,若不为空则返回该值,否则返回空字符串;

4.private String GetPhoneColor(String rawValue)

获取其中另外一个key对应的数据;理论上可以和上一个函数写成差不多的逻辑,但是这个函数有点意思;
函数参数为String类型的rawValue;

首先创建一个String类型的jsonComments变量用来存储key为comments的kv对的value;
创建一个String类型的buyColor变量存储key为buy_color的kv对的value;
然后定义了一个arrColor字符串数组,用来存放所有指定的值,也就是说你获得值只能从这里边选,不会出现无效值,若出现无效值,也是可控的无效值;
对arrColor数组进行循环,对buycolor和给定的颜色数组进行比对与赋值;
如果没有可以匹配的颜色就赋值为‘其他’;
将buyColor进行返回;

(这真的是这个类里边我最喜欢的函数!真的逻辑太妙了!星星眼)

5.private boolean CheckData(String[] paramArr)

检查数据;主要是判空;
参数为名为paramArr的String数组;//参考前边的函数及变量的命名方式,这应该是尺寸的那个数组;

对数据数组进行循环,如果值是空的就返回false,如果不是空的就返回true;

6.private String GenerateOutputData(String phoneBrand,String buyColor,String phoneSize)

按照要求格式整理字符串;
参数是String类型的phoneBrand,String类型的buyColor,String类型的phoneSize;
直接利用String.format()函数对字符串格式化,并返回;

7.protected void map(LongWritable key, Text value, Context context)

最后就是这个map;为啥最后再说它呢,因为它主要是调用了各种上述函数;
函数的参数有LongWritable类型的key,Text类型的value,Context类型的context;这个应该是继承Mapper类之后必须要重写的方法;

首先我们定义了一个String类型的rawValue,用来接收预处理后的value数据;
用String类型的phoneBrand变量接收key为phone_brand的value值;//此时的value值已经通过用户自定义函数GetStringByName()变成了String类型
用String类型的phoneSize变量接收执行了用户自定义函数GetPhoneSize()后的结果;
用String类型的buyColor变量接收执行了用户自定义函数GetPhoneColor()后的结果;
在控制台输出了buyColor这个变量;//个人感觉这个应该是测试数据吧hhhh
定义了一个String类型的数组params,其内容是前边我们获取的phoneBrand,phoneSize,buyColor;
对该数组进行判空,如果非空,就用用户自定义函数GenerateOutputData()对数据进行整合,整合为指定格式,再利用context.write()函数返回最后的数据;

最后

  1. 注意:每行数据都会进行一次map,所以如果想把上述函数具体化的话,可以想象只有一行数据,对该行数据进行处理;
  2. 温馨提示:本人也是小白菜,分析仅供参考,如有错误请指出!谢谢!!
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值