第三周第二题--基于Secondary Sort

思路:基于每个时段内的时长排序,可以理解为,基于key的二次排序,只不过这个key是一个对象,这个对象有两个私有属性,一个是imsi,一个是duration;二次排序就是指,第一次排序imsi,第二次排序duration。


闲话少说,上代码


key类:ImsiAndDuration
  1. public class ImsiAndDuration implements WritableComparable<ImsiAndDuration> {
  2.         
  3.         private String imsi;
  4.         private long duration;

  5.         public void setImsi(String imsi) {
  6.                 this.imsi = imsi;
  7.         }
  8.         public void setDuration(long duration) {
  9.                 this.duration = duration;
  10.         }

  11.         public String getImsi() {
  12.                 return imsi;
  13.         }
  14.         public long getDuration() {
  15.                 return duration;
  16.         }
  17.         
  18.         
  19.         public ImsiAndDuration() {
  20.                 super();
  21.                 this.imsi = "";
  22.                 this.duration = 0;
  23.         }

  24.         public void setImsiAndDuration(String imsi, long duration) {
  25.                 this.imsi = imsi;
  26.                 this.duration = duration;
  27.         }
  28.         
  29.         
  30.         public int compareTo(ImsiAndDuration o) {
  31. //                if(this.imsi != o.imsi)
  32.                         return this.imsi.compareTo(o.imsi);
  33. //                else if(this.duration != o.duration)
  34. //                        return this.duration >= o.duration ?  1: -1;
  35. //                else return 0;
  36.         }

  37.         public void readFields(DataInput in) throws IOException {
  38.                 this.imsi = in.readUTF();
  39.                 this.duration = in.readLong();
  40.         }
  41.         public void write(DataOutput out) throws IOException {
  42.                 
  43.                 out.writeUTF(imsi);
  44.                 out.writeLong(duration);
  45.         }
  46.         @Override
  47.         public int hashCode() {
  48.                 final int prime = 31;
  49.                 int result = 1;
  50.                 result = prime * result + Float.floatToIntBits(duration);
  51.                 result = prime * result + ((imsi == null) ? 0 : imsi.hashCode());
  52.                 return result;
  53.         }
  54.         @Override
  55.         public boolean equals(Object obj) {
  56.                 if (this == obj)
  57.                         return true;
  58.                 if (obj == null)
  59.                         return false;
  60.                 if (getClass() != obj.getClass())
  61.                         return false;
  62.                 ImsiAndDuration other = (ImsiAndDuration) obj;
  63.                 if (Float.floatToIntBits(duration) != Float
  64.                                 .floatToIntBits(other.duration))
  65.                         return false;
  66.                 if (imsi == null) {
  67.                         if (other.imsi != null)
  68.                                 return false;
  69.                 } else if (!imsi.equals(other.imsi))
  70.                         return false;
  71.                 return true;
  72.         }
  73.         @Override
  74.         public String toString() {
  75.                 return "ImsiAndDuration [imsi=" + imsi + ", duration=" + duration + "]";
  76.         }
  77.        
复制代码

LineException :
  1. public class LineException extends Exception{
  2.         private static final long serialVersionUID = 1L;
  3.         int flag;
  4.         public LineException(String msg, int flag) {
  5.                 super(msg);
  6.                 this.flag = flag;
  7.         }
  8.         
  9.         public int getFlag(){
  10.                 return flag;
  11.         }
  12. }
复制代码


TableLineWithImsiAndDuration:
  1. public class TableLineWithImsiAndDuration{
  2.         /**
  3.          * 位置数据格式:
  4.          * IMSI        IMEI        UPDATETYPE LOC TIME
  5.          * UPDATETYPE为 该用户的状态,开机关机或者上传
  6.          * 
  7.          * 上网数据格式:
  8.          * IMSI IMEI        LOC        TIME        URL
  9.          * 
  10.          * 公共字段为IMSI IMEI LOC TIME
  11.          * LOC 即为position
  12.          * 因为time为unix时间,timeflag为time转换为24小时中的时间段
  13.          * 
  14.          */
  15.         private String imsi,position,time;
  16.         protected String timeFlag;
  17.         private Date day;
  18.         private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  19.         
  20.         
  21.         /**
  22.          * 初始化并检查该行的合法性
  23.          * 
  24.          * @param line
  25.          * @param source
  26.          * @param date
  27.          * @param timepoint
  28.          * @throws LineException 
  29.          */
  30.         
  31.         public void set(String line ,boolean source ,String date, String [] timepoint) throws LineException{
  32.                 String [] lineSplit = line.split("\t");                
  33.                 
  34.                 if(source){
  35.                         //POS
  36.                         this.imsi = lineSplit[0];
  37.                         this.position = lineSplit[3];
  38.                         this.time = lineSplit[4];
  39.                 }else{
  40.                         //NET
  41.                         this.imsi = lineSplit[0];
  42.                         this.position = lineSplit[2];
  43.                         this.time = lineSplit[3];
  44.                 }
  45.                 
  46.                 //检查日期的合法性
  47.                 if(!this.time.startsWith(date)){
  48.                         //年月日必须与date一直
  49.                         throw new LineException("", -1);
  50.                 }
  51.                 
  52.                 try {
  53.                         this.day = this.formatter.parse(this.time);
  54.                 } catch (ParseException e) {
  55.                         throw new LineException("", 0);
  56.                 }
  57.                 
  58.                 
  59.                 //计算所属的时间段
  60.                 int i = 0, n = timepoint.length;
  61.                 //yyyy-MM-dd HH:mm:ss截取HH
  62.                 int hour = Integer.valueOf(this.time.split(" ")[1].split(":")[0]);
  63.                 //用户的几个时间段(不一定是3个)小于当前hour的个数
  64.                 while(i < n && Integer.valueOf(timepoint[i]) <= hour)
  65.                         i++;
  66.                 
  67.                 if(i < n){
  68.                         //00-时间段
  69.                         if(i == 0){
  70.                                 this.timeFlag = ("00-"+timepoint[i]);
  71.                         }else{
  72.                                 //timepoint[i-1]时间段
  73.                                 this.timeFlag = (timepoint[i-1] + "-" + timepoint[i]);
  74.                         }
  75.                         
  76.                 }else
  77.                         throw new LineException("", -1);                
  78.         }
  79.         
  80.         
  81.         
  82.         @Override
  83.         public String toString() {
  84.                 return "TableLineWithComparable [imsi=" + imsi + ", position="
  85.                                 + position + ", time=" + time + ", timeFlag=" + timeFlag
  86.                                 + ", day=" + day + ", formatter=" + formatter.toString() + "]";
  87.         }

  88.         public ImsiAndDuration outKey(){
  89.                 long t = (day.getTime() / 1000L );
  90.                 ImsiAndDuration imsiAndDuration = new ImsiAndDuration();
  91.                 imsiAndDuration.setImsiAndDuration(imsi, t);
  92.                 return imsiAndDuration;
  93.         }
  94.         
  95.         public Text outValue(){
  96.                 return new Text(this.position + "\t" + this.timeFlag);
  97.                 
  98.         }
复制代码


BaseStationDataPreprocessFirstThree:
  1. public class BaseStationDataPreprocessFirstThree {

  2.         
  3.         enum Counter{
  4.                 
  5.                 TIMESKPI,                        //时间个数有误
  6.                 OUTOFTIMESKIP,                //时间不在参数指定的时间段内
  7.                 LINESKIP,                        //源文件行有误
  8.                 USERSKIP                        //某个用户有个时间段被整个放弃
  9.         }
  10.         
  11.         
  12.         private static int time = 0;
  13.         
  14.         
  15.         public static class MyMapper extends Mapper<LongWritable, Text, ImsiAndDuration, Text>{
  16.                 
  17.                 String date;
  18.                 String [] timepoint;
  19.                 boolean dataSource;
  20.                 
  21.                 
  22.                 @Override
  23.                 protected void map(LongWritable key, Text value, Context context)
  24.                                 throws IOException, InterruptedException {
  25.                         
  26.                         String line = value.toString();
  27.                         TableLineWithImsiAndDuration tableLine = new TableLineWithImsiAndDuration();
  28.                         
  29.                         try {
  30.                                 tableLine.set(line, this.dataSource, this.date, timepoint);
  31.                         } catch (LineException e) {
  32.                                 if(e.getFlag() == 1){
  33.                                         context.getCounter(Counter.OUTOFTIMESKIP).increment(1);
  34.                                 }else{
  35.                                         context.getCounter(Counter.TIMESKPI).increment(1);
  36.                                 }
  37.                                 return;
  38.                         }catch (Exception e) {
  39.                                 context.getCounter(Counter.LINESKIP).increment(1);
  40.                                 return;
  41.                         }
  42.                         
  43.                         context.write(tableLine.outKey(), tableLine.outValue());        
  44. //                        System.out.println("outKey : " + tableLine.outKey());
  45. //                        System.out.println("outValue : " + tableLine.outValue());
  46.                 }
  47.                 
  48.                 
  49.                 @Override
  50.                 protected void setup(Context context) throws IOException,
  51.                                 InterruptedException {
  52.                         this.date = context.getConfiguration().get("date");
  53.                         this.timepoint = context.getConfiguration().get("timepoint").split("-");
  54.                         
  55.                         //提取文件名
  56.                         FileSplit fileSplit = (FileSplit) context.getInputSplit();
  57.                         String fileName = fileSplit.getPath().getName();
  58.                         if (fileName.startsWith("POS")) {
  59.                                 dataSource = true;
  60.                         }else if (fileName.startsWith("NET")){
  61.                                 dataSource = false;
  62.                         }else {
  63.                                 throw new IOException("File Name should starts with POS or NET");
  64.                         }
  65.                 }
  66.         }
  67.         
  68.         
  69.         public static class MyReducer extends Reducer<ImsiAndDuration, Text, Text, Text>{
  70.                 
  71.                 private String date;
  72.                 private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  73.         
  74.                 @Override
  75.                 protected void reduce(ImsiAndDuration key, Iterable<Text> values,Context context)
  76.                                 throws IOException, InterruptedException {
  77.                         
  78.                         if( 0 == time ){
  79.                                 context.write(new Text("IMSI\t"), new Text("POSITION|TIMEFLAG|DURATION(min)"));
  80.                                 time++;
  81.                         }
  82.                         
  83. //                        System.out.println("ImsiAndDuration:" + key.toString());
  84.                         
  85.                         String imsi = key.getImsi();
  86.                         long duration = key.getDuration();
  87.                         
  88.                         String valueString = null,position = null,timeFlag = null,reduce_position = null,reduce_timeFlag=null;
  89.                         TreeMap<Long, String> uploads = new TreeMap<Long, String>();

  90.                         Iterator<Text> it = values.iterator();
  91.                         while(it.hasNext()){
  92.                                 valueString = it.next().toString();
  93.                                 position = valueString.split("\t")[0];
  94.                                 timeFlag = valueString.split("\t")[1];
  95.                                                                 
  96.                                 try {
  97.                                         uploads.put(duration,position);
  98.                                 } catch (NumberFormatException e) {
  99.                                         context.getCounter(Counter.TIMESKPI).increment(1);
  100.                                         continue;
  101.                                 }
  102.                         }

  103.                         //add the off position
  104.                         try {
  105.                                 
  106.                                 Date tmp = this.formatter.parse(this.date + " " +timeFlag.split("-")[1] + ":00:00" );
  107.                                 uploads.put(tmp.getTime() / 1000L, "OFF");
  108.                                 
  109.                                 HashMap<String, Float> locs = getStayTime(uploads);
  110.                                 
  111.                                 
  112.                                 for (Entry<String, Float> entrySet : locs.entrySet()) {
  113.                                         
  114.                                         reduce_position = entrySet.getKey();
  115.                                         reduce_timeFlag = String.valueOf(entrySet.getValue());
  116.                                         context.write(new Text(imsi), new Text(reduce_position + "|" + timeFlag +"|"+ reduce_timeFlag));
  117.                                         
  118.                                 }
  119.                                                                 
  120.                         } catch (Exception e) {
  121.                                 context.getCounter(Counter.USERSKIP).increment(1);
  122.                                 return;
  123.                         }                        
  124.                 }
  125.                 
  126.                 //location time
  127.                 private HashMap<String, Float> getStayTime(TreeMap<Long, String> uploads) {
  128.                         Entry<Long,String> upload ,nextUpload;
  129.                         HashMap<String, Float> locs = new HashMap<String, Float>();
  130.                         
  131.                         
  132.                         
  133.                         Iterator<Entry<Long, String>> it = uploads.entrySet().iterator();
  134.                         upload = it.next();
  135.                         while(it.hasNext()){
  136.                                 nextUpload = it.next();
  137.                                 float diff = (float)(nextUpload.getKey() - upload.getKey()) / 60.0f;
  138.                                 
  139.                                 if(diff <= 60.0){
  140.                                         if(locs.containsKey(upload.getValue())){
  141.                                                 locs.put(upload.getValue(), locs.get(upload.getValue()) + diff);
  142.                                         }else{
  143.                                                 locs.put(upload.getValue(), diff);
  144.                                         }
  145.                                 }
  146.                                 upload = nextUpload;
  147.                         }
  148.                         
  149.                         return locs;
  150.                 }
  151.                 
  152.                 @Override
  153.                 protected void setup(Context context)
  154.                                 throws IOException, InterruptedException {
  155.                         
  156.                         this.date = context.getConfiguration().get("date");

  157.                 }
  158.         }
  159.         
  160.         
  161.         
  162.         public static class firstThreePartitioner extends Partitioner<ImsiAndDuration, Text>{

  163.                 @Override
  164.                 public int getPartition(ImsiAndDuration key, Text value, int numReducers) {
  165.                         //imsi
  166.                         return (key.getImsi().hashCode() & Integer.MAX_VALUE) % numReducers;
  167.                 }
  168.         }
  169.         
  170.         //每个分区内又调用job.setSortComparatorClass或者key的比较函数进行排序,以duration进行排序
  171.         public static class firstThreeKeySortComparator extends WritableComparator{

  172.                 protected firstThreeKeySortComparator() {
  173.                         super(ImsiAndDuration.class,true);
  174.                 }

  175.                 @SuppressWarnings("rawtypes")
  176.                 @Override
  177.                 public int compare(WritableComparable a, WritableComparable b) {
  178.                         
  179.                         ImsiAndDuration imsi1 = (ImsiAndDuration)a;
  180.                         ImsiAndDuration imsi2 = (ImsiAndDuration)b;        
  181.                         
  182.                         int cmp = imsi1.compareTo(imsi2);
  183.                         if(cmp != 0)
  184.                                 return cmp;
  185.                         return imsi1.getDuration() != imsi2.getDuration() ?  imsi1.getDuration() > imsi2.getDuration() ? 1: -1 : 0;
  186.                         
  187.                 }
  188.                 
  189.                 @Override
  190.                 public int compare(byte[] b1, int s1, int l1, byte[] b2,
  191.                                 int s2, int l2) {
  192.                         return WritableComparator.compareBytes(b1, s1, l1, b2, s2, l2);
  193.                 }
  194.         }
  195.                 
  196.         @SuppressWarnings("rawtypes")
  197.         //相同key的value在一起,以imsi 分组
  198.         public static class firstThreeGroupingComparator extends WritableComparator{

  199.                 public firstThreeGroupingComparator() {
  200.                         super(ImsiAndDuration.class,true);
  201.                 }
  202.                 
  203.                 
  204.                 @Override
  205.                 public int compare(WritableComparable a, WritableComparable b) {
  206.                         ImsiAndDuration imsi1 = (ImsiAndDuration)a;
  207.                         ImsiAndDuration imsi2 = (ImsiAndDuration)b;
  208.                         return imsi1.compareTo(imsi2);
  209.                 }                
  210.                 
  211.                 @Override
  212.                 public int compare(byte[] b1, int s1, int l1, byte[] b2,
  213.                                 int s2, int l2) {
  214.                         return WritableComparator.compareBytes(b1, s1, l1, b2, s2, l2);
  215.                 }
  216.         }
  217.         
  218.         
  219.         public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
  220.                 
  221.                 Configuration conf = new Configuration();
  222.                 
  223.                 conf.set("date", "2013-09-12");
  224.                 conf.set("timepoint", "09-17-24");
  225.                 
  226.                 conf.set("mapred.job.tracker", "192.168.126.3:9001");
  227.                 conf.addResource("classpath:/hadoop/core-site.xml");
  228.                 conf.addResource("classpath:/hadoop/hdfs-site.xml");
  229.                 conf.addResource("classpath:/hadoop/mapred-site.xml");
  230.                 conf.addResource("classpath:/hadoop/master");
  231.                 conf.addResource("classpath:/hadoop/slave");
  232.                 
  233.                 Path inPath = new Path("/input/1217");
  234.                 Path outPath = new Path("/output/1217/BaseStation3");
  235.                 
  236.                 Job job = new Job(conf, "BaseStation3");
  237.                 
  238.                 FileInputFormat.addInputPath(job, inPath);
  239.                 FileOutputFormat.setOutputPath(job, outPath);
  240.                 
  241.                 job.setJarByClass(BaseStationDataPreprocess.class);
  242.                 job.setMapperClass(MyMapper.class);
  243.                 job.setReducerClass(MyReducer.class);
  244.                 job.setPartitionerClass(firstThreePartitioner.class);
  245.                 job.setGroupingComparatorClass(firstThreeGroupingComparator.class);
  246.                 job.setSortComparatorClass(firstThreeKeySortComparator.class);
  247.                 
  248.                 
  249.                 job.setMapOutputKeyClass(ImsiAndDuration.class);
  250.                 job.setMapOutputValueClass(Text.class);
  251.                 
  252.                 job.setOutputKeyClass(Text.class);
  253.                 job.setOutputValueClass(Text.class);
  254.                 
  255.                 System.exit(job.waitForCompletion(true)? 0 : 1);
  256.                 
  257.                 
  258.         }
  259.         
  260.         
  261.         
  262. }
复制代码

因为之前,跑了100000个imsi,vm跑挂了,所以这次数据量小一点。
运行数据量100个imsi,两个数据文件加起来2M左右
生成结果:
 

因为这个程序是验证二次排序的效果,没有取前3.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值