• Hive基础知识概念


    Hive基础

    Hive 概念

    hive是用于解决海量结构化日志的数据统计工具,是基于hadoop的一个数仓工具,可以将结构化数据文件映射成一张表,并提供类SQL查询。
    hive本质:将HSQL转化为MR程序。
    1、hive数据源存储在本地HDFS
    2、hive分析数据底层的实现是MR
    3、执行程序在Yarn

    Hive优缺点

    优点

    1、采用类SQL语法,简单,容易上手,提供了快速开发能力。
    2、避免了写MR程序,减少开发人员学习成本
    3、HIVE执行延迟比较高,常用于数据分析等对实时要求不高的场合。
    4、Hive优势在处理大数据,对小规模数据没有优势,
    5、Hive支持用户自定义函数,用户可以根据自己的需求实现自己的函数。

    缺点

    1、Hive sql表达能力有限:1、迭代算法无法实现2、数据挖掘方面不擅长,高效率的算法因为mr数据处理流程的限制无法实现
    2、Hive效率低:1、hive自动生成的MR作业,通常情况下不够智能(需要优化)2、Hive调优比较困难,粒度比较粗

    Hive名词概念

    1、用户接口client:CLLI(Command-line-interface)、JDBC/ODBC(jdbc访问hive),WEBUI(浏览器访问Hive)

    2、元数据metastore:包括表名、表所属数据库(默认default)、表拥有者、列/分区字段,表类型(是否分区表),表数据所在目录等。元数据默认存储在自带的derby数据库,推荐用mysql

    3、驱动器driver:包括
    编译器 compiler:解析器、逻辑计划生成器、解析器 SQL Parser:将sql转化为抽象语法树AST TREE。这一步一般都用第三方工具库完成,比如antlr;对AST进行语法分析,比如表是否存在、字段是否存在、SQL语义是否有误。

    1、逻辑计划生成器(Physical Plan):将AST编译生成逻辑执行计划。
    2、优化器Query Optimizer:对逻辑计划进行优化
    3、执行器Execution:对逻辑计划转换为可执行的物理计划。
    4、查询分析器semanticAnalyzer:包含了对查询的所有优化操作以及查询分析
    
    • 1
    • 2
    • 3
    • 4

    hive底层执行流程

    1、client与hiveserver2建立连接,创建会话

    2、client提交DDL或者查询,转给driver处理

    3、driver内部通过parser对语句进行解析,校验语法是否正确,生成AST tree

    4、然后通过compiler编译器生成逻辑计划:

    1、semanticAnalyzer遍历AST TREE,进一步进行语义分析。然后和hive
    metastore通信获取元数据schema信息,抽象成query block。 2、逻辑生成器physical plan 会遍历query
    block,翻译成operatortree,这是未优化的逻辑计划。

    5、optimizer优化器会对逻辑计划operatorTree进行优化,例如谓词下推,常量值替换,列裁剪等,得到优化后的逻辑计划。

    6、semanticAnalyzer对逻辑计划进行处理,通过task compiler生成物理计划taskTree

    7、task compiler会对物理计划进行优化,然后根据底层不同引擎进行提交。

    hive 与RDBMS传统关系型数据库对比

    查询语言

    数据库采取了SQL查询,hive采取了类SQL 即HSQL

    数据更新

    hive是针对数据仓库设计,数据仓库是读多写少,因此hive不建议对数据的改写,所有数据都是加载的时候确定好的。但是数据的数据通常都是经常修改的,经常用update和insert into

    执行延迟

    hive查询表的时候因为没有索引,所以需要扫描表,所以延迟比较高。除此之外,因为hive是用MR框架去计算,所以延迟很高。数据库在处理小数据延迟很低,但是在大数据量上比不过并行计算的hive。

    数据规模

    hive是针对大数据,rdbms是针对小数据

    hive基本数据类型(原子数据类型)

    tinyint 相当java 的byte,长度是1byte有符号整数,例如20
    smalint java的short,长度是2byte的有符号整数,例如20
    int  java的int,4byte的有符号整数,例如20
    bigint  java的long,8byte的有符号整数,例如20
    boolean  java的boolean,java的布尔类型, 例如true或者false
    float 相当于java的float,单精度浮点,3.1415
    double  相当于java的double,双精度浮点,3.1415
    string  java的string,
    timestamp  时间类型
    binary		字节数组				
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    hive的集合数据类型

    Create  table  complex(
    tickdata0 array,
    tickdata MAP,
    tickdata1 struct<
            name: string,
            sex: string,
            age: int>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    STRUCT 描述:例如某列是xx列内容是{"name":"chen","sex":"nan","age":"18"}	可以通过xx.name获取name列
    MAP描述:键-值集合,例如xx列内容是MAP{"name":"chen","sex":"nan","age":"18"} 可以通过xx['name']获取name
    ARRAY描述:值集合,例如xx列内容是["chen","adasd","aqweqw","aqwe"] 可以通过xx[0]获取chen
    
    • 1
    • 2
    • 3

    类型转换

    hive的基本数据类型(原子数据类型)
    hive基础数据类型是可以进行隐性转换的,类似java的转换,byte小的可以转成大的,byte大的转小的要用cast。例如某表达式使用int类型,tinyint类型就会转换成int类型。但是int类型转换成tinyint类要用cast转换,例如cast(‘xx’ as int)

    隐性转换规则

    1、任何整数类型可以转换成一个byte范围更广的整数类型,例如tinyint转换成int
    2、所有整数类型、float、string 类型都能转换成double
    3、TINYINT、SMALLINT、INT都可以转换为FLOAT。
    4、boolean不能转换为任何类型

    DDL语言

    1、创建数据库(数据存在默认位置) create database database_name
    2、创建数据库,指定数据存放在HDFS某个位置 create database if not exists database_name location 'hdfs/dir/xxx.db’
    3、删除空数据库: drop database database_name
    4、数据库不为空,要用cascade 强制删除命令 drop database db_name cascade
    5、创建表

    create 【external】 table 【if not exists】 table_name(  
    col_1 string comment"字段1注释"
    ,col_2 string ccomment"字段2注释"
    ) comment "表注释"
    partition by(c0_1)  						--分区表
    clustered by (co_1,co_2) 					--分桶表
    sorted by (co_1 asc)						--对分桶表的字段排序
    row format delimit fields terminated by ',' --列分隔符
    collection items terminated by '_',  		--map struct 和array的分隔符
    may keys terminated by '_'   				--map中的key和value分隔符
    line terminated by '\n'  					--行分隔符 
    localtion  									---数据存储地点
    TBLPROPERTIES (property_name=property_value, ...)  --表的一些属性
    stored as file 								--以文件形式存储
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    导入数据 入hive表
    load data local inpath ‘xx/xxx/xx/xx’
    展示表信息
    desc tablename

    内部表

    默认创建的(没有external)表都是内部表,也叫管理表。这种表的数据存储位置由hive配置项管理hive.metastore.warehouse.dir管理,例如默认是/usr/hive/warehouse。
    当我们删除一个内部表的时候,hive也会删除这个表中的数据。

    创建普通内部表

    create

    create table if not exists xxx(
    id int , name string 
    )
    row format delimited fields terminated by '\t'
    stored as texfile 
    location '/usr/hive/warehouse/xx'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    create table as

    create table if not exists xxx as select id ,name from x
    
    • 1

    create table like (只创建结构)

    create table if not exists xxx like student
    
    • 1

    外部表

    外部表,hive只管理外部表的元数据,不管理外部表的数据文件。因此删除外部表的时候,只是删除元数据,不删除数据文件。
    #外部表使用场景
    每天收集的日志信息或者文件流入HDFS,然后建立外部表读取文件,然后在外部表的基础上做分析或者用外部表做增量处理,数据流入内部表。

    外部表创建

    create external table xx (
    id int, name string
    )
    row format delimited fields terminated by '\t'
    
    • 1
    • 2
    • 3
    • 4

    内部表和外部表互转

    查看表类型

    desc formatted student;
    
    • 1

    Table Type: MANAGED_TABLE (内部表)

    内部表转外部表

    alter table student set tblproperties('EXTERNAL' = 'TRUE')
    desc formatted student;
    
    • 1
    • 2

    Table Type: EXTERNAL_TABLE

    外部表转内部表

    alter table student set tblproperties('EXTERNAL'='TRUE')
    desc formatted student;
    
    • 1
    • 2

    Table Type: MANAGED_TABLE (内部表)

    hive常用操作

    重命名表

    alter table table_old_name rename to table_new_name;
    
    • 1

    增加/修改/替换列信息

    1、修改列名、数据类型、列注释、列所在顺序(first在第一列,after在aftercol后一列):

    alter table table_name change  old_col_name new_col_name column_type comment_col first/after col 
    
    • 1

    例如:

    after table test       change  col1          col2         STRING     '修改为信的注释'  after col3 
    
    • 1

    2、增加和替换列:ADD COLUMNS允许用户在当前列的末尾,分区列之前添加新的列,REPLACE COLUMNS允许用户更新列,更新的过程是先删除当前所有的列,然后在加入新的列。注:只有在使用native的SerDE时才可以这么做。

    alter table table_name add|replace COLUMN(col_name data_type [comment],...) 
    例如:
    alter table tesvt add column (col_new STRING comment '添加新列')
    alter table test replace column(eid INT,empid INT ,ename String,name String )
    
    • 1
    • 2
    • 3
    • 4

    表中载入数据

    1、load data [local] inpath 'xx/x/x/xx/x'[overwrite] into table student [partition(col = xxx)]
    load data:表示加载数据
    load data:表示加载数据
    inpath:表示加载数据的路径
    inpath:表示加载数据的路径
    into table:表示加载到哪张表
    student:表示具体的表
    partition:表示上传到指定分区
    
    2、insert into  table table_name value ('1','23231'),('2','xxx')
    3、insert into/overwrite  table table_name【partition (col = xx)】 select * from xx 
    4、create table if not exists table_name as select * from xx
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    导入导出数据

    1、导入数据
    import table table_name from 'xx/x//x//x/xx'
    2、查询结果导出本地
    insert overwrite local directory 'xx/xx/xx' select * from table_name;
    2、查询结果结构化导出本地 
    insert overwrite local directory 'xx/xx/xx' row format delimited fields terminated by '\t' select * from table_name 
    3、查询结果导出HDFS
    insert overwrite  directory 'xx/xx/xx' select * from table_name;
    4、Hadoop 命令导出本地表文件 
    dfs -get //user/hive/warehouse/student/student.txt /opt/module/datas/export/student3.txt;
    5、Hive shell 导出本地查询结果
    hive -e 'select * from table_name;' > /x/xx/xxx/xx.txt 
    6、export 导表到HDFS 
    export table default.studnet to 'usr/xxxx/xx/xx/'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    truncate

    内部表删除数据和元数据,外部表删除元数据不能删除数据

    基础查询

    分区 (distribute by)

    Distribute By: 在有些情况下,我们需要控制某个特定行应该到哪个reducer,通常是为了进行后续的聚集操作distribute by 子句可以做这件事。distribute by类似MR中partition(自定义分区),进行分区,结合sort by使用
    对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。
    例如:先按照部门编号分区,再按照员工编号降序排序。

     set mapreduce.job.reduces=3; 
    insert overwrite local directory '/opt/module/hive/datas/distribute-result' select * from emp distribute by deptno sort by empno desc;
    distribute by的分区规则是根据分区字段的hash码与reduce的个数进行模除后,余数相同的分到一个区。
    Hive要求DISTRIBUTE BY语句要写在SORT BY语句之前
    
    • 1
    • 2
    • 3
    • 4

    cluster by

    当disribute by 和sort by 相同时候,可以用cluster by 。但是cluster by 排序只能是升序,不能指定为降序。

     select * from emp cluster by deptno;=select * from emp distribute by deptno sort by deptno;
    
    • 1

    分区表

    分区表就是对应HDFS上文件系统的一个文件夹,该文件夹就是该分区所有的数据文件。hive中分区就是HDFS该表数据所在的文件夹在的一个子目录。把一个大的数据集分割成多个小的数据集。查询的时候通过where指定分区,查询效率会提升很多。

    创建分区表

    create table if not exists table_name (
    id INT, name STRING)
    partitioned by (day STRING)
    row format delimited fields terminated by '\t'
    
    • 1
    • 2
    • 3
    • 4

    加载数据到分区表某分区

    load data inpath 'xx/xx/xxx/xx.log' into table table_name partition(partition_col = 'xx')
    
    • 1

    查询分区表数据

    select * from A where dt = '20220728'
    
    • 1

    分区表增加/删除分区

    alter table table_name add/drop partition(partition_col = 'xx')(多个分区就空格再接partition(partition_col = 'xx'))
    
    • 1

    查看分区数

    show partitions table_name 
    
    • 1

    查看分区表结构

    desc formatted table_name

    二级分区

    二级分区建表

    create table if not exists table_name (
    id INT, name STRING)
    partitioned by (day STRING,hour STRING)
    row format delimited fields terminated by '\t'
    
    • 1
    • 2
    • 3
    • 4

    加载数据和查询数据

    参考单分区表

    动态分区

    开启参数设置后,会根据设定好的分区字段自动取值分区。

    开启动态分区

    hive.exec.dynamic.partition = true ;
    
    • 1

    设置为非严格模式(动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。)

    hive.exec.dynamic.partition.mode=nonstrict
    
    • 1

    在所有执行MR的机器上设置最大动态分区数,默认1000

    hive.exec.max.dynamic.partitions = 1000;
    
    • 1

    在每个执行MR的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。比如:源数据中包含了一年的数据,即day字段有365个值,那么该参数就需要设置成大于365,如果使用默认值100,则会报错。

    hive.exec.max.dynamic.partitions.pernode=100
    
    • 1

    整个MR Job中,最大可以创建多少个HDFS文件。默认100000

    hive.exec.max.created.files=100000
    
    • 1

    当有空分区生成时,是否抛出异常。一般不需要设置。默认false

    hive.error.on.empty.partition=false
    
    • 1

    分桶表

    分桶表是让某一列数据,让这一列数据按照哈希取模的方式进行随机、均匀的发送到各个同文件中。

    抽样查询

    tablesample(bucket x out of y on col_name)
    将某列分成y个桶,然后选第x个桶
    select * from stu_buck tablesample(bucket 1 out of 4 on id);
    
    • 1
    • 2
    • 3

    随机抽取20个

    select *  from table_name order by rand() limit 20 ;
    
    • 1

    常用内置函数

    NVL

    判断字段是否为null,为null则用另一个值代替。

    select comm, nvl(comm,mgr) from emp;
    
    • 1

    case when … then … else … end

    判断字段逻辑

    um(case sex when '男' then 1 else 0 end) male_count
    
    • 1

    行转列

    concat(col/string,col/string) 将两个字符串或者字段连接。例如concat(id,'-',name) 
    concat_ws(separator, str1, str2,...)  separator 是分隔符,用分隔符将str1,str2...连接起来。str1,str2...也可以是array
    
    • 1
    • 2

    concat_set(col) 将某一列的值去重,然后汇总为一个array类型
    孙悟空 白羊座 A
    大海 射手座 A
    宋宋 白羊座 B
    猪八戒 白羊座 A
    凤姐 射手座 A
    苍老师 白羊座 B
    ||
    射手座,A 大海|凤姐
    白羊座,A 孙悟空|猪八戒
    白羊座,B 宋宋|苍老师

    SELECT t1.c_b , CONCAT_WS("|",collect_set(t1.name))
    FROM (
    SELECT NAME ,CONCAT_WS(',',constellation,blood_type) c_b
    FROM person_info
    )t1 
    GROUP BY t1.c_b
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    列转行

    explode(col) :将hive中复杂的array或者map分成多行。
    lateral view:用于和split, explode等UDTF一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合。
    
    • 1
    • 2

    例如:
    [atguigu@hadoop102 datas]$ vi movie_info.txt
    《疑犯追踪》 悬疑,动作,科幻,剧情
    《Lie to me》 悬疑,警匪,动作,心理,剧情
    《战狼2》 战争,动作,灾难
    ||
    《疑犯追踪》 悬疑
    《疑犯追踪》 动作
    《疑犯追踪》 科幻
    《疑犯追踪》 剧情
    《Lie to me》 悬疑
    《Lie to me》 警匪
    《Lie to me》 动作
    《Lie to me》 心理
    《Lie to me》 剧情
    《战狼2》 战争
    《战狼2》 动作
    《战狼2》 灾难

    select movie,category_name 
    from movie_info 
    lateral view explode (split(category,',')) movie_info_tmp  as category_name;
    
    • 1
    • 2
    • 3

    开窗函数(窗口函数)

    over():指定分析函数的数据窗口大小,这个数据窗口大小可能随着行的变化而变化。
    current row : 当前行
    n preceding :往前n行 
    n following: 往后n行 
    unbounded : 起点 
    unbounded preceding : 表示 从前面的起点 
    unbounded following : 标识 到后面的终点
    LAG(col,n,default_value) 往前第n行数据 
    LEAD(col,n,default_value) 往后第n行数据
    NTILE(n):把有序窗口的行发送到指定的数据组中,各个组有编号,从1开始。NTILE 返回此行所属的组的编号 。 (分成n组,组号是从1到..n,返回编号)
    rows:根据排序后的行数处理 ,例如rows between 100 preceding and 200  表示取 前100行和后100行 
    range:根据排序后的值 处理,例如 range between 100 preceding and 200  表示取 大于且等于100 的数 到 小于等于200的数。
    聚合函数sum,max,min + over() 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    select name,orderate,cost,
    sum(cost) over(), -- 把所有行相加
    sum(cost) over(partition by name) -- 按name 分组,然后组内全部行sum
    sum(cost) over(partition by name order by orderdate), -- 按name分组,组内按 orderdate排序,然后组内全部sum
    sum(cost) over(partition by name order ny orderdate rows between unbounded preceding and current row ) -- 按name分组,组内按 orderdate排序,然后取组内第0行(起点)到当前行的cost进行sum相加
    sum(cost) over(partition by name order ny orderdate rows between current row and undounded following ) -- 按name分组,组内按 orderdate排序,然后取当前行到最后一行的cost进行sum相加
    sum(cost) over(partition by name order ny orderdate range between unbounded preceding and current row ) -- 按name分组,组内按 orderdate排序,然后取组内小于当前行的cost和大于第0行cost的cost进行sum相加
    sum(cost) over(partition by name order ny orderdate rows between 1 preceding and current row ) -- 按name分组,组内按 orderdate排序,然后取当前行的cost和前一行的cost进行sum相加
    sum(cost) over(partition by name order ny orderdate rows between 1 preceding and 1 following ) -- 按name分组,组内按 orderdate排序,然后取当前行的cost和前一行的cost以及后一行的cost进行sum相加
    from business;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    查看顾客上次购买时间

    select name, orderdate, cost,
    lag(orderdate,1,'1900-01-01') over (partition by name order by orderdate) as time2
    from business;
    
    • 1
    • 2
    • 3

    查询前20%时间的订单信息

    select * from(
    select name, orderdate, cost,
    ntile(5) over(order by orderdate)as nt
    from business 
    )a
    where nt=1; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    RANK

    rank() 排序的时候会重复,总数不会变
    DENSE_RANK() 排序的时候会重复,总数会变少
    row_number() 排序不会重复

    rank() over(partition by subject order by score desc) rp,
    dense_rank() over(partition by subject order by score desc) drp,
    row_number() over(partition by subject order by score desc) rmp
    
    • 1
    • 2
    • 3

    score rk dr rn
    84 1 1 1
    84 1 1 2
    78 3 2 3
    68 4 3 4

    常用函数

    日期函数

    unix_timestamp 返回当前时间或者指定时间的时间戳

    select unix_timestamp;
    select unix_timestamp('2022-12-18','yyyy-MM-dd');
    
    • 1
    • 2

    from_unixtime 将时间戳转换为日期模式

    select from_unixtime(1603843200)
    select from_unixtime(unix_timestamp('2022-12-18:12:13 : asd','yyyy-MM-dd HH:mm:ss'))
    
    • 1
    • 2

    current_date和current_timestamp;

    current_date 当前日期 yyyy-MM-dd
    current_timestamp 当前日期+时间 yyyy-MM-dd HH:mm:ss
    
    • 1
    • 2

    to_date 将日期+时间格式的数据抽取出日期

    select to_date('2022-08-02 12:12:12') 
    
    • 1

    year/month/day/hour/minute/second 获取对应时间的年、月、日、小时、分、秒

    select year/month/day/hour/minute/second(current_date);
    select year/month/day/hour/minute/second(current_timestamp); 
    
    • 1
    • 2

    weekofyear/dayofmonth 一年中的第几周 或者是一个月中的第几天

    select weekofyear/dayofmonth(current_date)
    
    • 1

    months_between 两个日期之间的月份

    select months_between('2022-04-01','2022-10-28');
    
    • 1

    add_months 日期加减月

    select add_months(current_date,-3);
    
    • 1

    datediff 两个日期相差天数

    select datediff('2020-11-04','2020-10-28');
    
    • 1

    date_add 日期加天数(负数实现减)

    select date_add(current_date,-3);
    
    • 1

    date_sub 日期减天数(负数实现加)

    select date_sub(current_date,3);
    
    • 1

    last_day 当月最后一天

    select last_day(current_date);
    
    • 1

    date_format(); 格式化日期

    select date_format(current_date,'yyyydMM/dd HH:mm:ss');
    
    • 1

    常用取整函数

    round 四舍五入

     select round(3.54);
    
    • 1

    ceil 向上取整 只要有小数就加1

    select ceil(3.14);
    select ceil(3.54);
    
    • 1
    • 2

    floor 向下取整,不计算小数,只取整数部分

    select floor(3.14);
    select floor(3.54)
    
    • 1
    • 2

    字符串函数

    upper/lower 大小写

    select upper/lower('xx')
    
    • 1

    length 长度

    select length ('xx')
    
    • 1

    trim 前后去空格

    select trim('  aasd  ')
    
    • 1

    lpad/rpad 向左/右补齐,通过指定字符串补到指定长度

    select lpad/rpad('aasd',10,'c')
    
    • 1

    regexp_replace 使用正则表达式匹配目标字符串,匹配成功后进行替换

    SELECT regexp_replace('2020/10/25', '/', '-');
    
    • 1

    substr() 截取字符串

    substr(string str, int start ) 截取 str字符串 坐标start 后的字符串(下坐标是0开始)
    substr(string str, int start, int len)  截取 str字符串 坐标start 后的字符串,截取长度为len
    
    • 1
    • 2

    concat 拼接字符串

    concat('a','-','b')
    
    • 1

    判断是否空值

    nvl(val1,val2) 判断是否空值空

    val1字段非空null,则返回val1,如果为空,则返回val2

    coalesce(expr,val1,val2,…valN)

    判断expr是否为空,如果第一个为空,则返回val1,第二个为空返回val2…第N个空值,返回valN

    json 解析函数

    json_tupe 解析json

    select json_tupe(json,'id','name') as (id,name) from json_test ;
    
    • 1

    get_json_object()

    get_json_object 函数第一个写json对象变量,第二个参数用$表示json变量表示,用.或[]读取对象或者数组
    select get_json_object(content,'$.姓名') as name
    from json_Test;
    
    • 1
    • 2
    • 3

    自定义函数

    UDF: 一进一出(一个参数进来,一个结果返回)
    UDAF:多进一出
    UDTF:一进多出

    UDF流程 (粗略)

    1、创建maven项目
    2、导入依赖
    3、继承UDF类 GenericUDF
    4、重写三个方法:1、initialize 初始化,一般判断参数,UDF参数限定为1个 2、执行计算evaluate,这里写计算逻辑。3、返回执行计划顺序getDisplayString,一般是空值“”
    5、打包编译
    6、添加到hive类路径
    7、创建临时函数 create temporary function my_len as “com.atguigu.udf.MyUDF”;
    8、测试

    具体代码如下:

    public class MyUDF extends GenericUDF {
        @Override
        public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {
            if (objectInspectors.length != 1){
                throw new UDFArgumentException("参数个数不为1");
            }
            return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
        }
    
        @Override
        public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
            String input = deferredObjects[0].get().toString();
            if (input ==null){
                return 0;
            }
            return input.length();
        }
    
        @Override
        public String getDisplayString(String[] strings) {
            return "";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    存储

    HIVE存储格式:textfile,sequencefile,orc,parquet.
    但总的来说,分两类,一类是行存储,一类是列存储,但是他们的逻辑板展示形式是一样的(结果展示一样,底层存储不一样)。
    逻辑表:
    a b c
    a1 b1 c1
    a2 b2 c2
    a3 b3 c4

    行存储逻辑:
    a1b1c1 a2b2c2 a3b3c3
    列存储逻辑
    a1 a2 a3 a4… b1b2b3b4… c1c2c3c4

    行存储

    使用行存储的一般是texfile和sequencefile 。

    行存储特点:
    写入数据的时候,一行一行写入保存,查询满足条件的某一行数据的时候(多字段或者整行),只需要找到一个值即可,其他同行的数据就在隔壁。此时查询速度更快。
    因为同行数据都在隔壁,所以insert和update操作更快。

    列存储
    使用列存储的一般是orc和parquet

    列存储特点

    把每一个字段的数据聚集存储,在查询少数字段的时候,查询速度快。update和insert会很慢。

    textfile

    默认格式,数据不压缩。磁盘开销大,数据解析开销大,可以结果Gzip、Bzip2等压缩使用。但是使用Gzip等压缩格式,hive不会对数据进行切分,所以无法对数据进行操作。

    ORC格式

    每个orc由1个或者多个stripe组成,每个stripe一般为hdfs的一个块大小,每个stripe包含多条信息记录,这些记录单独存储,对应parquet中的row group。
    每个strip分三部分,index_Data,row_data,stripe footer.

    index_Data:轻量级的index。默认每隔1w数据就做一个索引,记录某行的各字段的offset。
    row data : 存的是具体数据,先取部分行,再对行按列进行存储,对每个列都进行了编号,分成多个stream进行存储。
    stripe footer: 存储的是stream的类型,长度等信息。
    
    • 1
    • 2
    • 3

    同时每个文件都会有一个file footer,这里存的是stripe的行数,每个column的数据类型信息等。
    每个文件尾部由一个post stript文件,记录了整个文件的压缩类型以及file footer的长度信息等。
    读取文件的时候,先seek到文件尾端读取post stript,里面解析了file footer的长度,再读取file footer,从里面解析各个stripe的信息,再读取stripe,即从后往前读。

    parquet

    parque是列式存储,以二进制的方式存储为parquet文件,所以是不能直接读取。 该文件包括该文件的数据和元数据,所以parquet是自解析。
    parquet文件有三个概念:
    1、行组(row group ):每一行组包括一定的行数,一个hdfs文件中至少存储1个行组,类似orc的stripe。
    2、列块(column chunk):在一个行组中的一个列块中,行组中的所有列都是连续存储在这个列块的,一个列块中的值都是相同类型的。不同的列块可能使用不同的算法压缩。
    3、页(page)每一个列块划分多个页,一页是最小编码,在同一个列块中的不同页可能使用不同的编码方式。page有三种类型:数据页(存储当前行组中该列的值)、字典页(该值的编码字典)、和索引列(该行组下该列的索引)

    通常情况下,存储parquet数据的时候会按照hdfs的block大小设置行组的大小,因为一个mapper能处理任务数据的最小是一个block,所以可以把每一个行组交给一个mapped任务处理,增大任务执行并行度。

    压缩

    压缩算法:分无法切分和可切分的压缩
    无法切分的压缩算法:snappy,Gzip

  • 相关阅读:
    数据库学习笔记——DML
    游戏引擎分层简介
    设计模式之【策略模式】
    数据结构与算法之图: Leetcode 133. 克隆图 (Typescript版)
    1555. 银行账户概要
    [SQL开发笔记]SQL 别名:为表名称或列名称指定别名
    玩转Vue3全家桶09丨动画:Vue中如何实现动画效果?
    爬虫第二次笔记 解编码 使用get请求方式和post请求方式
    手撕SparkSQL五大JOIN的底层机制
    云计算发展的十年IaaS、Paas、SaaS、APaaS
  • 原文地址:https://blog.csdn.net/weixin_43859562/article/details/126232033