使用Hadoop统计日志数据

用户行为日志概述

用户行为日志:

  • 用户每次访问网站时所有的行为数据

    • 访问、浏览、搜索、点击...
  • 用户行为轨迹、流量日志(用户行为日志的其他名称)

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

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

用户行为日志生成渠道:

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

用户行为日志大致内容:

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

用户行为日志分析的意义:

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

离线数据处理架构

离线数据处理流程:

  • 数据采集

    • 例如可以使用Flume进行数据的采集:将web日志写入到HDFS
  • 数据清洗
    • 可以使用Spark、Hive、MapReduce等框架进行数据的清洗,清洗完之后的数据可以存放在HDFS或者Hive、Spark SQL里
  • 数据处理
    • 按照我们的需求进行相应业务的统计和分析
  • 数据处理结果入库
    • 结果可以存放到RDBMS、NoSQL数据库
  • 数据的可视化展示
    • 通过图形化展示的方式展现出来:饼图、柱状图、地图、折线图等等
    • 工具:ECharts、HUE、Zeppelin

流程示意图:


项目需求

需求:

  • 统计网站访问日志中每个浏览器的访问次数

日志片段如下:

183.162.52.7 - - [10/Nov/2016:00:01:02 +0800] "POST /api3/getadv HTTP/1.1" 200 813 "www.xxx.com" "-" cid=0&timestamp=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

功能实现之UserAgent解析类测试

首先我们需要根据日志信息抽取出浏览器信息,针对不同的浏览器进行统计操作。虽然可以自己实现这个功能,但是懒得再造轮子了,所以我在GitHub找到了一个小工具可以完成这个功能,GitHub地址如下:

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>

  <!-- mvn assembly:assembly -->
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <mainClass></mainClass>
            </manifest>
          </archive>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>

然后我们编写一个测试用例来测试一下这个解析类,因为之前并没有使用过这个工具,所以对于一个未使用过的工具,要养成在工程中使用之前对其进行测试的好习惯:

package org.zero01.project;

import com.kumkee.userAgent.UserAgent;
import com.kumkee.userAgent.UserAgentParser;

/**
 * @program: hadoop-train
 * @description: UserAgent解析测试类
 * @author: 01
 * @create: 2018-04-01 22:43
 **/
public class UserAgentTest {

    public static void main(String[] args) {
        String source = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36";
        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);
        System.out.println("引擎:" + engine);
        System.out.println("引擎版本:" + engineVersion);
        System.out.println("操作系统:" + os);
        System.out.println("平台:" + platform);
        System.out.println("是否是移动设备:" + isMobile);
    }
}

控制台输出结果如下:

浏览器:Chrome
引擎:Webkit
引擎版本:537.36
操作系统:Windows 7
平台:Windows
是否是移动设备:false

从打印结果可以看到,UserAgent的相关信息都正常获取到了,我们就可以在工程中进行使用这个工具了。


使用MapReduce完成需求统计

创建一个类,编写代码如下:

package org.zero01.hadoop.project;

import com.kumkee.userAgent.UserAgent;
import com.kumkee.userAgent.UserAgentParser;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
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;

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @program: hadoop-train
 * @description: 使用MapReduce来完成统计浏览器的访问次数
 * @author: 01
 * @create: 2018-04-02 14:20
 **/
public class LogApp {

    /**
     * Map: 读取输入的文件内容
     */
    public static class MyMapper extends Mapper<LongWritable, Text, Text, LongWritable> {

        LongWritable one = new LongWritable(1);
        private UserAgentParser userAgentParser;

        protected void setup(Context context) throws IOException, InterruptedException {
            userAgentParser = new UserAgentParser();
        }

        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            // 接收到的每一行日志信息
            String line = value.toString();

            String source = line.substring(getCharacterPosition(line, "\"", 7) + 1);
            UserAgent agent = userAgentParser.parse(source);
            String browser = agent.getBrowser();

            // 通过上下文把map的处理结果输出
            context.write(new Text(browser), one);
        }

