文章目录

  • 绪论
  • 1、PageView和UserView
  •  1.1、PageView(PV)
  •  1.2、UserView(UV)
  •  1.3、PV+UV
  • 2、生成数据
  • 3、代码


绪论

  学大数据的初衷就是在海量的数据中挑选出我们需要的有价值的数据。今天这个例子就是模仿这个场景。海量数据下如何筛选并计算出我们需要的数据???

  前提:500w条记录环境下(可以更多,视计算机性能而定),统计每天最热门的top3板块。

1、PageView和UserView

  我们要统计的是最热门的top3板块,而热门如果只是简单地通过页面浏览量(PV)或者用户浏览量(UV)来决定都显得比较片面,这里我们综合这两者(0.3PV+0.7UV)来获取我们的需求。

  PageView:浏览量。(有几次浏览就算几次)

  

spark 歷史日志前綴eventlog_v2 spark运行日志_Spark

  UserView:用户量。(同一个用户同一天浏览一个模块多次,只能算一次)

  

spark 歷史日志前綴eventlog_v2 spark运行日志_spark_02

  通过上面的分析已经解释了PV和UV的含义,以及获取这两个值的具体操作思路。下面探讨一下,如何在这两个值的基础上,求出每天最热门的top3板块。


  按照前面的操作已经获得了两个RDD,PVRDD、UVRDD。在这两个RDD上使用join连接,在join算子里面通过(0.3PV+0.7UV)可以获得每天的各个模块的一个热度值。将这个值排序。取前三名,就是我们要求的每天最热top3板块了。

  

spark 歷史日志前綴eventlog_v2 spark运行日志_Spark_03

2、生成数据

  由于没有获取大量数据的条件,这里我们通过代码自己制造一部分数据来进行相关操作。我模仿的数据结构是:UUID  用户id  时间戳  页面id   模块名(中间用\t制表符分隔)

  生成代码如下(请更换自己的包名):

package com.hpe.data;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.UUID;

/**
 * seesionId  userid time pageId channelId
 * @author eversec
 */


public class MakeLogData {
	public static void main(String[] args) throws Exception {
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:/logdata")));
		Random random = new Random();
		int logNUm = 5000000;
		StringBuilder stringBuilder = new StringBuilder();
		List<String> channelList = Arrays.asList("spark","hdfs","mr","yarn","hive","scala","python");
		 
		for (int i = 0; i < logNUm; i++) {
			String sessionId = UUID.randomUUID().toString();
			int userId = random.nextInt(10000);
			int year = 2018;
			int month = random.nextInt(12) + 1;
			int day = random.nextInt(30) + 1;
			int hour = random.nextInt(24);
			int minute = random.nextInt(60);
			int second = random.nextInt(60);
			String dateTime = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
			SimpleDateFormat form = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");	
			long time = form.parse(dateTime).getTime();
			int pageId = random.nextInt(100);
			String channel = channelList.get(i % channelList.size() );
			stringBuilder.append(sessionId + "\t" + userId + "\t" + time + "\t" + pageId + "\t" + channel + "\n");
			bw.write(stringBuilder.toString());
			stringBuilder.delete(0, stringBuilder.length());
		}
		
		bw.flush();
		bw.close();
	}
}

3、代码

package com.hpe.spark.loganalyse

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import java.util.Date
import java.text.SimpleDateFormat
import org.apache.spark.rdd.RDD.rddToPairRDDFunctions
import org.apache.spark.rdd.RDD

object PVAndUV {
  def main(args: Array[String]): Unit = {
    //配置信息
    val conf = new SparkConf();
    conf.setAppName("UV + PV")
    conf.setMaster("local")
    val sc = new SparkContext(conf)
    
    //加载数据
    val rdd = sc.textFile("d:/data/logdata")
    
    
    //调用方法
     val rdd2 = first(rdd)
     
     //rdd2.saveAsTextFile("d:/data/Log2")
     
     sc.stop()
  }
  
  //封装方法
  def first(rdd:RDD[String]) = {
    
    
    //切割字符串
    val splitRDD = rdd.map { _.split("\t") }
    
    //过滤,去除脏数据
    val filterRDD = splitRDD.filter { _.length == 5 }
   
    //PV model
    val reduceRDD = pv(filterRDD)
   
    //UV model
    val reduceRDD2 = uv(filterRDD)

    //jion 合并两个RDD
    val unionRDD = reduceRDD.join(reduceRDD2)
    
    //返回  时间_模块
    //(时间_模块,(a,b))
    val endRDD = unionRDD
      .map(x =>{
        val value = x._2._1 *0.3 + x._2._2 *0.7
        (x._1,value)
      })
      .sortBy(_._2,false)
      .map(x =>{
        val day = x._1.split("_")(0)
        val model = x._1.split("_")(1)
        (day,model)
      })
      .groupByKey()
      .map(x => {
        val list = x._2.take(3)
        (x._1,list)
      }).foreach { println }
    
    
    endRDD
  }
  
  //pv操作
  def pv(filterRDD:RDD[Array[String]]) = {
    val mapRDD = filterRDD.map { x => {
      val time = x(2).toLong
      val date = new Date(time)
      val format = new SimpleDateFormat("yyyy-MM-dd")
      val dateStr = format.format(date)
      x(2) = dateStr
      //返回  时间_模块
      (x(2) + "_" + x(4),1)
    } }
   
    val reduceRDD=mapRDD.reduceByKey(_+_)
    reduceRDD
  }
  
  //uv操作
  def uv(filterRDD:RDD[Array[String]]) = {
    val mapRDD2 = filterRDD.map { x => {
      val time = x(2).toLong
      val date = new Date(time)
      val format = new SimpleDateFormat("yyyy-MM-dd")
      val dateStr = format.format(date)
      x(2) = dateStr
      //返回  用户id_模块_时间
      (x(1) + "_" + x(2) + "_" + x(4),null)
    } }
   
    //去重
    val disRDD = mapRDD2.distinct()
    
    //只需要key,组装二元组
    val tupleRDD = disRDD.map(x =>{
      val key = x._1
      //key:会员id_时间_板块id
      //把会员id切掉
      val newKey = key.substring(key.indexOf("_")+1, key.length())
      (newKey,1)
    })
    
    //累加
    val reduceRDD2=tupleRDD.reduceByKey(_+_)
    reduceRDD2
  }
}