Hive详解(3)

Hive

数据类型

struct类型

  1. struct:结构体,对应了Java中的对象,实际上是将数据以json形式来进行存储和处理

  2. 案例

    1. 原始数据

      复制代码
      a tom,19,male amy,18,female
      b bob,18,male john,18,male
      c lucy,19,female lily,19,female
      d henry,18,male david,19,male
    2. 案例

      复制代码
      -- 建表
      create table groups (
          group_id string,
          mem_a    struct<name:string, age:int, gender:string>,
          mem_b    struct<name:string, age:int, gender:string>
      ) row format delimited
          fields terminated by ' '
          collection items terminated by ',';
      -- 加载数据
      load data local inpath '/opt/hive_data/infos' into table groups;
      -- 查询数据
      select * from groups;
      -- 获取成员a的信息
      select mem_a from groups;
      -- 获取成员a的名字
      select mem_a.name from groups;

运算符和函数

概述

  1. 在Hive中,提供了非常丰富的运算符和函数,用于对数据进行处理和分析。在Hive中,运算符和函数可以归为一类

  2. 如果需要查看Hive中所有的函数,可以通过

    复制代码
    show functions;
  3. 如果想要查看某一个函数的描述,可以使用

    复制代码
    -- 简略描述
    desc function sum;
    -- 详细描述
    desc function extended sum;
  4. 在Hive中,还允许用户自定义函数

  5. 在Hive中,函数必须结合其他的关键字来构成语句!

入门案例

  1. 案例一:给定字符串表示日期,例如'2024-03-25',从获取年份

    复制代码
    -- 方式一:以-拆分字符串,获取数组的第一位,将字符串转化为整数类型
    select cast(split('2024-03-25', '-')[0] as int);
    -- 方式二:正则表达式-捕获组
    select cast(regexp_extract('2024-03-25', '(.*)-(.*)-(.*)', 1) as int);
    -- 方式三:提供了year函数,直接用于提取年份,要求年月日之间必须用-隔开
    select year('2024-03-25');
  2. 案例一:给定字符串表示日期,例如'2024/03/25',从获取年份

    复制代码
    -- 方式一
    select cast(split('2024/03/25', '/')[0] as int);
    -- 方式二
    select cast(regexp_extract('2024/03/25', '(.*)/(.*)/(.*)', 1) as int);
    -- 方式三:先将/替换为-,再利用year函数来提取
    select year(regexp_replace('2024/03/25', '/', '-'));

常用函数

nvl函数
  1. nvl(v1, v2):判断v1的值是否为null,如果v1的值不是null,那么返回v1,如果v1的值是null,那么返回v2

  2. 案例

    1. 原始数据

      复制代码
      1 Adair 800
      2 David 600
      3 Danny 1000
      4 Ben 500
      5 Grace
      6 Cathy 700
      7 Kite
      8 Will 600
      9 Thomas 800
      10 Tony 1000
    2. 案例

      复制代码
      -- 建表
      create table rewards (
          id     int,
          name   string,
          reward double
      ) row format delimited fields terminated by ' ';
      -- 加载数据
      load data local inpath '/opt/hive_data/rewards' into table rewards;
      -- 查询数据
      select * from rewards;
      -- 计算每一个人平均发到的奖金是多少
      -- avg属于聚合函数,所有的聚合函数在遇到null的时候自动跳过不计算
      -- select avg(reward) from rewards;
      select avg(if(reward is not null, reward, 0.0)) from rewards;
      -- nvl
      select avg(nvl(reward, 0)) from rewards;
case-when函数
  1. 类似于Java中的switch-case结构,是对不同的情况进行选择

  2. 案例

    1. 原始数据

      复制代码
      1 bob 财务 男
      2 bruce 技术 男
      3 cindy 技术 女
      4 david 财务 男
      5 eden 财务 男
      6 frank 财务 男
      7 grace 技术 女
      8 henry 技术 男
      9 iran 技术 男
      10 jane 财务 女
      11 kathy 财务 女
      12 lily 技术 女
    2. 案例

      复制代码
      -- 建表
      create table employers (
          id         int,
          name       string,
          department string,
          gender     string
      ) row format delimited fields terminated by ' ';
      -- 加载数据
      load data local inpath '/opt/hive_data/employers' into table employers;
      -- 查询数据
      select *
      from employers;
      -- 需求:统计每一个部门的男生和女生人数
      -- 方式一:sum(if())
      select department                   as `部门`,
             sum(if(gender = '男', 1, 0)) as `男`,
             sum(if(gender = '女', 1, 0)) as `女`
      from employers
      group by department;
      -- 方式:sum(case-when)
      select department                                   as `部门`,
             sum(case gender when '男' then 1 else 0 end) as `男`,
             sum(case gender when '女' then 1 else 0 end) as `女`
      from employers
      group by department;