        protected void cleanup(Context context) throws IOException, InterruptedException {
            userAgentParser = null;
        }
    }

    /**
     * Reduce: 归并操作
     */
    public static class MyReducer extends Reducer<Text, LongWritable, Text, LongWritable> {

        protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
            long sum = 0;
            for (LongWritable value : values) {
                // 求key出现的次数总和
                sum += value.get();
            }
            // 将最终的统计结果输出
            context.write(key, new LongWritable(sum));
        }
    }

    /**
     * 获取指定字符串中指定标识的字符串出现的索引位置
     *
     * @param value
     * @param operator
     * @param index
     * @return
     */
    private static int getCharacterPosition(String value, String operator, int index) {
        Matcher slashMatcher = Pattern.compile(operator).matcher(value);
        int mIdex = 0;
        while (slashMatcher.find()) {
            mIdex++;

            if (mIdex == index) {
                break;
            }
        }
        return slashMatcher.start();
    }

    /**
     * 定义Driver:封装了MapReduce作业的所有信息
     */
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        Configuration configuration = new Configuration();

        // 准备清理已存在的输出目录
        Path outputPath = new Path(args[1]);
        FileSystem fileSystem = FileSystem.get(configuration);
        if (fileSystem.exists(outputPath)) {
            fileSystem.delete(outputPath, true);
            System.out.println("output file exists, but is has deleted");
        }

        // 创建Job,通过参数设置Job的名称
        Job job = Job.getInstance(configuration, "LogApp");

        // 设置Job的处理类
        job.setJarByClass(LogApp.class);

        // 设置作业处理的输入路径
        FileInputFormat.setInputPaths(job, new Path(args[0]));

        // 设置map相关参数
        job.setMapperClass(LogApp.MyMapper.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(LongWritable.class);

        // 设置reduce相关参数
        job.setReducerClass(LogApp.MyReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);

        // 设置作业处理完成后的输出路径
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}

在工程目录下打开控制台,输入如下命令进行打包:

mvn assembly:assembly

打包成功:

将这个jar包上传到服务器上:

[[email protected] ~]# rz
[[email protected] ~]# ls |grep hadoop-train-1.0-jar-with-dependencies.jar
hadoop-train-1.0-jar-with-dependencies.jar
[[email protected] ~]#

把事先准备好的日志文件上传到HDFS文件系统中:

[[email protected] ~]# hdfs dfs -put ./10000_access.log /
[[email protected] ~]# hdfs dfs -ls /10000_access.log
-rw-r--r--   1 root supergroup    2769741 2018-04-02 22:33 /10000_access.log
[[email protected] ~]#

执行如下命令

[[email protected] ~]# hadoop jar ./hadoop-train-1.0-jar-with-dependencies.jar org.zero01.hadoop.project.LogApp /10000_access.log /browserout

执行成功:

查看处理结果:

[[email protected] ~]# hdfs dfs -ls /browserout
Found 2 items
-rw-r--r--   1 root supergroup          0 2018-04-02 22:42 /browserout/_SUCCESS
-rw-r--r--   1 root supergroup         56 2018-04-02 22:42 /browserout/part-r-00000
[[email protected] ~]# hdfs dfs -text /browserout/part-r-00000
Chrome  2775
Firefox 327
MSIE    78
Safari  115
Unknown 6705
[[email protected] ~]# 

原文地址:http://blog.51cto.com/zero01/2093820

时间: 2024-10-08 09:46:45

使用Hadoop统计日志数据的相关文章

海量日志数据如何处理统计?

项目需要做一个dashboard图表网站,展示日志的相关统计信息.这个页面图表很多,一次性会加载出很多数据. 日志表有很多种,都是一些入侵攻击日志.恶意站点访问日志等等,需要统计出当前时间.过去24小时.过去一周被攻击主机个数.恶意站点数(这是其中两个需求)等等数据. 比如被攻击主机个数,需要查多张数据表,然后统计出这个数据. 日志存储在PostgreSQL里面,已经基于时间做了分表,但是每天的的日志量都在100W以上. 写入数据库的模式是随时从其他的系统中写入. 根据这个应用场景,如果设计这个

Hadoop HDFS源码分析 读取命名空间镜像和编辑日志数据

