轻轻松松谈谈大数据

大数据概述

什么是大数据

大数据定义:

大数据(big data),IT行业术语,是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

麦肯锡全球研究所:一种规模大到在获取、存储、管理、分析方面大大超出了传统数据库软件工具能力范围的数据集合,具有海量的数据规模、快速的数据流转、多样的数据类型和价值密度低四大特征

我:大数据顾名思义:数据大(至少TB以上)

数据单位:

bit、Byte、KB、MB、GB、TB、PB、EB、ZB、YB、BB、NB、DB

1024

产生的背景:
在这里插入图片描述

大数据的意义:

(1)对大量消费者提供产品或服务的企业可以利用大数据进行精准营销;

(2)做小而美模式的中小微企业可以利用大数据做服务转型;

(3)面临互联网压力之下必须转型的传统企业需要与时俱进充分利用大数据的价值。

大数据的作用

(1)及时解析故障、问题和缺陷的根源,每年可能为企业节省数十亿美元。(网站日志)

(2)为成千上万的快递车辆规划实时交通路线,躲避拥堵。

(3)分析所有SKU(库存进出容量),以利润最大化为目标来定价和清理库存。

(4)根据客户的购买习惯,为其推送他可能感兴趣的优惠信息。

(5)从大量客户中快速识别出金牌客户。

(6)使用点击流分析和数据挖掘来规避欺诈行为。(刷点击)) [13]

(4)信用评价

(5)犯罪预测(洗黑钱、离岸金融数据监控、国内非法资金转移 )(网联清算有限公司)

大数据涉及的一般流程

数据采集:数据采集,又称数据获取,是利用一种装置,从系统外部采集数据并输入到系统内部的一个接口。数据采集技术目前广泛应用于各个领域。针对制造业企业的庞大生产数据,数据采集工具尤为重要。()

数据处理/分析、挖掘:从大量的原始数据抽取出有价值的信息,即数据转换成信息的过程

数据存储:将处理后的数据存入到数据库中,一般为大型的分布式存储

数据可视化:将数据化的展示出来

数据收集(获取):爬虫爬数据或者其他

flume采集工具

大数据处理目前比较流行的是两种方法,一种是离线处理,一种是在线处理,基本处理架构如下:

img

离线处理计算:(对时间要求不是非常严格)

hadoop 生态体系(Hadoop集群、)

img

后面我们的工作正是要基于Flume采集到HDFS中的数据做离线处理与分析。

MapReduce来对数据进行预处理,预处理之后的结果,我们也是保存到HDFS中,即采用如下的架构:

img

实时处理计算:(对时间要求非常严格)

spark生态体系(相对于Hadoop快一百倍,理论上)

Apache Spark是专为大规模数据处理而设计的快速通用的计算引擎 。现在形成一个高速发展应用广泛的生态系统

首先,高级 API 剥离了对集群本身的关注,Spark 应用开发者可以专注于应用所要做的计算本身。

其次,Spark 很快,支持交互式计算和复杂算法。

最后,Spark 是一个通用引擎,可用它来完成各种各样的运算,包括 SQL 查询、文本处理、机器学习等,而在 Spark 出现之前,我们一般需要学习各种各样的引擎来分别处理这些需求。

Hadoop详解

Hadoop架构

img

  • HDFS: 分布式文件存储
  • YARN: 分布式资源管理
  • MapReduce: 分布式计算
  • Others: 利用YARN的资源管理功能实现其他的数据处理方式

内部各个节点基本都是采用Master-Woker架构

Hadoop Distributed File System,分布式文件系统

架构

