大資料實戰:使用者流量分析系統

來源:互聯網
上載者:User

標籤:

本文是結合hadoop中的mapreduce來對使用者資料進行分析,統計使用者的手機號碼、上行流量、下行流量、總流量的資訊,同時可以按照總流量大小對使用者進行分組排序等。是一個非常簡潔易用的hadoop項目,主要使用者進一步加強對MapReduce的理解及實際應用。文末提供來源資料採集檔案和系統源碼。

本案例非常適合hadoop初級人員學習以及想入門大資料、雲端運算、資料分析等領域的朋友進行學習。

一、待分析的資料來源

以下是一個待分析的文字檔,裡面有非常多的使用者瀏覽資訊,保擴使用者手機號碼,上網時間,機器序號,訪問的IP,訪問的網站,上行流量,下行流量,總流量等資訊。這裡只截取一小段,具體檔案在文末提供下載連結。


二、準系統實現想要統計出使用者的上行流量、下行流量、總流量資訊,我們需要建立一個bean類來對資料進行封裝。於是建立應該Java工程,導包,或者直接建立一個MapReduce工程。在這裡面建立一個FlowBean.java檔案。
        private long upFlow;private long dFlow;private long sumFlow;
然後就是各種右鍵產生get,set方法,還要toString(),以及產生建構函式,(千萬記得要產生一個空的建構函式,不然後面進行分析的時候會報錯)。完整代碼如下:
package cn.tf.flow;import java.io.DataInput;import java.io.DataOutput;import java.io.IOException;import org.apache.hadoop.io.Writable;import org.apache.hadoop.io.WritableComparable;public class FlowBean  implements WritableComparable<FlowBean>{private long upFlow;private long dFlow;private long sumFlow;public long getUpFlow() {return upFlow;}public void setUpFlow(long upFlow) {this.upFlow = upFlow;}public long getdFlow() {return dFlow;}public void setdFlow(long dFlow) {this.dFlow = dFlow;}public long getSumFlow() {return sumFlow;}public void setSumFlow(long sumFlow) {this.sumFlow = sumFlow;}public FlowBean(long upFlow, long dFlow) {super();this.upFlow = upFlow;this.dFlow = dFlow;this.sumFlow = upFlow+dFlow;}@Overridepublic void readFields(DataInput in) throws IOException {upFlow=in.readLong();dFlow=in.readLong();sumFlow=in.readLong();}@Overridepublic void write(DataOutput out) throws IOException {out.writeLong(upFlow);out.writeLong(dFlow);out.writeLong(sumFlow);}public FlowBean() {super();}@Overridepublic String toString() { return  upFlow + "\t" + dFlow + "\t" + sumFlow;}@Overridepublic int compareTo(FlowBean o) {return this.sumFlow>o.getSumFlow() ? -1:1;}}

