基于MapRedue分析用户画像

1、项目描述

  • 用户画像:也叫用户信息标签化。根据用户的信息和行为动作,用一些标签把用户描绘出来,描绘的标签就是用户画像。

  • 这里我们通过手机app对用户的性别和年龄段进行推算,通过对app设置性别和年龄段的相应权重,然后结合用户每天使用app的时长,综合计算app中的性别和年龄段的比重,从而得出app在男女人群和年龄段中的受欢迎程度。

  • appID:用于标记APP,APP的唯一编号,判断终端安装的APP。

  • 年龄段说明:

    名称说明
    年龄段124岁以下
    年龄段225-30岁
    年龄段331-35岁
    年龄段436-40岁
    年龄段540岁以上

2、数据描述

这个有两个数据文件,一个是用户使用app的数据userdata文件,一个是每个app对年龄段和男女设置的权重信息appTabs文件。

  • userdata文件:部分数据如下,数据以’|'为分隔符,其中,第1个字段如:‘NXxY3tn5XsuFcyzEw8qP8g==’表示加密过的手机号;第10个字段表示时间戳;第16个字段表示appID。
NXxY3tn5XsuFcyzEw8qP8g==|1|100.88.255.208|100.88.184.53|2152|2152|204409856|61650535|18320|81244939|CMNET.MNC002.MCC460.GPRS|1471017931598|23|1|33|330400|1|0|10.32.244.101||43785|0|111.20.242.48||80|724|3718|2|tb.himg.baidu.com|/sys/portraitn/item/e5047a6875313233343531322005||bdtb for Android 7.6.2|image/jpeg|||2912|0||||0|0|255|4006|40060044|500-1000|||2055|116.09607|43.93931|290||4||
5ghu6yckW5vTxRGAtMhTFg==|1|100.88.255.71|100.88.188.59|2152|2152|318639104|55579611|18322|102176409|CMNET.MNC002.MCC460.GPRS|1471017996630|153|1|02|020451|8|0|10.232.18.66||55282|0|111.56.32.73||80|1651|14092|2|p2.pstatp.com|/list/s360/9e70005465a6ee3a4e8.webp||okhttp/2.6.0|image/webp|||12384|0||||0|0|255|4002|40020157|3000-4000|||2457|116.08951|43.81833|471||1||
MpzAa6+icSF9HWozeAdLuQ==|1|100.88.255.210|100.88.191.101|2152|2152|131009536|37537304|18320|102115991|CMNET.MNC002.MCC460.GPRS|1471017994558|2225|1|||0|0|10.53.77.48||63518|0|111.56.28.120||8080|1014|614|2|111.56.28.120|/html/servicereq/listredenvelope?callback=angular.callbacks._4&csession=-2111826898&langId=zh&reqparam=%7B%22sresptime%22:%2220160813001330%22%7D&templateId=fullscreenbar||Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D257|application/json;charset=UTF-8|||0|0||||0|0|255|4001|40010003|3000-4000||||116.01994|43.99342|471||4||
  • appTabs文件:各字段含义如下。
AppID App名称 男性权重 女性权重 年龄段1 年龄段2 年龄段3 年龄段4 年龄段5
10004|阿里旺旺|0.001|0.001|0|0.2|0.3|0.2|0.3
10005|微信|0.001|0.001|0|0.2|0.3|0.2|0.3
10006|陌陌|0.001|0.001|0|0.2|0.3|0.2|0.3

3、代码实现