读取命名空间镜像和编辑日志数据 1.读取命名空间镜像 类FSImage是 命名空间镜像的java实现,在源码中,英文注释为, /** * FSImage handles checkpointing and logging of the namespace edits. * */ FSImage.loadFSImage(FSNamesystem, StartupOption, MetaRecoveryContext) 读取命名空间镜像. 1 private boolean loadFSImage(

Hadoop! | 大数据百科 | 数据观 | 中国大数据产业观察_大数据门户

你正在使用过时的浏览器,Amaze UI 暂不支持. 请 升级浏览器 以获得更好的体验! 深度好文丨读完此文,就知道Hadoop了! 来源:BiThink 时间:2016-04-12 15:14:39 作者:陈飚 “昔我十年前,与君始相识.” 一瞬间Hadoop也到了要初中择校的年龄了. 十年前还没有Hadoop,几年前国内IT圈里还不知道什么是Hadoop,而现在几乎所有大型企业的IT系统中有已经有了Hadoop的集群在运行了各式各样的任务. 2006年项目成立的一开始,“Hadoop”这个单

Hadoop和大数据:60款顶级大数据开源工具

一.Hadoop相关工具 1. Hadoop Apache的Hadoop项目已几乎与大数据划上了等号.它不断壮大起来,已成为一个完整的生态系统,众多开源工具面向高度扩展的分布式计算. 支持的操作系统:Windows.Linux和OS X. 相关链接: http://hadoop.apache.org 2. Ambari 作为Hadoop生态系统的一部分,这个Apache项目提供了基于Web的直观界面,可用于配置.管理和监控Hadoop集群.有些开发人员想把Ambari的功能整合到自己的应用程序当

Hadoop和大数据:60款顶级开源工具

虽然此文尽力做到全面,但难免遗漏,欢迎大家补充,点击文末右下角"写评论",分享你的观点. 说到处理大数据的工具,普通的开源解决方案(尤其是Apache Hadoop)堪称中流砥柱.弗雷斯特调研公司的分析师Mike Gualtieri最近预测,在接下来几年,"100%的大公司"会采用Hadoop.Market Research的一份报告预测,到2011年,Hadoop市场会以58%的年复合增长率(CAGR)高速增长:到2020年,市场产值会超过10亿美元.IBM更是非

用python统计日志中IP的数量

引 入 日志文件,是我们记录用户行为的重要手段.而对于不同的用户,我们往往又会根据IP来区分,所以统计日志文件中的IP访问,对于数据分析人员和相关运营专员来说,是一件重要的事情,这里,采用python这门语言来完成这个小功能. 一.分析IP格式 这里只讨论ipv4. 分析IP格式思路有许多,这里我只分析其中一种比较容易理解的. 1) 从分析一个从1~255的数字开始 一个1~255的数细分成以下5个分组. 数字分组 正则表达式表示 1~9 [1-9] 10~99 [1-9][0-9] 100~1

Poseidon 系统是一个日志搜索平台——认证看链接ppt,本质是索引的倒排列表和原始日志数据都存在HDFS,而文档和倒排的元数据都在NOSQL里,同时针对单个filed都使用了独立索引,使用MR来索引和搜索

Poseidon 系统是一个日志搜索平台,可以在百万亿条.100PB 大小的日志数据中快速分析和检索.360 公司是一个安全公司,在追踪 APT(高级持续威胁)事件,经常需要在海量的历史日志数据中检索某些信息,例如某个恶意样本在某个时间段内的活动情况.在 Poseidon 系统出现之前,都是写 Map/Reduce 计算任务在 Hadoop 集群中做计算,一次任务所需的计算时间从数小时到数天不等,大大制约了 APT 事件的追踪效率.Poseidon 系统就是解决这个需求,能在数百万亿条规模的数据

flume学习(三):flume将log4j日志数据写入到hdfs(转)

原文链接:flume学习(三):flume将log4j日志数据写入到hdfs 在第一篇文章中我们是将log4j的日志输出到了agent的日志文件当中.配置文件如下: [plain] view plaincopy tier1.sources=source1 tier1.channels=channel1 tier1.sinks=sink1 tier1.sources.source1.type=avro tier1.sources.source1.bind=0.0.0.0 tier1.sources

5个日志数据:让你轻松分析系统性能

1.缓慢的响应时间 响应时间是日志数据最常见和最有用的性能,它能让你知道请求是多长时间被系统响应的.例如Web服务器日志可以让你洞察请求需要多久才能返回客户端设备的响应.这时间可以包括采用web服务器背后的不同组件(应用服务器,数据块)来处理请求的时间,因此它能够即时查看到你的应用程序是如何运作的.从客户端设备/ 浏览器记录的响应时间能够给你一个更全面的了解,因为它也捕捉在app/浏览器的页面加载和网络延迟时间. 一个好的测量响应时间的法则是1993年Jakob Nielsen发表的3响应时间的