explode函数
  1. explode在使用的时候,需要传入一个数组或者是映射类型的参数。如果传入的是数组,那么会将数组中的每一个元素拆分成单独的一行构成一列数据;如果传入的是映射,那么会将映射的键和值拆分成两列

  2. 案例:单词统计

    复制代码
    -- 创建目录
    dfs -mkdir /words
    -- 将文件复制到这个目录下
    dfs -cp /txt/words.txt /words
    -- 查看数据
    dfs -ls /words
    -- 建表
    -- 注意:数据在HDFS上已经存在,所以应该建立外部表
    create external table words (
        line array<string>
    ) row format delimited
        collection items terminated by ' '
        location '/words';
    -- 查询数据
    select * from words;
    -- 需求:统计这个文件中每一个单词出现的次数
    -- 思路
    -- 第一步:先将数组中的元素转成一列
    select explode(line)
    from words;
    -- 第二步:统计单词出现的次数
    -- 基本结构:select x, count(x) from tableName group by x;
    select w, count(w) from (
      select explode(line) as w from words
    ) t1 group by w;
列转行
  1. 列转行,顾名思义,指的是将一列的数据拆分成多行数据。在列转行的过程中,最重要的函数就是explode

  2. 案例

    1. 原始数据

      复制代码
      沙丘2 剧情/动作/科幻/冒险
      被我弄丢的你 剧情/爱情
      堡垒 剧情/悬疑/历史
      热辣滚烫 剧情/喜剧
      新威龙杀阵 动作/惊悚
      周处除三害 动作/犯罪
    2. 案例

      复制代码
      -- 建表
      create table movies (
          name  string,       -- 电影名
          kinds array<string> -- 电影类型
      ) row format delimited
          fields terminated by ' '
          collection items terminated by '/';
      -- 加载数据
      load data local inpath '/opt/hive_data/movies' into table movies;
      -- 查询数据
      select * from movies;
      -- 需求:查询所有的动作片
      -- lateral view function(ex) tableAlias as colAlias
      -- 列转行,又称之为'炸列'
      select name, k
      from movies lateral view explode(kinds) ks as k
      where k = '动作';
  3. 案例二

    1. 原始数据

      复制代码
      bob 开朗,活泼   打游戏,打篮球
      david   开朗,幽默   看电影,打游戏
      lucy    大方,开朗   看电影,听音乐
      jack    内向,大方   听音乐,打游戏
    2. 案例

      复制代码
      -- 建表
      create table persons (
          name       string,        -- 姓名
          characters array<string>, -- 性格
          hobbies    array<string>  -- 爱好
      ) row format delimited
          fields terminated by '\t'
          collection items terminated by ',';
      -- 加载数据
      load data local inpath '/opt/hive_data/persons' into table persons;
      -- 查询数据
      select * from persons;
      -- 获取性格开朗且喜欢打游戏的人
      select name, c, h
      from persons
               lateral view explode(characters) cs as c
               lateral view explode(hobbies) hs as h
      where c = '开朗'
        and h = '打游戏';
行转列
  1. 行转列,将多行的数据合并成一列

  2. 案例

    复制代码
    select * from students_tmp;
    -- 将同年级同班级的学生放到一起
    -- collect_list和collect_set将数据合并到一个数组中
    -- 不同的地方在于,collect_list允许有重复数据,但是collect_set不允许元素重复
    -- concat_ws(符号,元素),表示将后边的元素之间用指定的符号进行拼接,拼接成一个字符串
    select grade                               as `年级`,
           class                               as `班级`,
           concat_ws(', ', collect_list(name)) as `学生`
    from students_tmp
    group by grade, class;

分类

  1. 除了窗口函数以外,将其他的函数分为了3类:UDF、UDAF和UDTF函数

  2. UDF:User Defined Function,用户定义函数,特点是一进一出,即用户输入一行数据会获取到一行结果,例如yearsplitconcat_wsregexp_replaceregexp_extract

  3. UDAF:User Defined Aggregation Function,用户定义聚合函数,特点是多进一出,即用户输入多行数据会获取到一行结果,例如sumavgcountmaxmincollect_listcollect_set

  4. UDTF:User Defined Table-generated Function,用户定义表生成函数,特点是一进多出,即用户输入一行数据能够获取到多行结果,例如explodeinlinestack

  5. 在Hive中,大部分函数都是UDF函数