然後就是這個統計的代碼了,建立一個FlowCount.java.在這個類裡面,我直接把Mapper和Reduce寫在同一個類裡面了,如果按規範的要求應該是要分開寫的。在mapper中,擷取後面三段資料的值,所以我的這裡length-2,length-3.
       public static class FlowCountMapper extends Mapper<LongWritable, Text, Text, FlowBean> {@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {// 拿到這行的內容轉成stringString line = value.toString();String[] fields = StringUtils.split(line, "\t");try {if (fields.length > 3) {// 獲得手機號及上下行流量欄位值String phone = fields[1];long upFlow = Long.parseLong(fields[fields.length - 3]);long dFlow = Long.parseLong(fields[fields.length - 2]);// 輸出這一行的處理結果,key為手機號,value為流量資訊beancontext.write(new Text(phone), new FlowBean(upFlow, dFlow));} else {return;}} catch (Exception e) {}}}

在reduce中隊資料進行整理,統計
public static class FlowCountReducer extends Reducer<Text, FlowBean, Text, FlowBean> {@Overrideprotected void reduce(Text key, Iterable<FlowBean> values, Context context) throws IOException, InterruptedException {long upSum = 0;long dSum = 0;for (FlowBean bean : values) {upSum += bean.getUpFlow();dSum += bean.getdFlow();}FlowBean resultBean = new FlowBean(upSum, dSum);context.write(key, resultBean);}}


最後在main方法中調用執行。
public static void main(String[] args) throws Exception {Configuration conf = new Configuration();Job job = Job.getInstance(conf);job.setJarByClass(FlowCount.class);job.setMapperClass(FlowCountMapper.class);job.setReducerClass(FlowCountReducer.class);job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(FlowBean.class);job.setOutputKeyClass(Text.class);job.setOutputValueClass(FlowBean.class);FileInputFormat.setInputPaths(job, new Path(args[0]));FileOutputFormat.setOutputPath(job, new Path(args[1]));boolean res = job.waitForCompletion(true);System.exit(res ? 0 : 1);}
當然啦,還需要先在你的hdfs根目錄中建立/flow/data資料,然後我那個使用者的資料來源上傳上去。
 bin/hadoop fs -mkdir -p /flow/data bin/hadoop fs -put HTTP_20130313143750.dat /flow/data bin/hadoop jar  ../lx/flow.jar

把上面這個MapReduce工程打包成一個jar檔案,然後用hadoop來執行這個jar檔案。例如我放在~/hadoop/lx/flow.jar,然後再hadoop安裝目錄中執行
bin/hadoop jar ../lx/flowsort.jar cn/tf/flow/FlowCount  /flow/data  /flow/output

最後執行結果如下:


在這整過過程中,我們是有yarnchild的進程在執行的,如所示:當整個過程執行完畢之後yarnchild也會自動結束。
三、按總流量從大到小排序

如果你上面這個基本操作以及完成了的話,按總流量排序就非常簡單了。我們建立一個FlowCountSort.java.

全部代碼如下:

package cn.tf.flow;import java.io.IOException;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.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;public class FlowCountSort {public static class FlowCountSortMapper extends Mapper<LongWritable, Text, FlowBean, Text>{@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {String line=value.toString();String[] fields=StringUtils.split(line,"\t");String phone=fields[0];long upSum=Long.parseLong(fields[1]);long dSum=Long.parseLong(fields[2]);FlowBean sumBean=new FlowBean(upSum,dSum);context.write(sumBean, new Text(phone));}}public static class FlowCountSortReducer extends Reducer<FlowBean, Text, Text, FlowBean>{//進來的“一組”資料就是一個手機的流量bean和手機號@Overrideprotected void reduce(FlowBean key, Iterable<Text> values, Context context) throws IOException, InterruptedException {context.write(values.iterator().next(), key);}}public static void main(String[] args) throws Exception {Configuration conf = new Configuration();Job job = Job.getInstance(conf);job.setJarByClass(FlowCountSort.class);job.setMapperClass(FlowCountSortMapper.class);job.setReducerClass(FlowCountSortReducer.class);job.setMapOutputKeyClass(FlowBean.class);job.setMapOutputValueClass(Text.class);job.setOutputKeyClass(Text.class);job.setOutputValueClass(FlowBean.class);FileInputFormat.setInputPaths(job, new Path(args[0]));FileOutputFormat.setOutputPath(job, new Path(args[1]));boolean res = job.waitForCompletion(true);System.exit(res ? 0 : 1);}}

這個主要就是使用了FlowBean.java中的代碼來實現的,主要是繼承了WritableComparable<FlowBean>介面來實現,然後重寫了compareTo()方法。

@Overridepublic int compareTo(FlowBean o) {return this.sumFlow>o.getSumFlow() ? -1:1;}
按照同樣的方法對這個檔案打成jar包,然後使用hadoop的相關語句進行執行就可以了。

bin/hadoop jar ../lx/flowsort.jar cn/tf/flow/FlowCountSort  /flow/output  /flow/sortoutput
結果圖:




四、按使用者號碼地區進行分類

流量匯總之後的結果需要按照省份輸出到不同的結果檔案中,需要解決兩個問題:

 1、如何讓mr的最終結果產生多個檔案: 原理:MR中的結果檔案數量由reduce
  task的數量絕對,是一一對應的 做法:在代碼中指定reduce task的數量
 
 
  2、如何讓手機號進入正確的檔案 原理:讓不同手機號資料發給正確的reduce task,就進入了正確的結果檔案
  要自訂MR中的分區partition的機制(預設的機制是按照kv中k的hashcode%reducetask數)
  做法:自訂一個類來幹預MR的分區策略——Partitioner的自訂實作類別

主要代碼與前面的排序是非常類似的,只要在main方法中添加如下兩行代碼就可以了。

          //指定自訂的partitionerjob.setPartitionerClass(ProvincePartioner.class);job.setNumReduceTasks(5);

這裡我們需要建立一個ProvincePartioner.java來處理號碼分類的邏輯。

public class ProvincePartioner extends Partitioner<Text, FlowBean>{private static HashMap<String, Integer> provinceMap = new HashMap<String, Integer>();static {provinceMap.put("135", 0);provinceMap.put("136", 1);provinceMap.put("137", 2);provinceMap.put("138", 3);}@Overridepublic int getPartition(Text key, FlowBean value, int numPartitions) {String prefix = key.toString().substring(0, 3);Integer partNum = provinceMap.get(prefix);if(partNum == null) partNum=4;return partNum;}}

執行方法和前面也是一樣的。從執行的流程中我們可以看到這裡啟動了5個reduce task,因為我這裡資料量比較小,所以只啟動了一個map task。



到這裡,整個使用者流量分析系統就全部結束了。關於大資料的更多內容,歡迎關注。點擊左上方頭像下方“點擊關注".感謝您的支援!



資料來源:http://download.csdn.net/detail/sdksdk0/9545935

源碼項目地址:https://github.com/sdksdk0/HDFS_MapReduce




大資料實戰:使用者流量分析系統

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.