• Hadoop——Hive的序列化,文件存储,分桶和分区


    一、序列化

      1.正则表达式 创建表

    //在加载文件时可以通过正则表达式来区分字段,字段名必须和文件中的字段名一致
    create table reg_table(
         id int,
         name string
    ) row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe'
    with serdeproperties('input.regex'="id=(.*),name=(.*)"); //.代表单个字符 *  0~N次
    //加载数据
    load data local inpath '/usr/local/hive_data/regexp_test'  overwrite into table reg_table;

      2.通过json文件创建表

    //创建user用户数据的指定JSON的序列化器
    create  table user_json_textfile(
          uid string,
          phone string,
          addr string 
    ) row format serde 'org.apache.hive.hcatalog.data.JsonSerDe';//这个类名是固定的
    //加载数据
    load data local inpath '/usr/local/xl_project/user/user_login_info.json'  overwrite into table user_json_textfile;

      需要注意的问题: 每行必须是一个完整的JSON,一个JSON串不能跨 越多行,原因是Hadoop是依赖换行符分割文件的。

            创建数据表:(数据表中的列名与JSON中的KEY保持一致

      3.什么是SerDe:

        SerDe是“Serializer and Deserializer”(序列化器和反序列化器的缩写)

        Hive使用SerDe读写表的行数据

        HDFS FILES-->InputFileFormat--><key,value>-->Deserializer--> Row Object    

        Row Object-->Serializer--><key,value>-->OutputFileFormat-->HDFS FILES

        注意,“key”部分在读时被忽略,在写时始终是常量。基本上,row对象存储在value中

        序列化是对象转换为字节序列的过程 反序列化是字节序列恢复为对象的过程 对象的序列化主要有两种用途:对象的持久化,即把对象转换成字节序列后保存到文件中;对象数据的网络传送。 除了上面两点, hive的序列化的作用还包括:Hive的反序列化是对key/value反序列化成hive table的每个列的值。Hive可以方便的将数据加载到表中而不需要对数据进行转换,这样在处理海量数据时可以节省大量的时间。

      SerDe说明hive如何去处理一条记录,包括Serialize/Deserilize两个功能, Serialize把hive使用的java object转换成能写入hdfs的字节序列,或者其他系统能识别的流文件。Deserilize把字符串或者二进制流转换成hive能识别的java object对象。比如:select语句会用到Serialize对象, 把hdfs数据解析出来;insert语句会使用Deserilize,数据写入hdfs系统,需要把数据序列化。

      Hive的一个原则是Hive不拥有HDFS文件格式。用户应该能够使用其他工具直接读取Hive表的HDFS文件或者使用其他工具直接写那些可以加载到外部表中的HDFS文件。

    二、文件存储

      1.文件格式的分类

         hive文件的存储格式主要分为以下四种:  TEXTFILE、SEQUENCEFILE、RCFILE、ORCFILE    

            其中TEXTFILE为默认格式,建表时不指定默认为这个格式,导入数据时直接把数据文  COPY到HDFS上不进行处理。

            SEQUENCEFILERCFILEORCFILE格式的表不能直接从本地文件导入数据,数据要  先导入到textfile格式的表中,然后再从表中用insert导入SequenceFile,RcFile和  OrcFile中。

      2.TEXTFILE格式

             默认格式,数据不做压缩,磁盘开销大,数据解析开销大。

             可结合Gzip、Bzip2使用(系统自动检查,执行查询时解压),但使用这种方式, hive默认对数据不会切分,从而无法对数据进行并行操作。

             在反序列化的过程中,必须逐个字符判断是不是分隔符或行终止符,因此反序列化 开销最大。

      3.SEQUENCEFILE格式

              SequenceFile是Hadoop API 提供的一种二进制文件,它将数据以二进制的形 式序列化到文件中。这种二进制文件内部使用Hadoop 的标准的Writable 接口 实现序列化和反序列化。它Hadoop API中的MapFile 是互相兼容的。Hive 中 SequenceFile 继承自Hadoop API 的SequenceFile,不过它的key为空,使 value 存放实际的值, 这样是为了避免MR 在运行map 阶段的排序过程。

      4.RCFILE

        是一种行列存储相结合的存储方式。首先,其将数据按行分块,保证同一个record在一个块上,避免读一个记录需要读取多个block。其次,块数据列式存储,有利于数据压缩和快速的列存取。

      5.ORCFILE格式

          Orcfile(Optimized Row Columnar)是hive 0.11版里引入的新的存储格式, 对之前的RCFile存储格式的优化可以看到每个Orc文件由1个或多个stripe(线条)组成,每个stripe250MB大小, 这个Stripe实际相当于之前的rcfile里的RowGroup概念,不过大小由 4MB->250MB, 这样应该能提升顺序读的吞吐率。每个Stripe里有三部分组成,分 别是IndexData,Row Data,Stripe Footer:

      1Index Data:一个轻量级的index,默认是每隔1W行做一个索引。这里做的索引只是记录某行的各字段在Row Data中的offset

           2Row Data:存的是具体的数据,和RCfile一样,先取部分行,然后对这些行按列进行存储。与RCfile不同的地方在于每个列进行了编码,分成多个Stream来存储

           3Stripe Footer:存的是各个Stream的类型,长度等信息。

    每个文件有一个File Footer,这里面存的是每个Stripe的行数,每个Column的数据类型信息等;每个文件的尾部是一个PostScript,这里面记录了整个文件的压缩类型以及FileFooter的长度信息等。在读取文件时,会seek到文件尾部读PostScript,从里面解析到File Footer长度,再读FileFooter,从里面解析到各个Stripe信息,再读各个Stripe,即从后往前读

       6.总结   

        textfile 存储空间消耗比较大,并且压缩的text 无法分割和合并 查询的效率最低,可以直接存储,加载数据的速度最高

        sequencefile 存储空间消耗最大,压缩的文件可以分割和合并 需要通过text文件 转化来加载

        rcfile 存储空间小,查询的效率高 ,需要通过text文件转化来加载,加载的速度最低

        orcfile 存储空间最小,查询的最高 ,需要通过text文件转化来加载,加载的速度最低

    三、分区

      1.什么是分区

        hive开发中,在存储数据时,为了更快地查询数据和更好地管理数据,都会对hive 表中数据进行分区存储。所谓的分区,在hive表中体现的是多了一个字段。而在底 层文件存储系统中,比如HDFS上,分区则是一个文件夹,或者说是一个文件目录, 不同的分区,就是数据存放在根目录下的不同子目录里,可以通过show partitions查看。

        查看分区

    show partitions

      2.动态和静态分区

        创建分区(无论动态还是静态分区创建语句是不变的只有插入语句变化)

    //创建一个按照年份分区的表 
    create table test_partition (
    id string comment 'ID', 
    name string comment '名字'
    ) comment '测试分区'
     partitioned by (year int comment '')
     ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' 

        静态分区

    #insert语句:
    insert into table test_partition partition(year=2018) values ('001','张三');
    insert into table test_partition partition(year=2018) values ('001','张三');
    insert into table test_partition partition(year=2018) values ('002','李四');
    #load语句
    load data local inpath '/usr/local/part_test' into table test_partition partition (year =2018);
    load data local inpath '/usr/local/part_test' into table test_partition partition (year =2018);
    load data local inpath '/usr/local/part_test' into table test_partition partition (year =2017);
    //要加载的文件为
    002,李四
    003,王五
    003,王五

      动态分区

     //动态分区默认不开启,需要使用下列语句开启:
    set hive.exec.dynamic.partition.mode=nonstrict;#需退出hive,重新进入执行
               
    //  insert语句数据插入:
    insert into table test_partition partition(year) values ('001','张三',2016);
              
    //load语句插入:
    load data local inpath '/usr/local/part_test' into table test_partition partition (year);
    FAILED: NullPointerException null 报错
            
    
    //在这里没有为分区字段赋任何值,所以会抛出NullPointerException这样的异常,可以使用下面的办法解决:
                       
     创建一张没有分区的表:
    create table test (
    id string comment 'ID', 
    name string comment '名字',
    year int comment ''
    )comment '测试'
    ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' ;
                                  
    //将数据载入到没有分区的表中:
    load data local inpath '/usr/local/part_test' into table test;
                       
    // 然后从表test,动态分区的插入到test_partition中:
    insert into table test_partition partition(year) select * from test;
                       

      删除修改分区

    1、修改分区
                 alter table 表名 partition (分区列=分区值) set location 新分区地址;     
                   注意:此时原先的分区文件夹仍存在,但是在往分区添加数据时,只会添加到新的分区目录。
    2、删除分区
                alter table 表名 drop partition(分区列=分区值);

       静态分区和动态分区的区别   

        静态分区和动态分区的主要区别在与:

                 静态分区中的数据需要手动指定,当分区列的值有很多的情况下,就要不停的 使用INSERT语句进行显示指定。

                 动态分区:可通过SELECT语句实现数据的一次性导入,而且可以通过数据源中 不同分区列的值动态的生成相应的目录,并把对应的数据写入对应的目录中。

               简单的来说:静态分区是给与固定的值,而动态分区可实现分区数据的动态指定

    四、分桶

      1.什么是分桶

        分桶是相对分区进行更细粒度的划分。分桶将整个数据内容安装某列属性值得 hash值进行区分,如要安装name属性分为3个桶,就是对name属性值的hash 值对3取摸,按照取模结果对数据分桶。如取模结果为0的数据记录存放到一个文 件,取模为1的数据存放到一个文件,取模为2的数据存放到一个文件。(放置分桶的内容不能自定义,只能通过hashcode的值来进行)

      2.分桶和分区的区别

        分区针对的是数据存储路径(HDFS中表现出来的便是文件夹),分桶针对的是数据文件。分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区,特别是当数据要确定合适的划分大小的时候,分区便不再合适。分桶是将数据集分解成更容易管理的若干部分的技术。

      3.怎么用分桶

    #创建一个存有id和name的表
    create table student_bck
    (id int, name string)
    clustered by (id) into 3 buckets #创建三个分桶
    row format delimited fields terminated by ",";//设置加载文件的字段分隔符
    #向桶中插入数据
    insert overwrite table student_bck select id,name from test; //insert将原有表中的数据加载到分桶的表中
    #查看桶中的数据
    select * from student_bck tablesample (bucket x out of y on id);//x表示从哪个桶(x-1)开始,y代表分几个桶,也可以理解分x为分子,y为分母,及将表分为y份(桶),取第x份(桶)

    为何取出王五的记录,是因为王五的记录为3,取模桶数余数为0,所以 理应放置在第一个桶中。当X=1时代表获取的是第一个桶的数据。

    
    


      

      

  • 相关阅读:
    题解——洛谷P3812【模板】线性基
    题解——洛谷P2781 传教(线段树)
    题解——洛谷P1962 斐波那契数列(矩阵乘法)
    题解——洛谷P3390 【模板】矩阵快速幂(矩阵乘法)
    题解——牛客网OI赛制测试赛2
    题解——code[vs] 1506 传话(传递闭包)
    题解——Codeforces Round #508 (Div. 2) T3 (贪心)
    题解——Codeforces Round #508 (Div. 2) T2 (构造)
    题解——Codeforces Round #508 (Div. 2) T1 (模拟)
    题解——Codeforces Round #507 (based on Olympiad of Metropolises) T2(模拟)
  • 原文地址:https://www.cnblogs.com/wuxuewei/p/11469175.html
Copyright © 2020-2023  润新知