自定义函数

  1. 自定义UDF:需要定义一个类,Hive1.x和Hive2.x继承UDF类,但是Hive3.x,UDF类已经过时,所以需要继承GenericUDF

  2. 自定义UDTF:需要定义一个类,继承GenericUDTF

  3. 打成jar包,然后上传到HDFS上

  4. 在Hive中创建函数

    复制代码
    -- 基本语法
    create function 函数名
        as '包名.类名'
        using jar '在HDFS上的存储路径';
    -- UDF
    create function indexOf
        as 'com.fesco.AuthUDF'
        using jar 'hdfs://hadoop01:9000/F_Hive-1.0-SNAPSHOT.jar';
    -- UDTF
    create function splitLine
        as 'com.fesco.AuthUDTF'
        using jar 'hdfs://hadoop01:9000/F_Hive-1.0-SNAPSHOT.jar';
    
    -- 测试
    select indexOf('welcome', 'm');
    select splitLine('welcome to big data', ' ');
  5. 删除函数

    复制代码
    drop function indexOf;

窗口函数

概述

  1. 窗口函数又称之为开窗函数,用于限定要处理的数据范围

  2. 基本语法结构

    复制代码
    分析函数 over(partition by 字段 order by 字段 [desc/asc] rows between 起始范围 and 结束范围)
    1. partition by对数据进行分类

    2. order by对数据进行排序

    3. rows between x and y指定数据的处理范围

      关键字 解释
      preceding 向前
      following 向后
      unbounded 无边界
      current row 当前行
    4. 示例:假设当前处理的第5行数据

      1. 2 preceding and current row:处理前两行到当前行。即处理第3~5行的数据

      2. current row and 3 following:处理当前行以及向后3行。即处理第5~8行的数据

      3. unbounded preceding and current row:从第一行到当前行

      4. current row and unbounded following:从当前行到最后一行

    5. 分析函数:大致可以分为三组

      1. 聚合函数,例如sumavg

      2. 移位函数,包含lagleadntil

      3. 排序函数,包含row_numberrankdense_rank

案例

  1. 原始数据

    复制代码
    jack,2017-01-01,10
    tony,2017-01-02,15
    jack,2017-02-03,23
    tony,2017-01-04,29
    jack,2017-01-05,46
    jack,2017-04-06,42
    tony,2017-01-07,50
    jack,2017-01-08,55
    mart,2017-04-08,62
    mart,2017-04-09,68
    neil,2017-05-10,12
    mart,2017-04-11,75
    neil,2017-06-12,80
    mart,2017-04-13,94
  2. 建表

    复制代码
    -- 建表
    create table orders
    (
        name       string,
        order_date string,
        cost       int
    ) row format delimited fields terminated by ',';
    -- 加载数据
    load data local inpath '/opt/hive_data/orders' into table orders;
  3. 需求一:查询每一位顾客的消费明细以及到消费日期为止的总消费金额

    复制代码
    -- 思路:
    -- 1. 拆寻每一位顾客的信息,那么需要按照顾客姓名来分类
    -- 2. 按照日期,将订单进行排序
    -- 3. 计算总消费金额,所以需要求和
    -- 4. 到当前消费日期为止的金额,也就意味着是获取从第一行到当前行的数据来处理
    select *,
           sum(cost) over (partition by name order by order_date rows between unbounded preceding and current row ) as total_cost
    from orders;

补充:正则捕获组

概述

  1. 在正则表达式中,将()括起来的部分,称之为捕获组,此时可以将捕获组看作是一个整体

  2. 在正则表达式中,默认会对捕获组进行编号,编号是从1开始的。编号的计算,是从捕获组左半边括号出现的顺序来依次计算的

    复制代码
    例如:(AB(C(D)E)F(G))
    1	AB(C(D)E)F(G)
    2	C(D)E
    3	D
    4	G
  3. 在正则表达式中,可以通过\n的形式来引用对应编号的捕获组。例如\1表示引用编号为1的捕获组

相关推荐
floret*1 小时前
HiveSQL面试题
hive·sql
ETLCloud数据集成社区2 小时前
论如何使用ETL数据仓库
数据仓库·etl·数据集成
时差95321 小时前
【面试题】Hive 查询:如何查找用户连续三天登录的记录
大数据·数据库·hive·sql·面试·database
苍老流年21 小时前
Hive中各种Join的实现
数据仓库·hive·hadoop
静听山水21 小时前
Hive:UDTF 函数
hive
EDG Zmjjkk1 天前
Hive 查询(详细实操版)
数据仓库·hive·hadoop
lzhlizihang1 天前
【Hive sql 面试题】求出各类型专利top 10申请人,以及对应的专利申请数(难)
大数据·hive·sql·面试题
Hsu_kk1 天前
Hive 查询各类型专利 Top 10 申请人及对应的专利申请数
数据仓库·hive·hadoop
静听山水1 天前
Hive 的数据存储单元结构
hive
大数据编程之光1 天前
Hive 查询各类型专利 top10 申请人及专利申请数
大数据·数据仓库·hive·hadoop