10小时入门大数据()------Hadoops项目实战

一、用户行为日志概述

1)用户行为日志
用户每次访问网站时所有的行为数据:访问、浏览、搜索、点击… 用户行为轨迹、流量

2)为什么要记录用户访问行为日志

  • 进行网站页面的访问量的统计
  • 分析网站的黏性
  • 推荐

3)用户行为日志生成渠道

  • Nginx:web服务器记录的web访问日志
  • Ajax:记录的访问日志以及其他相关的日志

4)用户行为日志大致内容

  • 访问时间
  • 访问者所使用的客户端(UserAgent)
  • 访问者的IP地址
  • 访问者账号某个页面的停留时间
  • 访问的时间与地点跳转的链接地址(referer)
  • 访问信息,例如:session_id模块AppID

5)日志数据内容

  • 访问的系统属性:操作系统、浏览器等
  • 访问特征:点击的url、从哪个url跳转过来的(referer)、页面上的停留时间等
  • 访问信息:session_id、访问ip(访问城市)等

6) 用户行为日志分析的意义

  • 网站的眼睛
  • eg.能够看到用户的主要来源、喜好网站上的哪些内容,以及用户的忠诚度等
  • 网站的神经
  • eg.通过分析用户行为日志,我们能对网站的布局、功能进一步的优化,以提高用户的体验等
  • 网站的大脑
  • eg.通过分析结果,进行推广预算的划分,以及重点优化用户群体的倾向点

二、离线处理架构##### 数据处理流程

1)数据采集:Flume:Web日志写入到HDFS
当访问某个网站时,每一个访问请求都会发送到后台的服务器上,面对高并发的情况下,大多使用的是Njexl来接受请求,然后再进行高并发的访问均衡,即使用N已经可以输出数据了,再通过Flume采集,它是将数据从一个地方搬运到另一个地方的框架
2)数据清洗
脏数据 eg.不符合日志规范的数据,要先清除技术:Hive Spark MapReduce或其他一些分布式计算框架清洗完的数据可以存放在HDFS(Hive/Spark SQL)
3)数据处理
按照我们的需要进行相应业务的统计和分析Hive Spark MapReduce或其他一些分布式计算框架
4)处理结果入库
可以存放到RDBMS(关系型数据库)、NoSQL(非关系型数据库)
5)数据的可视化
通过图形化的方式展现出来:饼图、柱状图、地图、折线图等ECharts、HUE、Zeppelin
在这里插入图片描述

三、项目需求统计imooc主站访问日志的浏览器访问次数

  • 根据日志信息抽取出浏览器信息
  • 针对不同的浏览器进行统计操作

1)日志片段如下:

183.162.52.7 - - [10/Nov/2016:00:01:02 +0800] "POST /api3/getadv HTTP/1.1" 200 813 "www.xxx.com" "-" cid=0×tamp=1478707261865&uid=2871142&marking=androidbanner&secrect=a6e8e14701ffe9f6063934780d9e2e6d&token=f51e97d1cb1a9caac669ea8acc162b96 "mukewang/5.0.0 (Android 5.1.1; Xiaomi Redmi 3 Build/LMY47V),Network 2G/3G" "-" 10.100.134.244:80 200 0.027 0.027
10.100.0.1 - - [10/Nov/2016:00:01:02 +0800] "HEAD / HTTP/1.1" 301 0 "117.121.101.40" "-" - "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "-" - - - 0.000

2)实现UserAgent解析类测试
工具类下载githu地址:https://github.com/LeeKemp/UserAgentParser

通过git clone或者浏览器下载到本地后,使用命令行进入到其主目录下,然后通过maven命令对其进行打包并安装到本地仓库里:

mvn clean package -DskipTest    
mvn clean install -DskipTest

安装完成后,在工程中添加依赖:

<!-- 添加UserAgent解析的依赖 -->   
 <dependency>      
 <groupId>com.kumkee</groupId>      
 <artifactId>UserAgentParser</artifactId>      
 <version>0.0.1</version>    
 </dependency>

编写一个测试用例来测试一下这个解析类

**
 * UserAgentTest测试类
 */