img

  • Block数据&##x5757;
  1. 基本存储单位,一般大小为64M(配置大的块主要是因为:1)减少搜寻时间,一般硬盘传输速率比寻道时间要快,大的块可以减少寻道时间;2)减少管理块的数据开销,每个块都需要在NameNode上有对应的记录;3)对数据块进行读写,减少建立网络的连接成本)
  2. 一个大文件会被拆分成一个个的块,然后存储于不同的机器。如果一个文件少于Block大小,那么实际占用的空间为其文件的大小
  3. 基本的读写S#x5355;位,类似于磁盘的页,每次都是读写一个块
  4. 每个块都会被复制到多台机器,默认复制3份
  • NameNode
  1. 存储文件的metadata,运行时所有数据都保存到内存,整个HDFS可存储的文件数受限于NameNode的内存大小
  2. 一个Block在NameNode中对应一条记录(一般一个block占用150字节),如果是大量的小文件,会消耗大量内存。同时map task的数量是由splits来决定的,所以用MapReduce处理大量的小文件时,就会产生过多的map task,线程管理开销将会增加作业时间。处理大量小文件的速度远远小于处理同等大小的大文件的速度。因此Hadoop建议存储大文件
  3. 数据会定时保存到本地磁盘,但不保存block的位置信息,而是由DataNode注册时上报和运行时维护(NameNode中与DataNode相关的信息并不保存到NameNode的文件系统中,而是NameNode每次重启后,动态重建)
  4. NameNode失效则整个HDFS都失效了,所以要保证NameNode的可用性
  • Secondary NameNode
  1. 定时与NameNode进行同步(定期合并文件系统镜像和编辑日&#x#x5FD7;,然后把合并后的传给NameNode,替换其镜像,并清空编辑日志,类似于CheckPoint机制),但NameNode失效后仍需要手工将其设置成主机
  • DataNode
  1. 保存具体的block数据
  2. 负责数据的读写操作和复制操作
  3. DataNode启动时会向NameNode报告当前存储的数据块信息,后续也会定时报告修改信息
  4. DataNode之间会进行通信,复制数据块,保证数据的冗余性

replication:复制

Hadoop MapReduce

一种分布式的计算方式指定一个Map(映#x5C04;)函数,用来把一组键值对映射成一组新的键值对,指定并发的Reduce(归约)函数,用来保证所有映射的键值对中的每一个共享相同的键组

img

map: (K1, V1) → list(K2, V2) combine: (K2, list(V2)) → list(K2, V2) reduce: (K2, list(V2)) → list(K3, V3)

Map输出格式和Reduce输入格式一定是相同的

package WebLogCleanBigdata;

import com.EducationWebLog.IpHelper;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
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 org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

import java.io.IOException;
import java.net.URI;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class WebLogClean extends Configured implements Tool {
/*主函数*/
    public static void main(String[] args) {
        /*创建配置实例*/
        Configuration conf = new Configuration();
        /*检测异常处理*/
        try {
            int res = ToolRunner.run(conf, new WebLogClean(), args);
            System.exit(res);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public int run(String[] args) throws Exception {
        final Job job = new Job(new Configuration(),
                WebLogClean.class.getSimpleName());
// 设置为可以打包运行的处理类
        job.setJarByClass(WebLogClean.class);
        /*设置输入文件的路径*/
        FileInputFormat.setInputPaths(job, args[0]);

        job.setMapperClass(MyMapper.class);
        /*设置mapper的相关参数*/
        job.setMapOutputKeyClass(LongWritable.class);
        job.setMapOutputValueClass(Text.class);
        /*设置reduce的相关系数*/
        job.setReducerClass(MyReduce.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(NullWritable.class);
        /*设置输出的文件的路径*/
        FileOutputFormat.setOutputPath(job, new Path(args[1]));
// 清理已存在的输出文件
        FileSystem fs = FileSystem.get(new URI(args[0]), getConf());
        Path outPath = new Path(args[1]);
        if (fs.exists(outPath)) {
            fs.delete(outPath, true);
        }

        boolean success = job.waitForCompletion(true);
        if(success){
            System.out.println("Clean process success!");
        }
        else{
            System.out.println("Clean process failed!");
        }
        return 0;
    }



    //------------------------------------------------------------------------------------------------
    /*
     * 日志解析类
     */
    /*对数据的切分与合并*/
    static class LogParser {
        public static void main(String[] args) throws ParseException {
            //final String S1 = "111.161.98.60 - - [10/Nov/2016:00:01:50 +0800] \"GET /search/article?page=4&words=%E6%97%B6%E6%97%B6%E5%BD%A9%E5%90%8E%E4%B8%80%E5%80%8D%E6%8A%95%E6%96%B9%E6%A1%88%E3%80%90%E5%AE%A2%E6%9C%8Dqq7 HTTP/1.1\" 200 14154 \"www.example.com\" \"http://www.example.com/search/article?page=4&words=%E6%97%B6%E6%97%B6%E5%BD%A9%E5%90%8E%E4%B8%80%E5%80%8D%E6%8A%95%E6%96%B9%E6%A1%88%E3%80%90%E5%AE%A2%E6%9C%8Dqq7\" - \"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)\" \"-\" 10.100.136.65:80 200 0.086 0.086";
            final String S1="117.35.88.11 - - [10/Nov/2016:00:01:02 +0800] \"GET /article/ajaxcourserecommends?id=124 HTTP/1.1\" 200 2345 \"www.example.com\" \"http://blog.jobbole.com/wfsdf/107417\" - \"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36\" \"-\" 10.100.136.65:80 200 0.616 0.616";
            LogParser parser = new LogParser();
            final String[] array = parse(S1);
            if (array[0].equals("-")){
                return;
            }else if (array[2].matches(".*[a-zA-Z].*")||array[2].equals("-")||array[2].equals(null)){
                return;
            }else {
                System.out.println(array[0]+"\t"+array[1]+"\t"+array[2]+"\t"+array[3]+"\t"
                        +array[4]+"\t"+array[5]+"\t"+array[6]+"\t"+array[7]);
            }
    
            String classno="";
    
        }
    
    }
    /*时间格式的转换*/
    public static final SimpleDateFormat FORMAT = new SimpleDateFormat(
            "d/MMM/yyyy:HH:mm:ss", Locale.ENGLISH);
    public static final SimpleDateFormat dateformat1 = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss");
    //解析英文时间字符串
    private static Date parseDateFormat(String string) {
        Date parse = null;
        try {
            parse = FORMAT.parse(string);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return parse;
    }
    /*对Time数据的"[]"处理,获取时间*/
    private static String parseTime(String line) {
        final int first = line.indexOf("[");
        final int last = line.indexOf("+0800]");
        String time = line.substring(first + 1, last).trim();
        Date date = parseDateFormat(time);
        return dateformat1.format(date);
    }
    /**
     * 解析日志的行记录
     *
     * @param line
     * @return 数组含有8个元素
     */
    public static String[] parse(String line){
        /*以空格切分,取第一个,获取时间*/
        String ip = line.split(" ")[0];
        String tmp = line.substring(line.indexOf("[")+1,
                line.indexOf("]")).replace("+0800","").trim();
        String dataTmp[] = tmp.split(":")[0].split("/");
    
        String datatime = parseTime(line);
        String data = datatime.substring(0,getCharacterPosion(datatime," ",1));


        String time = tmp.replace(tmp.split(":")[0]+":","");
        //String url = line.split(" ")[11].replace("\"","");
        String url = line.substring(getCharacterPosion(line,"\"",5)+1,
                getCharacterPosion(line,"\"",6));
        String cmsType;
        String cmsNo;
        if (url.equals("-")){
            cmsNo="-1";
            cmsType= "-";
        }else {
            String tmp1[] = url.split("/");
            cmsType = tmp1[tmp1.length-2];
            //cmsNo = url.substring(tmp1[4].length()+1);
            if (tmp1.length>5){
                cmsNo = "-";
            }else {
                cmsNo = url.substring(getCharacterPosion(url,"/",4)+1);
            }
    
        }
        String stream = line.split(" ")[9];
    
        String city = IpHelper.findRegionByIp(ip);
        if (city.contains("中国")||city.contains("全球")||city.contains("未知")){
            return new String[] {""};
        }
        //return ip +"\t"+ data +"\t"+dataTime +"\t"+url +"\t"+cmsType +"\t"+cmsNo +"\t"+city +"\t"+stream;
        return new String[]{url,cmsType,cmsNo,stream,ip,city,time,data};
    }
    private static int getCharacterPosion(String value,String operator,int index){
        Matcher slashMatcher = Pattern.compile(operator).matcher(value);
        int mIdx = 0;
        while (slashMatcher.find()){
            mIdx++;
            if (mIdx == index){
                break;
            }
        }
        return slashMatcher.start();
    }
    //------------------------------------------------------------------------------------
    public static class MyMapper extends Mapper<LongWritable, Text, LongWritable, Text> {
        @Override
        protected void map(LongWritable key, Text value, Context context) {
            try {
                String[] string = parse(value.toString());
                if (string[0].equals("-")){
                    return;
                }else if (string[2].matches(".*[a-zA-Z].*")||string[2].equals("-")){
                    return;
                }else {
                    context.write(key, new Text((string[0]+"\t"+string[1]+"\t"+string[2]+"\t"+string[3]+
                            "\t"+string[4]+"\t"+string[5]+"\t"+string[6]+"\t"+string[7])));
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    public static class MyReduce extends Reducer<LongWritable, Text, NullWritable, Text> {
        @Override
        protected void reduce(LongWritable key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
            for (Text value : values) {
                context.write(NullWritable.get(), value);
            }
        }
    }
}

基本流程

MapReduce主要是先读取文件数据,然后进行Map处理,接着Reduce处理,最后把处理结果写到文件中//img.mukewang.com/wiki/5bf260b309b7114706030175.jpg

img

Map Side

Record reader

记录阅读器会翻译由输入格式生成的记录,记录阅读器用于将数据解析给记录,并不分析记录自身。记录读取器的目的是将数据解析成记录,但不分析记录本身。它将数据以键值对的形式传输给mapper。通常键是位置信息,值是构成记录的数据存储块.自定义记录不在本文讨论范围之内.

Map

在映射器中用户提供的代码称为中间对。对于键值的具体定义是慎重的,因为定义对于分布式任务的完成具有重要意义.键决定了数据分类的依据,而值决定了处理器中的分析信息.本书的设计模式将会展示大量细节来解释特定键值如何选择.

Shuffle and Sort

ruduce任务以随机和排序步骤开始。此步骤写入输出文件并下载到本地计算机。这些数据采用键进行排序以把等价密钥组合到一起。

Reduce

reducer采用分组数据作为输入。该功能传递键和此键相关值的迭代器。可以采用多种方式来汇总、过滤或者合并数据。当ruduce功能完成,就会发送0个或多个键值对。

输出格式

输出格式会转换最终的键值对并写入文件。默认情况下键和值以tab分割,各记录以换行符分割。因此可以自定义更多输出格式,最终数据会写入HDFS

构成记录的数据存储块.自定义记录不在本文讨论范围之内.

Map

在映射器中用户提供的代码称为中间对。对于键值的具体定义是慎重的,因为定义对于分布式任务的完成具有重要意义.键决定了数据分类的依据,而值决定了处理器中的分析信息.本书的设计模式将会展示大量细节来解释特定键值如何选择.

Shuffle and Sort

ruduce任务以随机和排序步骤开始。此步骤写入输出文件并下载到本地计算机。这些数据采用键进行排序以把等价密钥组合到一起。

Reduce

reducer采用分组数据作为输入。该功能传递键和此键相关值的迭代器。可以采用多种方式来汇总、过滤或者合并数据。当ruduce功能完成,就会发送0个或多个键值对。

输出格式

输出格式会转换最终的键值对并写入文件。默认情况下键和值以tab分割,各记录以换行符分割。因此可以自定义更多输出格式,最终数据会写入HDFS

发布了32 篇原创文章 · 获赞 9 · 访问量 3131

猜你喜欢

转载自blog.csdn.net/weixin_43501566/article/details/104957457