用户行为分析之蜕变 -- hadoop 替代纯 java

在用户行为分析系统开发中,作者从最初使用Java遇到的数据处理速度和复杂性问题,转向学习并应用Hadoop。通过Hadoop,31M的测试数据在2-3分钟内完成处理,显著提升了效率。文章介绍了学习Hadoop的步骤,实战经验,并分享了关于学习新技术、关注性能优化和未来可能涉及工作流的感悟。
摘要由CSDN通过智能技术生成

背景:

最近两个月在弄用户行为分析系统,我本来是做java ee, 一开始,在数据量还不是很大的情况下,用纯 java 实现数据分析。但是越来越痛苦,我的数据采用一级一级总结抽取的方法,第一级数据是用户上传的txt数据,系统转化一次一级数据的时间从无知觉-几分钟-十几分钟-几十分钟-一个多钟-到现在的接近两个钟点。而且,中途还得保证数据的完整性、程序的健壮性,举个例子,我要分析5000个用户文件,如果中途机器出现故障、程序报错、或者用户数据不规范,都会导致转化数据不完整,这个时候,我不知道哪些是已经被分析的数据,哪些数据是清白的,我得做容错处理,做读取标记,或者做事物回滚。而这些,如果涉及到关联,控制层关联缓存,缓存关联服务层,服务层关联dao层,dao层直接影响数据库,那就太麻烦了。

于是,打算用hadoop来做,hadoop 是用java 实现的,API看起来特别舒服!!! 断断续续看了一个星期,在此记录一下

步骤:

我完完全全把hadoop看成是一个java框架,类似于spring,学习步骤也是老套路

  • 先看看能做出什么样的效果

  • 适用性和局限性

  • 工作原理机制、模式

  • hello,world

  • 看别人的代码快速解决当前实际需求

  • 漫长的查看API、代码深入

上面的网络一大把资源,我这里总结一些学习资源:

实战:

hadoop的3种运行模式中,我先用单机模式,如果在本地上安装hadoop很耗费时间,配置、跑wordCount的demo老是不成功的条件下,可以先不用本地安装。既然是个java框架,用maven导进来即可。

  • 新建一个maven支持的java项目

  • pom.xml 文件引进hadoop,版本随意,注意下兼容jdk版本就行

<!-- hadoop -->
    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-common</artifactId>
      <version>${hadoop.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-hdfs</artifactId>
       <version>${hadoop.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-mapreduce-client-core</artifactId>
      <version>${hadoop.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-mapreduce-client-jobclient</artifactId>
      <version>${hadoop.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-mapreduce-client-common</artifactId>
      <version>${hadoop.version}</version>
    </dependency>

    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-client</artifactId>
       <version>${hadoop.version}</version>
    </dependency>
  • log4j 的配置文件,打印log
log4j.rootLogger=INFO,Console,File

#控制台日志
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%p][%t][%d{yyyy-MM-dd HH\:mm\:ss}][%C] - %m%n


#普通文件日志
log4j.appender.File=org.apache.log4j.RollingFileAppender
log4j.appender.File.File=logs/ssm.log
log4j.appender.File.MaxFileSize=10MB
#输出日志,即debug日志
log4j.appender.File.Threshold=ALL
log4j.appender.File.layout=org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern=[%p][%t][%d{yyyy-MM-dd HH\:mm\:ss}][%C] - %m%n
  • 编码
...

  static class MyMapper extends Mapper<Object, Text, Text, IntWritable> {

        private final static IntWritable one = new IntWritable(0);
        private Text word = new Text();

        @Override
        protected void map(Object key, Text value, Mapper<Object, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {

            //分隔
            String[]  appSerial = value.toString().split("&");
            //只要第一行第3个元素序列号
            if(appSerial.length > 3) {
                word.set(appSerial[2]);
                context.write(word, one);
            }   
        }

    }

    static class MyReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
        private IntWritable result = new IntWritable();
        private Text keyEx = new Text();

        @Override
        protected void reduce(Text key, Iterable<IntWritable> values,
                              Reducer<Text, IntWritable, Text, IntWritable>.Context context)
                throws IOException, InterruptedException {
            int sum = 0;
            //叠加统计结果
            for (IntWritable val : values) {
                sum += val.get() + 1;
            }
            result.set(sum);

            keyEx.set(key.toString());
            context.write(keyEx, result);
        }
    }
...  

上面的代码是核心的两个内部类,是hadoop对数据处理的工作模式

这里写图片描述

map 和 reduce 方法实际上相反的过程,就像分而治之的思想,皇帝要收税,把任务根据封地分为几个小任务,每个封地的诸侯收集封地的税,统一交给皇帝处理。数据在输入的时候,在输入拆分中为每个键值对调用一次map方法,把数据分成多份,让map并行处理,输出的结果作为reduce的输入,reduce方法为每一个键调用一次(这个键就是map出来的结果的键值)。


  • 运行效果,31M的txt测试数据用了2~3分钟跑完,跟纯java的速度比火箭还快,!

这里写图片描述


这里写图片描述

后记–感悟:

1.学习新东西,都是从-迷茫-清晰-迷茫-清晰-…一步一步一个脚印,没有捷径

2.API,一年前的我很讨厌看API,尤其是纯英文的,而现在习惯了,经验+教训,一步一步一个脚印,没有捷径

3.编码,在业务系统中从来没注意过性能,但是当数据一大,平常一个毫无知觉的失误可能会引起很大的性能下降,数据量变到G级,我不得不考虑怎么减少循环、这个类要在哪里创建最好、我这一块代码有没有设计模式或是好的方法实现、用int还是Integer,异常要在哪里抛出…还是经验+教训,一步一步一个脚印,没有捷径

4.直觉:我现在用单机版本,本地跑,跟业务分开,那如果要部署上线呢,数据分析和业务结合怎么结合,如果客户要定制呢。现在强烈预感到下一个要接触的是工作流。

5.谢谢观看!!!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值