public class UserAgentTest {
    /**
     * 单元测试:UserAgent工具类的使用
     */
    @Test
    public void testUserAgentParser(){
        //信息
        String source="183.162.52.7 - - [10/Nov/2016:00:01:02 +0800] \"POST /api3/getadv HTTP/1.1\" 200 813 \"www.xxx.com\" \"-\" cid=0×tamp=1478707261865&uid=2871142&marking=androidbanner&secrect=a6e8e14701ffe9f6063934780d9e2e6d&token=f51e97d1cb1a9caac669ea8acc162b96 \"mukewang/5.0.0 (Android 5.1.1; Xiaomi Redmi 3 Build/LMY47V),Network 2G/3G\" \"-\" 10.100.134.244:80 200 0.027 0.027\n" +
                "10.100.0.1 - - [10/Nov/2016:00:01:02 +0800] \"HEAD / HTTP/1.1\" 301 0 \"117.121.101.40\" \"-\" - \"curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2\" \"-\" - - - 0.000";

        //解析日志头部的工具类
        UserAgentParser userAgentParser  = new UserAgentParser();
        UserAgent agent = userAgentParser.parse(source);

        //功能
        String browser=agent.getBrowser();
        String engine=agent.getEngine();
        String engineVersion=agent.getEngineVersion();
        String os=agent.getOs();
        String platform=agent.getPlatform();
        boolean isMobile=agent.isMobile();

        //输出结果
        System.out.println(browser+", "+engine+", "+engineVersion+", "+os+", "+platform+", "+isMobile);
    }

结果:Unknown, Unknown, null, Linux, Android, true

四、基于Hash的本地浏览器数量代码

package com.immoc.hadoop.project;

import com.kumkee.userAgent.UserAgent;
import com.kumkee.userAgent.UserAgentParser;
import org.apache.commons.lang.StringUtils;
import org.junit.Test;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * UserAgentTest测试类
 */
public class UserAgentTest {
    /**
     * 单元测试:UserAgent工具类的使用
     */
    @Test
    public void testUserAgentParser(){
        //信息
        String source="183.162.52.7 - - [10/Nov/2016:00:01:02 +0800] \"POST /api3/getadv HTTP/1.1\" 200 813 \"www.xxx.com\" \"-\" cid=0×tamp=1478707261865&uid=2871142&marking=androidbanner&secrect=a6e8e14701ffe9f6063934780d9e2e6d&token=f51e97d1cb1a9caac669ea8acc162b96 \"mukewang/5.0.0 (Android 5.1.1; Xiaomi Redmi 3 Build/LMY47V),Network 2G/3G\" \"-\" 10.100.134.244:80 200 0.027 0.027\n" +
                "10.100.0.1 - - [10/Nov/2016:00:01:02 +0800] \"HEAD / HTTP/1.1\" 301 0 \"117.121.101.40\" \"-\" - \"curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2\" \"-\" - - - 0.000";

        //解析日志头部的工具类
        UserAgentParser userAgentParser  = new UserAgentParser();
        UserAgent agent = userAgentParser.parse(source);

        //功能
        String browser=agent.getBrowser();
        String engine=agent.getEngine();
        String engineVersion=agent.getEngineVersion();
        String os=agent.getOs();
        String platform=agent.getPlatform();
        boolean isMobile=agent.isMobile();

        //输出结果
        System.out.println(browser+", "+engine+", "+engineVersion+", "+os+", "+platform+", "+isMobile);
    }

    /**
     * 自定义方法
     * 获取指定字符串中指定标识符的字符串出现的索引位置
     * @param value 字符串值
     * @param operator 指定标识符
     * @param index 索引位置
     * @return
     */
    private int getCharacterPosition(String value,String operator,int index){
        //对子字符串进行匹配
        Matcher slashMatcher= Pattern.compile(operator).matcher(value);
        int mInx=0;//计数
        //matcher.find();尝试查找与该模式匹配的输入序列的下一个子序列
        while (slashMatcher.find()){
            mInx++;
            if (mInx==index){
                break;
            }
        }
        //slashMatcher.start()返回上一个匹配的起始索引
        return slashMatcher.start();
    }

    /**
     * 测试自定义方法
     */
    @Test
    public void testGtCharacterPosition(){
        String value="183.162.52.7 - - [10/Nov/2016:00:01:02 +0800] \"POST /api3/getadv HTTP/1.1\" 200 813 \"www.xxx.com\" \"-\" cid=0×tamp=1478707261865&uid=2871142&marking=androidbanner&secrect=a6e8e14701ffe9f6063934780d9e2e6d&token=f51e97d1cb1a9caac669ea8acc162b96 \"mukewang/5.0.0 (Android 5.1.1; Xiaomi Redmi 3 Build/LMY47V),Network 2G/3G\" \"-\" 10.100.134.244:80 200 0.027 0.027\n" +
                "10.100.0.1 - - [10/Nov/2016:00:01:02 +0800] \"HEAD / HTTP/1.1\" 301 0 \"117.121.101.40\" \"-\" - \"curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2\" \"-\" - - - 0.000";
        int index=getCharacterPosition(value,"\"",7);
        System.out.println(index);
    }


    /**
     * 测试读取文件
     */
    @Test
    public void testReadFile() throws Exception{
        String path="";
        //读取path路径下的文件内容
        BufferedReader reader=new BufferedReader
                (new InputStreamReader(new FileInputStream(new File(path))));

        String line="";
        //计数
        int count=0;

        //解析日志头部的工具类
        UserAgentParser userAgentParser=new UserAgentParser();

        //String 浏览器类型 Integer 浏览次数
        Map<String,Integer> browserMap=new HashMap<String,Integer>();

        while(line!=null){
            line=reader.readLine();//一次读取一行数据
            count++;//记录数据量

            if (StringUtils.isNotBlank(line)){
                //得到第7个"后的字符串
                String source=line.substring(getCharacterPosition(line,"\"",7)+1);

                UserAgent agent = userAgentParser.parse(source);
                String browser=agent.getBrowser();
                String engine=agent.getEngine();
                String engineVersion=agent.getEngineVersion();
                String os=agent.getOs();
                String platform=agent.getPlatform();
                boolean isMobile=agent.isMobile();

                Integer broswerValue=browserMap.get(browser);
                if(broswerValue!=null){
                    //put(K key,V value)
                    browserMap.put(browser,broswerValue+1);
                }else{
                    browserMap.put(browser,1);
                }

                //输出结果
                System.out.println(browser+", "+engine+", "+engineVersion+", "+os+", "+platform+", "+isMobile);
            }
        }
        System.out.println("records count:"+count);

        System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        //entrySet将map里的键值对取出来封装成一个Entry对象再存到一个Set中
        for(Map.Entry<String,Integer> entry : browserMap.entrySet()){
            System.out.println(entry.getKey()+": "+entry.getValue());
        }
    }


    public static void main(String []args){

    }
}

猜你喜欢

转载自blog.csdn.net/mys_mys/article/details/82595414