大数据学习笔记(spark日志分析案例)

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

1、PV和UV

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

1.1、PV

PageView:浏览量。(有几次浏览就算几次)
  大数据学习笔记(spark日志分析案例)_第1张图片

1.2、UV

UserView:用户量。(同一个用户同一天浏览一个模块多次,只能算一次)
  大数据学习笔记(spark日志分析案例)_第2张图片
1.3、PV+UV

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

按照前面的操作已经获得了两个RDD,PVRDD、UVRDD。在这两个RDD上使用join连接,在join算子里面通过(0.3PV+0.7UV)可以获得每天的各个模块的一个热度值。将这个值排序。取前三名,就是我们要求的每天最热top3板块了。
大数据学习笔记(spark日志分析案例)_第3张图片

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;

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 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
  }
}

你可能感兴趣的:(大数据学习笔记(spark日志分析案例))