zoukankan      html  css  js  c++  java
  • Hadoop学习之路(一)理论基础和逻辑思维

    三个题目

    第一题

    问题描述

    统计出当前这个一行一个IP的文件中,到底哪个IP出现的次数最多

    解决思路

    //必须要能读取这个内容  
    
            BufferedReader br = new BuffedReader(new FileInputStream(new File("c:/big.txt")));
              // 每次读取一行
            String line = null;
            while( (line=br.readLine()) != null){
                // 处理这读取到的一行内容的代码
            }
    
            //最简单的一种思路:  初始化一个hashmap
    
            //hashmap中存储的键值对的  key : IP      value : 次数
    
            int count = 0;  // 就是用来进行存储当前出现次数最多的那个IP的次数
            String maxip = null;
            Set<String> ips = hashmap.keySet();
            for(String ip :  ips){
                int ipcount = hashmap.get(ip)
                if(ipcount > count){
                    count = ipcount
                    maxip = ip;
                }
            }
            System.out.println(maxip + " : " +count);

    问题难点

    1、当读取的文件的大小超过内存的大小时,以上的解决方案是不可行的。

    2、假如说你的内存足够大,能装下这个文件中的所有ip,整个任务的执行效率会非常低,消耗的时间会非常的长。

      1GB -- 5分

      1TB --- 1024 * 5 分

    3、最终整个任务就使用一台机器,那么最终整个任务执行完成所消耗的时间是和数据的大小成正比。提升服务器的执行性能来提高数据的处理速度。

        当前这一台机器的执行性能:          5分钟/GB

        提升服务器的执行性能: CPU :i3 ---> i7 1分钟/GB

    在最开始的服务器领域:提升服务器对外提供服务的效率手段就是纵向提升服务器性能。理想是丰满的,现实是骨感的,但是服务器性能提升有瓶颈。

    摩尔定律:每隔18-24个月,服务器的性能提升一倍。

    如果说数据的增长是每隔18-24个月就增长一倍,工作量增加了一倍。工作效率也增加了一倍,那么最终完成同一个任务所花费的时间是一样的。

    但是数据的增长速度是远远超过服务器性能的提升。在数据不断增长的情况下,单位时间内,服务器所需要处理的数据量是越来越大。

    假如:

    服务器的性能提升 速率 和 数据的增长速率一样: 在18-24个月
    10GB --- 性能: 1分钟/GB --- 10分钟
    20GB --- 性能: 1分钟/2GB --- 10分钟

    假如:

    服务器的性能提升 速率 和 数据的增长速率不一样: 在18-24个月
    10GB --- 性能: 1分钟/GB --- 10分钟
    100GB --- 性能: 1分钟/2GB --- 50分钟

    最终的结论: 靠 纵向提升服务器性能的手段 在理论上有 瓶颈的。

    最终解决方案:纵向不可取,所以采取横向扩展。

    所谓的横向扩展:就是增加服务器的数量。

    一个庞大的复杂任务就应该 平均分配给所有的服务器做处理
    
    10GB 一台服务器 10分钟
    
    100GB 一台服务器 100分钟
    
    100GB 10台服务器 10分钟
    
    10000GB 1000台 10分钟
    
    在理论上 有上限么??没有

    两种情况下:
    1、在数据量比较小的情况下,单台服务器就可以再用户可接受的时限范围内完成任务。
    2、当数据量变大时,如果用户也想在可接受的时限范围内完成任务,那么可行的方案就是进行服务器的横向扩展。

    核心思想: 大事化小 分而治之
    终极解决方案:
    1、先把文件切碎成很多的小文件。
    2、每一个服务器节点去处理一个小文件。
    3、再把所有服务器的处理结果汇总到一起。
    4、再把所有的数据合并到一起求出出现次数最多的那个ip。

    只要是通过网络传输数据,就一定存在丢失数据的可能。

    第二题

    问题描述

    在两个庞大文件中,文件也都是存储的URL地址(每行一个),比如文件名叫做file1和file2, 找出这两个文件中的交集(相同的URL)?

    以上问题等同于SQL:select url from file1 a join file2 b on a.url = b.url

    问题分析

    概念:出现在在file1中的元素也出现在file2中。这些元素的集合就是交集

    需求:求2个文件的交集

    文件中的元素:URL

    解决方案

    1.当2个文件都比较小的时候

      步骤:

        1. 编写一个程序可以去读文件的内容,把文件中的所有元素都放置在一个set1中

            编写一个流处理取读取文件内容,逐行读取,每次读取到的一行放入set1中

        2. 运行相同的程序处理另外一个文件的内容,把文件中的所有元素都放置在一个set2中

        3. 先遍历一个集合,每次遍历出来的元素都去另外一个集合中判断存在不存在。如果存在,就是共同元素,这个共同元素就存储在某个集合中resultSet;如果不存在,就不是共同元素。

        4. 结果集:集合resultSet

    2.当2个文件都比较大的时候

      第一种思路:采取跟第一个题目一样的大事化小的策略

      第二种思路:改良第一种思路。避免第一种思路中的很多无效匹配 a1 * a2

            必须做到合理的数据分区,数据分区的两种最基本的思路:

              1.先排序,然后分段==分区

              2.hash散列  --  求hash值,然后利用hash值求和分区个数的余数,如果余数相同,就证明这些元素在同一个分区中

            改良了实现思路之后,可以让原来应该执行16个小任务的大任务。只需要执行4个小任务即可。

    终极解决方案:

    1.先指定一个分区策略:hash散列

    2.预估预估一下数据要被切分成多少个块,一定要保证两个文件切分出来的小文件个数成倍数

    3.根据hash散列的策略,对两份文件分别进行操作

    4.根据原来指定的策略,寻找对应的两个大文件中的对应小文件进行求交集操作

    5.所有的结果,根本就不用再进行去重了。直接进行拼接即可。

    学到的东西:

      整个大数据生态系统中的很多技术软件的底层处理数据的分区时,默认的策略都是hash散列。

    第三题

    问题描述

    现在有一个非常庞大的URL库(10000E),然后现在还有一个URL,(迅速)判断这个URL是否在这个URL库中?

    问题分析

    需求:判断一个元素在不在某个集合中

    解决方案

    1、计数排序

    1、初始化一个数组 数组的长度 就是 集合中元素的区间长度

    2、遍历集合,把每个元素放入数组中 寻找对应的下标位置,找出值,然后重新设置成+1的值

    3、按序遍历即可

    array[0] = 1, array[1] = 2, array[2] = 0, array[3] = 3,

    0 1 1 3 3 3

    2、改进需求:

    求出某个元素在不在这个数组(数据结构改良之前的集合)中

    array[5] = count if count > 0


    3、既然是判断存在不存在。

    所以结果其实就是一个状态 : 要么存在 要么不存在

    存在 : 1
    不存在: 0

    把int数组进化成 为位数组

    优势:把数组所要消耗的内存降低到原来的 1/32


    改良了之后这种数据结构: BitMap

    真正的结构: 一个位数组 + 一个hash函数

    4、BitMap再次进行进化

    解决的问题: BitMap 中非常容易出现 hash碰撞的问题

    咱们可以结合使用多个hash函数来搞定

    缺点: 存在一定的误判率

    1、如果这种数据结构(BloomFilter) 告诉你说你要验证的那个元素不在这个 BloomFilter 中
    那就表示 这个元素一定不在这个 BloomFilter 中


    2、如果它告诉你这个元素存在, 它告诉你的这个存在的结果 有可能是假的

    真正的组成:

    一个位数组 + 一组hash函数

    如果要做工程实现:不管是什么变种的BloomFilter, 都一定要实现两个方法:

    1、第一个方法是往BloomFilter中存入一个元素

    2、第二个方法是验证一个元素是否在这个BloomFilter 中

    误判率的估计:

    1、位数组的长度 m

    2、总元素的个数 n

    3、hash函数的个数 k

    hash函数的个数 并不是越多越好

    在误判率最低的情况下。 这三个参数应该满足的一个公式: k = 0.7 * m / n

  • 相关阅读:
    Get distinct count of rows in the DataSet
    单引号双引号的html转义符
    PETS Public English Test System
    Code 39 basics (39条形码原理)
    Index was outside the bounds of the array ,LocalReport.Render
    Thread was being aborted Errors
    Reportviewer Error: ASP.NET session has expired
    ReportDataSource 值不在预期的范围内
    .NET/FCL 2.0在Serialization方面的增强
    Perl像C一样强大,像awk、sed等脚本描述语言一样方便。
  • 原文地址:https://www.cnblogs.com/qingyunzong/p/8487180.html
Copyright © 2011-2022 走看看