代码流程如下:首先读取userdata文件中的数据,根据appTabs数据的规则,解析数据。这里我们运行了两个Job任务,job2必须等job1执行成功后,才可以执行;接着,我们将解析后的数据写入hbase中。

  • 第一个阶段(job-1):map函数如下:

    public void map(LongWritable key, Text value, Context context)
                throws IOException, InterruptedException {
            String line = value.toString();
            String[] dataArray = line.split(config.Separator);
            String uiqkey = dataArray[Integer.parseInt(config.MDN)]
                    + dataArray[Integer.parseInt(config.appID)]; // MDN + appID
            String[] val = new String[5];
            String timenow = dataArray[Integer.parseInt(config.Date)];
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            val[0] = sdf.format(Long.parseLong(timenow));//时间
            val[1] = dataArray[Integer.parseInt(config.MDN)];// 手机号
            val[2] = dataArray[Integer.parseInt(config.appID)];// appID
            val[3] = "1";// 计数
            val[4] = dataArray[Integer.parseInt(config.ProcedureTime)];// 使用时长
            k.set(uiqkey);
            context.write(k, new TextArrayWritable(val));
     }
    

    reduce函数如下:

    public void reduce(Text key, Iterable<TextArrayWritable> values,
                           Context context) throws IOException, InterruptedException {
            long sum = 0;
            int count = 0;
            String[] res = new String[5];
            boolean flg = true;
            for (TextArrayWritable t : values) {
                String[] vals = t.toStrings();
                if (flg) {
                    res = vals;
                }
                if (vals[3] != null) {
                    count = count + 1;
                }
                if (vals[4] != null) {
                    sum += Long.valueOf(vals[4]);
                }
            }
            res[3] = String.valueOf(count);
            res[4] = String.valueOf(sum);
            StringBuffer sb = new StringBuffer();
            sb.append(res[0]).append("|");// 时间
            sb.append(res[1]).append("|");// 手机号
            sb.append(res[2]).append("|");// appID
            sb.append(res[3]).append("|");// 计数
            sb.append(res[4]);// 使用时长
            v.set(sb.toString());
            context.write(null, v);
     }
    
  • 第二个阶段(job-2):map函数如下:

    public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
              String line = value.toString();
              String[] dataArray = line.split("\\|");
              String newkey = dataArray[1] ; // MDN
              k.set(newkey);
              context.write(k, value);
    }
    

    reduce函数如下:

    Map<String, String[]> appMap = LoadHdfsTable.getAppMap();
    Text v = new Text();
    public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
         Map<String, UserDraw> userDrawMap = new HashMap<>();
         Set<String> keySet = userDrawMap.keySet();
         String keyMDN = null;
         for (Text t : values) {
             String[] dataArray = t.toString().split("\\|");
             keyMDN = dataArray[1]; // 用户MDN
             String appID = dataArray[2]; // APPID
             // 根据appID获取对应的标签信息
             if (appID.length() > 0) { // appID不能为空
                 if (appMap.get(appID) == null) {
                     continue;
                 }
                 String favourite = appMap.get(appID)[2];
                 float male = Float.parseFloat(appMap.get(appID)[1]);
                 float female = Float.parseFloat(appMap.get(appID)[2]);
                 float age1 = Float.parseFloat(appMap.get(appID)[3]);
                 float age2 = Float.parseFloat(appMap.get(appID)[4]);
                 float age3 = Float.parseFloat(appMap.get(appID)[5]);
                 float age4 = Float.parseFloat(appMap.get(appID)[6]);
                 float age5 = Float.parseFloat(appMap.get(appID)[7]);
    
                 long times = Long.parseLong(dataArray[4]);
                 if (userDrawMap.containsKey(keyMDN) == true) {
                     UserDraw userDraw = userDrawMap.get(keyMDN);
                     // 性别权重
                     userDraw.protraitSex(male, female, times);
                     // 年龄段权重
                     userDraw.protraitAge(age1, age2, age3, age4, age5, times);
                 } else {
                     userDrawMap.put(keyMDN, createDrawData(dataArray, favourite, male, female, age1, age2, age3, age4, age5, times));
                 }
             }
         }
         for (String keys : keySet) {
             v.set(userDrawMap.get(keys).toString());
             context.write(null, v);
         }
     }
    
  • 接着,我们将分析的数据写入hbase。

    public static class UserDrawPutInHbaseMap2 extends Mapper<LongWritable, Text, Text, Text> {
        Text k2 = new Text();
        Text v2 = new Text();
        @Override
        protected void map(LongWritable key, Text value, Context context)
                throws IOException, InterruptedException {
            String line = value.toString();
            String[] splited = line.split("\\|");
            k2.set(splited[1]);
            v2.set(line);
            context.write(k2, v2);
        }
    }
    
    public static class UserDrawPutInHbaseReduce2 extends TableReducer<Text, Text, NullWritable> 
        @Override
        protected void reduce(Text k2, Iterable<Text> val,
                              Reducer<Text, Text, NullWritable, Mutation>.Context context)
                throws IOException, InterruptedException {
            for (Text v2 : val) {
                String[] splited = v2.toString().split("\\|");
                //rowkey
                if (k2.toString().length() != 0) {
                    Put put = new Put(Bytes.toBytes(k2.toString()));
                    System.out.println("k2=" + k2.toString());
                    //跳过写入Hlog,提高写入速度
                    put.setDurability(Durability.SKIP_WAL);
                    put.add(Bytes.toBytes("draw"), Bytes.toBytes("mdn"), Bytes.toBytes(splited[1]));
                    put.add(Bytes.toBytes("draw"), Bytes.toBytes("male"), Bytes.toBytes(splited[2]));
                    put.add(Bytes.toBytes("draw"), Bytes.toBytes("female"), Bytes.toBytes(splited[3]));
                    put.add(Bytes.toBytes("draw"), Bytes.toBytes("age1"), Bytes.toBytes(splited[4]));
                    put.add(Bytes.toBytes("draw"), Bytes.toBytes("age2"), Bytes.toBytes(splited[5]));
                    put.add(Bytes.toBytes("draw"), Bytes.toBytes("age3"), Bytes.toBytes(splited[6]));
                    put.add(Bytes.toBytes("draw"), Bytes.toBytes("age4"), Bytes.toBytes(splited[7]));
                    put.add(Bytes.toBytes("draw"), Bytes.toBytes("age5"), Bytes.toBytes(splited[8]));
                    context.write(NullWritable.get(), put);
                }
            }
        }
    }
    
  • 源码和数据
    https://github.com/fengqijie001/userPortrait

    希望可以帮到各位,不当之处,请多指教~?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值