package mobvista.dmp.datasource.gender; import com.google.common.collect.Sets; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.io.compress.GzipCodec; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import org.apache.hadoop.util.GenericOptionsParser; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.type.JavaType; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; public class ExtractDeviceMRV2 { /** * author:liushuai * * @throws InterruptedException * @throws IOException * @throws ClassNotFoundException desc : 对dm_install_list每天的数据根据device_id进行去重并合并package_name */ public static void main(String[] args) throws ClassNotFoundException, IOException, InterruptedException { Configuration conf = new Configuration(); conf.set("mapreduce.map.speculative", "true"); conf.set("mapreduce.reduce.speculative", "true"); conf.set("mapreduce.task.io.sort.mb", "500"); conf.set("mapreduce.reduce.java.opts", "-Xmx1536m"); conf.set("mapreduce.reduce.memory.mb", "2048"); conf.set("mapreduce.reduce.shuffle.parallelcopies", "50"); String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs(); Job job = Job.getInstance(conf, "ExtractDeviceMR"); FileOutputFormat.setCompressOutput(job, true); FileOutputFormat.setOutputCompressorClass(job, GzipCodec.class); job.setJarByClass(ExtractDeviceMRV2.class); job.setMapperClass(ExtractMapper.class); job.setReducerClass(ExtractReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(Text.class); FileInputFormat.addInputPath(job, new Path(otherArgs[0])); FileOutputFormat.setOutputPath(job, new Path(otherArgs[1])); System.exit(job.waitForCompletion(true) ? 0 : 1); } public static class ExtractMapper extends Mapper<LongWritable, Text, Text, Text> { ObjectMapper objectMapper = new ObjectMapper(); JavaType javaType = objectMapper.getTypeFactory() .constructCollectionType(ArrayList.class, ExtractDeviceMould.class); Text outKey = new Text(); Text outValue = new Text(); String time = ""; public void setup(Context context) { try { time = context.getConfiguration().get("time"); } catch (Exception e) { System.exit(3); } } public void map(LongWritable key, Text value, Context context) { try { String line = value.toString(); String[] fields = MRUtils.SPLITTER.split(line, -1); if (fields.length != 4) { return; } if (fields[3].equals("")) { //package return; } String deviceId = fields[0]; String[] tmpDeviceId = deviceId.split("-", -1); StringBuilder tmpDeviceId2 = new StringBuilder(); for (String add : tmpDeviceId) { tmpDeviceId2.append(add); } if (tmpDeviceId.length == 1) { return; } if (tmpDeviceId2.toString().matches("^0*$")) { return; } if (deviceId.equals("")) { return; } StringBuilder outputValue = new StringBuilder(); //使用jackson解析json数组 List<ExtractDeviceMould> packageList = objectMapper.readValue(fields[3], javaType);//[{"date":"2017-03-30","package_name":"com.myntra.android"}] if (packageList.size() == 0) {//说明没有package_name,扔掉 return; } //在90天之内有过安装行为的数据保留,否则不保留 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String day = time; Date today = null; try { today = sdf.parse(day); } catch (ParseException e) { e.printStackTrace(); } Calendar theCa = Calendar.getInstance(); theCa.setTime(today); theCa.add(theCa.DATE, -90);//90天前 Date begin = theCa.getTime();//90天前 int num = 0; for (ExtractDeviceMould deviceMould : packageList) { if (deviceMould.getPackage_name().length() == 0 || deviceMould.getDate().length() == 0) { continue; } try { Date install = sdf.parse(deviceMould.getDate());//pkg安装的时间 if (install.getTime() >= begin.getTime()) { num = 1; break; } } catch (ParseException e) { continue; } } if (num == 0) { return; } String updateDate = ""; SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); for (ExtractDeviceMould deviceMould : packageList) { if (!StringUtils.isNotBlank(updateDate) && StringUtils.isNotBlank(deviceMould.getDate())) { updateDate = deviceMould.getDate(); } else { try { // 获取最近的活跃日期 if (format.parse(deviceMould.getDate()).after(format.parse(updateDate))) { updateDate = deviceMould.getDate(); } } catch (ParseException e) { } } outputValue.append("#" + deviceMould.getPackage_name());//循环把package_name加到后面 } if (outputValue.toString().equals("") || outputValue.toString().length() <= 1) { return; } outKey.set(MRUtils.JOINER.join(fields[0], fields[1]));//device_id, device_type outValue.set(mobvista.dmp.util.MRUtils.JOINER.join(outputValue.toString().substring(1), updateDate)); // pkg_name, updateDate context.write(outKey, outValue); } catch (Exception e) { return; } } } public static class ExtractReducer extends Reducer<Text, Text, Text, Text> { Text outKey = new Text(); Text outValue = new Text(); public void reduce(Text key, Iterable<Text> values, Context context) { try { String deviceId = MRUtils.SPLITTER.split(key.toString(), -1)[0]; String deviceType = MRUtils.SPLITTER.split(key.toString(), -1)[1]; StringBuilder packageName = new StringBuilder(""); Set<String> set = Sets.newHashSet(); String updateDate = ""; SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); for (Text value : values) { String[] arr = MRUtils.SPLITTER.split(value.toString(), -1); String[] array = arr[0].split("#", -1);//以#分隔的pkg for (String pkgName : array) { if (pkgName.equals("") || pkgName.length() < 1) { continue; } set.add(pkgName); } // 设备的最新活跃时间 if (!StringUtils.isNotBlank(updateDate) && StringUtils.isNotBlank(arr[1])) { updateDate = arr[1]; } else { try { if (format.parse(arr[1]).after(format.parse(updateDate))) { updateDate = arr[1]; } } catch (ParseException e) { } } } if (set.size() < 2) { return; } for (String pkg : set) { if (packageName.toString().equals("")) { packageName.append(pkg); } else { packageName.append("#" + pkg); } } outKey.set(deviceId); outValue.set(MRUtils.JOINER.join("B", packageName.toString(), deviceType, updateDate)); context.write(outKey, outValue); } catch (Exception e) { return; } } } }