• Hive优化及数据倾斜
    • 知识点01:回顾
    • 知识点02:目标
    • 知识点03:Hive函数:多行转多列
    • 知识点04:Hive函数:多行转单列
    • 知识点05:Hive函数:多列转多行
    • 知识点06:Hive函数:多列转单行
    • 知识点07:Hive函数:反射函数
    • 知识点08:Hive函数:Python脚本
    • 知识点09:Hive函数:JSON处理
    • 知识点10:Hive函数:窗口聚合函数
    • 知识点11:Hive函数:窗口位置函数
    • 知识点12:Hive函数:窗口分析函数
    • 知识点13:Hive函数:窗口函数案例
    • 知识点14:Hive优化:参数优化
    • 知识点15:Hive优化:SQL优化
    • 知识点16:Hive优化:表设计优化
    • 知识点17:数据倾斜:现象原因
    • 知识点18:数据倾斜:解决方案

Hive优化及数据倾斜

苟有恒,何必三更眠五更起;
最无益,莫过一日曝十日寒。

知识点01:回顾

  1. MapReduce处理Hive表数据的规则以及普通表结构的特点是什么?

    • 底层MapReduce的输入:表的最后一级目录

    • 普通表结构

      数据仓库目录/数据库目录/表的目录/数据文件
      
      • 最后一级目录就是表的目录
  2. 分区表的功能、结构和特点是什么?

    • 功能:将大量的数据按照一定规则条件进行划分,将数据分区目录存储,减少了底层MapReduce输入,提高了性能

    • 结构

      数据仓库目录/数据库目录/表的目录/分区目录/分区文件
      
    • 特点:最后一级目录是分区目录

    • 注意:分区表能实现优化的前提查询的过滤条件一定是分区字段【时间】

  3. 如何实现构建分区表?分区的设计是什么级别的?分区的字段是逻辑的还是物理的?

    • 两种方式

      • 静态分区:数据本身按照分区的规则划分好的

        • step1:创建分区表
        • step2:直接加载分区数据
      • 动态分区:数据本身没有做划分
        • step1:创建普通表,加载数据
        • step2:创建分区表,将普通表的数据动态分区写入分区表
    • 分区级别:目录
    • 分区字段:逻辑字段
  4. 分桶表的功能和设计思想是什么?分桶的设计是什么级别的?分桶字段是逻辑的还是物理的?

    • 功能:优化大表join大表过程,提高大表join大表的性能
    • 设计:将数据按照一定的规则划分到不同的文件中,将大文件拆分为多个小文件,实现每个小文件的Map Join
      • 本质:底层的MapReduce的分区,一个桶就是一个reduce,对应一个结果文件
      • 规则:Hash取余
    • 级别:文件
    • 分桶字段:物理字段
  5. Hive中的order by、sort by 、distribute by、cluster by的功能分别是什么?

    • order:全局排序,只能有1个reduce
    • sort:局部排序,多个Reduce,每个Reduce内部排序
    • distribute:指定底层MapReduce的K2的
    • cluster:在指定的是同一个字段的情况下,功能上等价于sort + distribute
  6. parse_url_tuple函数的功能及语法是什么?

    • 功能:用于解析URL
    • 语法:parse_url_tuple(url,… 要解析的字段)
      • HOST
      • PATH
      • QUERY
    • 应用:UDTF函数,一次性解析多个字段
  7. explode函数的功能及语法是什么?

    • 功能:拆分集合类型的元素,将每个元素变成一行
    • 语法:explode(Array | Map)
    • 应用:列转行
  8. lateral view的功能及语法是什么?

    • 功能:将UDTF结果构建成一个类似于视图的临时表,用于与原表进行拼接查询,解决UDTF查询限制问题

    • 语法

      lateral view udtf 别名 as 临时表的列的列名
      
    • 应用:搭配UDTF使用

  9. 考试编程题

    • MapReduce编程

      • 数据

        门店名,营业额,开支额,年份
        劲松店,600,350,2019年
        劲松店,800,250,2020年
        王府井店,1900,600,2020年
        王府井店,2000,900,2019年
        回龙观店,6700,1800,2020年
        西单店,3000,1000,2019年
        西单店,5000,1000,2020年
        ,3500,1000,2020年
        牡丹园店,3800,1400,2020年
        牡丹园店,2800,1300,2019年
        西直门店,1500,900,2019年
        太阳宫店,9000,3600,2019年
        三里屯店,,1000,2020年
        西直门店,3500,1000,2020年
        太阳宫店,6000,4600,2020年
        回龙观店,7500,2000,2019年
        
      • 需求

        • 去除源文件中字段缺失的数据

          • step1:分析结果

          • 字段不全的数据被过滤掉

          • step2:K2 是什么?

            • 没有分组和排序,没有Shuffle和Reduce、直接用Map进行过滤
          • map方法

            String[] items = value.toString.split(",")
            if(items.length != 4) return;
            for(item:items){if(item.length == 0 ) return;
            }
            context.write(value,NullWritable)
            
        • 按照不同年份将营业数据拆分到不同的文件中

          • step1:分析结果

            • 有多个文件:两个年份有两个文件
            • 自定义分区:按照年份
          • step2:K2:整体构建自定义数据,作为K2

            • 自定义分区

              class extends Partitioner<UserBean,NullWirtable>{getPartition(UserBean k2,Nullwritable v2,numReducer){String yearInfo = k2.getYearInfo;if(yearInfo.startWith("2019")) return 0 ;else return 1;}}
              
        • 对每一年的营业数据按照净盈利排序(营业额-开支额)

          • UserBean2:店铺名称、营业额[TotalInput]、开支[TotalOutput]、年份、利润[Input]

            • compareTo

              return -this.getInput.compareTo(o.getInput);
              
          • map

            UserBean2 outputKey = new UserBean2
            map(K1,V1){String[] items = v1.toString.split(",")this.outputKey.set(items[0],items[1],items[2],items[3],items[1] - items[2])
            }
            
        • 要求最后输出到文件的数据字段之间以‘\t’分割,后边加两个描述字段:净盈利额、盈利或者亏损标记

          UserBean2 outputKey = new UserBean2
          Text outputValue = new Text
          map(K1,V1){String[] items = v1.toString.split(",")long input = items[1] - items[2];this.outputKey.set(items[0],items[1],items[2],items[3],input)if(input > 0) {this.outputValue.set(“盈利”)context.write(outputKey,outptuValue)}else{this.outputValue.set(“亏损”)context.write(outputKey,outptuValue)}
          }
    • Hive编程

      • 数据

        • 学生表student

          学号sid,姓名sname,性别ssex,年龄sage,系 department
          95001,李勇,男,20,CS
          95002,刘晨,女,19,IS
          95003,王敏,女,22,MA
          95004,张立,男,19,IS
          95005,刘刚,男,18,MA
          95006,赵丽,女,20,CS
        • 成绩表score

          学生编号sid,课程编号cid,成绩sscore
          95001,1,81
          95001,2,85
          95001,3,88
          95001,4,70
          95002,1,90
          95002,2,80
          95002,3,90
          95002,4,80
          95003,1,70
          95003,2,78
          95003,3,65
          95003,4,65
          95004,1,70
          95004,2,90
          95004,3,85
          95004,4,90
          95005,1,70
          95005,2,90
          95005,3,70
          95005,4,90
          95006,1,70
          95006,2,90
          95006,3,70
          95006,4,90
        • 课程表course

          课程编号cid,课程名cname
          1,数据库
          2,数学
          3,信息系统
          4,操作系统
      • 需求

        • 创建三个外部表,并分别给外部表加载数据

          • student:学号sid,姓名sname,性别ssex,年龄sage,系 department

            --建库
            create database db_exam;
            use db_exam;
            --建表
            create external table if not exists student(sid string,sname string,ssex string,sage int,department string
            ) row format delimited fields terminated by ',';
            --加载
            load data local inpath '/export/data/student.txt' into table student;
          • score :学生编号sid,课程编号cid,成绩sscore

            --建表
            create external table if not exists score(sid string,cid string,sscore int
            ) row format delimited fields terminated by ',';
            --加载
            load data local inpath '/export/data/score.txt' into table score;
          • course:课程编号cid,课程名cname

            --建表
            create external table if not exists course(cid string,cname string
            ) row format delimited fields terminated by ',';
            --加载
            load data local inpath '/export/data/course.txt' into table course;
        • 查询各课的平均成绩,要求对平均成绩降序排序,并且小数保留2位,考虑四舍五入

          • step1:先看结果

            科目       平均成绩
            select 课程,平均成绩 from score 
      
      - step2:有没有行的过滤?- 没有where- step3:有没有分组- group by cid- 聚合:round(avg(sscore),2)- step4:有没有聚合的过滤- 没有having- step5:有没有排序- order by   avgscore desc​```sqlselect cid,round(avg(sscore),2) as avgscore from score group by cid order by avgscore desc;

      • 查询CS系中数学成绩最高的学生的信息,包括学生的学号和名字(考虑成绩相同情况)

        • step1:结果

          学号  名字
          select * from student  ;
        • step2:条件

          • CS系:student
          • 数学:course
      • 成绩:score

            selecta.sid,a.sname,a.department,b.cid,b.sscore,c.cnamefrom student a join score b on a.sid = b.sidjoin course c on b.cid = c.cid where a.department = 'CS' and c.cname = '数学';

        • 考虑成绩相同情况:dense_rank
          select sid,sname from (select a.sid,a.sname,a.department,b.cid,b.sscore,c.cname,dense_rank() over (partition by department,cname order by sscore desc) as rnfrom student a join score b on a.sid = b.sidjoin course c on b.cid = c.cidwhere a.department = 'CS' and c.cname = '数学' ) t where t.rn < 2;

      • 查询数学成绩比数据库成绩高的学生信息和分数

        select c.*,a.sscore,b.sscore from
        (
        --取出所有学生的数学成绩
        select sid,cid,sscore
        from score where cid in (select cid from course where cname = '数学')
        ) a
        join
        (
        --取出所有学生的数据库成绩
        select sid,cid,sscore
        from score where cid in (select cid from course where cname = '数据库')
        ) b
        on a.sid = b.sid
        join student c on a.sid = c.sid where a.sscore > b.sscore;
      • 求每个课程分数最高的前三名学生(考虑分数相同的情况)

        select * from (
        select a.sid,a.sname,a.department,b.cid,b.sscore,c.cname,dense_rank() over (partition by cname order by sscore desc) as rn
        from student a join score b on a.sid = b.sid
        join course c on b.cid = c.cid
        ) t where t.rn < 4;
      • 规律

        • 需求的结果中出现多张表字段:join

        • 需求中的结果是一张表的字段,条件是另外一张表的字段:子查询、join

        • 如果数据由多到少:过滤或者聚合

        • 如果数据由少到多:join,union

  10. 反馈问题

    • 正则的使用:不用管,掌握核心:记住每种的功能

知识点02:目标

  1. Hive中的函数

    • 了解反射函数、Python脚本辅助处理
    • 掌握
      • 行列转换实现:特殊函数
      • JSON处理函数
      • 开窗函数:窗口聚合、位置偏移、分析函数
        • 实例
  2. Hive优化以及数据倾斜【掌握】
    • 基本优化:参数优化、SQL优化、设计优化【文件格式】
    • 数据倾斜:现象、原因、解决

知识点03:Hive函数:多行转多列

  • 目标掌握行列转换的应用场景及实现多行转多列

  • 路径

    • step1:行列转换的场景
    • step2:多行转多列实现
  • 实施

    • 行列转换的场景

- 分析:基于每个小时分析不同指标【UV,PV,IP】的结果```select hourstr,count(distinct userid),count(url),count(distinct ip) from table group by hourstr``````00       300     1000        9001        200     1000        9002        100     1000        90……23      1000        1000        90```- 需求:得到每个指标不同小时的值:每个小时UV的值```select * from table where key = 'uv'``````00 01  02  ……  23300   200 100     1000```
  • 多行转多列实现

    • 输入

      vim /export/data/r2c1.txt
      a  c   1
      a   d   2
      a   e   3
      b   c   4
      b   d   5
      b   e   6
      --建表
      create table row2col1(
      col1 string,
      col2 string,
      col3 int
      )row format delimited fields terminated by '\t';
      --加载数据
      load data local inpath '/export/data/r2c1.txt' into table row2col1;
    • 结果

      +-------+----+----+----+--+
      | col1  | c  | d  | e  |
      +-------+----+----+----+--+
      | a     | 1  | 2  | 3  |
      | b     | 4  | 5  | 6  |
      +-------+----+----+----+--+
    • 分析

      • 肯定做了分组:按照第一列分组

      • 每一组如何能返回这一组的结果

        • 数据

          col1 col2    col3
          a       c       1
          a       d       2
          a       e       3
        • 结果

          +-------+----+----+----+--+
          | col1  | c  | d  | e  |
          +-------+----+----+----+--+
          | a     | 1  | 2  | 3  |
        • SQL

          selectcol1,max(case col2 when c then col3  else 0 end ) as c,max(case col2 when d then col3  else 0 end ) as d,max(case col2 when e then col3  else 0 end ) as c,
          from table
          group by col1;
    • 函数

      • group by语句中:select后面的字段要么是分组字段要么是聚合函数的结果

        • 每一组只返回一条
      • case when:判断函数

        • 功能:实现多种条件的判断

        • 方式一

          case col
          when  value1 then rs1
          when  value2 then rs2
          ……
          else rsN
          end
        • 方式二

          case
          when col = value1 then rs1
          when col = value2 then rs2
          ……
          else rsN
          end
    • SQL

      select col1 as col1,max(case col2 when 'c' then col3 else 0 end) as c,max(case col2 when 'd' then col3 else 0 end) as d,max(case col2 when 'e' then col3 else 0 end) as e
      from row2col1
      group by col1;
  • 小结

    • case when函数的功能及语法?
    • 功能:判断函数,实现条件的判断
      • 语法

        • case col when value
        • case when col = value
      • 应用:多条件判断场景

知识点04:Hive函数:多行转单列

  • 目标实现多行转单列的SQL开发

  • 实施

    • 输入

      vim /export/data/r2c2.txt
      a    b   1
      a   b   2
      a   b   3
      c   d   4
      c   d   5
      c   d   6
      --建表
      create table row2col2(
      col1 string,
      col2 string,
      col3 int
      )row format delimited fields terminated by '\t';
      --加载数据
      load data local inpath '/export/data/r2c2.txt' into table row2col2;
    • 结果

      +-------+-------+--------+--+
      | col1  | col2  |  col3  |
      +-------+-------+--------+--+
      | a     | b     | 1,2,3  |
      | c     | d     | 4,5,6  |
      +-------+-------+--------+--+
    • 分析

      • 分组:col1,col2
      • 聚合:将每组中的三行变成一行
      • 拼接字符串:将集合中每个元素进行拼接为字符串
    • 函数

      • collect_list/collect_set

        • 功能:聚合函数,将多行的内容合并为一行的内容
        • 语法:
          • collect_list(col):不做去重
          • collect_set(col):做去重
        • 应用:用于将多行转换为单列单行
      • concat / concat_ws
        • 功能:字符串拼接的
        • 语法
          • concat(str1,str2,str3……):不能指定分隔符,有一个为null,整个结果就为null
          • concat_ws(分隔符,str1,str2,str3……):可以指定分隔符,只要一个不为null,结果就不为null
    • SQL

      selectcol1,col2,concat_ws(",",collect_set(cast(col3 as string))) as col3
      from row2col2
      group by col1,col2;
  • 小结

    • concat与concat_ws函数的功能与语法?

      • 功能:字符串拼接
      • 语法
        • concat(str1,str2,str3……)
        • concat_ws(分隔符,str1,str2……)
    • collect_set与collect_list的功能与语法?
      • 功能:将多行合并到一行
      • 语法
        • collect_set(col):做去重
        • collect_list(col):不做去重

知识点05:Hive函数:多列转多行

  • 目标实现多列转多行的SQL开发

  • 实施

    • 输入

      vim /export/data/c2r1.txt
      a    1   2   3
      b   4   5   6
      create table col2row1(
      col1 string,
      col2 int,
      col3 int,
      col4 int
      )row format delimited fields terminated by '\t';
      --加载数据
      load data local inpath '/export/data/c2r1.txt' into table col2row1;
    • 结果

      +-----------+-----------+-----------+--+
      | _u1.col1  | _u1.col2  | _u1.col3  |
      +-----------+-----------+-----------+--+
      | a         | c         | 1         |
      | b         | c         | 4         |
      | a         | d         | 2         |
      | b         | d         | 5         |
      | a         | e         | 3         |
      | b         | e         | 6         |
      +-----------+-----------+-----------+--+
    • 分析

      • 实现行的合并
      • union all
    • 实现

      select col1,'c' as col2,col2 as col3 from col2row1
      union all
      select col1,'d' as col2,col3 as col3 from col2row1
      union all
      select col1,'e' as col2,col4 as col3 from col2row1;
  • 小结

    • union all的功能?

      • 功能:实现行的合并
      • 语法:select…… union all select ……
      • 应用:union all与union区别

知识点06:Hive函数:多列转单行

  • 目标实现多列转单行的SQL开发

  • 实施

    • 输入

      vim /export/data/c2r2.txt
      a    b   1,2,3
      c   d   4,5,6
      create table col2row2(
      col1 string,
      col2 string,
      col3 string
      )row format delimited fields terminated by '\t';
      --加载数据
      load data local inpath '/export/data/c2r2.txt' into table col2row2;
    • 输出

      +-------+-------+-------+--+
      | col1  | col2  | col3  |
      +-------+-------+-------+--+
      | a     | b     | 1     |
      | a     | b     | 2     |
      | a     | b     | 3     |
      | c     | d     | 4     |
      | c     | d     | 5     |
      | c     | d     | 6     |
      +-------+-------+-------+--+
    • 分析

      • 由少变多,将一行的内容拆分为多行
    • 函数

      • explode:将一个集合类型的内容中的每一个元素变成一行
    • SQL

      select
      col1,
      col2,
      lv.col3 as col3
      from col2row2
      lateral view explode(split(col3, ',')) lv as col3;
  • 小结

    • explode函数的功能?

      • 功能:用于将集合或者数组类型列中的每一个元素变成一行
      • 语法:explode(Array | map)
      • 应用:将一列转为多行

知识点07:Hive函数:反射函数

  • 目标了解reflect函数的功能及用法

  • 实施

    • 功能

      • 用于在Hive中直接调用Java中类的方法
    • 本质

      • 通过给定的类,反射构建了这个类的对象,通过对象调用方法给用户返回
    • 语法

      reflect(类,方法,参数)
    • 测试

      select reflect("java.util.UUID", "randomUUID");
      select reflect("java.lang.Math","max",20,30);
      select reflect("org.apache.commons.lang.math.NumberUtils","isNumber","123");
    • 应用:一般用于Java中已经有对应的工具类,可以直接被调用,省去写UDF

  • 小结

    • 了解即可

知识点08:Hive函数:Python脚本

  • 目标了解Hive中如何实现Python脚本辅助处理

  • 实施

    • 数据

  • 建表加载数据

    --创建原始数据表:用户id、电影id、用户评分、用户的观影时间
    CREATE TABLE u_data (userid INT,movieid INT,rating INT,unixtime STRING)
    ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
    STORED AS TEXTFILE;--加载数据:
    load data local inpath '/export/data/u.data' into table u_data;--查询数据
    select count(*) from u_data;
  • 创建目标表

    --创建新表:用户id、电影id、用户评分、用户的时间是周几
    CREATE TABLE u_data_new (userid INT,movieid INT,rating INT,weekday INT)
    ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
  • 创建Python脚本

    --创建Python脚本实现将原始表的时间转为对应的星期几
    vim /export/data/weekday_mapper.py
    import sys
    import datetimefor line in sys.stdin:line = line.strip()userid, movieid, rating, unixtime = line.split('\t')weekday = datetime.datetime.fromtimestamp(float(unixtime)).isoweekday()print '\t'.join([userid, movieid, rating, str(weekday)])
  • 加载脚本,写入数据

    --加载python脚本并将数据写入新表
    add FILE /export/data/weekday_mapper.py;INSERT OVERWRITE TABLE u_data_new
    SELECTTRANSFORM (userid, movieid, rating, unixtime)USING 'python weekday_mapper.py'AS (userid, movieid, rating, weekday)
    FROM u_data;
  • 查询分析

    --统计每周内每天用户观影的次数
    SELECT weekday, COUNT(*)
    FROM u_data_new
    GROUP BY weekday;
  • 小结

    • 了解即可

知识点09:Hive函数:JSON处理

  • 目标掌握Hive中处理JSON数据的两种方式

    • 常见的数据格式:结构化数据格式

      • csv:每一列都是用逗号分隔符
      • tsv:每一列都是用制表符分隔符
      • json:专有的JSON格式文件
      • properteies
      • xml
  • 路径

    • step1:JSON函数
    • step2:JSONSerDe
  • 实施

    • JSON函数

      • 创建数据

        vim /export/data/hivedata.json
        {"id": 1701439105,"ids": [2154137571,3889177061],"total_number": 493}
        {"id": 1701439106,"ids": [2154137571,3889177061],"total_number": 494}
      • 创建表

        create table tb_json_test1 (
        json string
        );
        --加载数据
        load data local inpath '/export/data/hivedata.json' into table tb_json_test1;
      • 函数

        • get_json_object:用于解析JSON字符串,指定取出JSON字符串中的某一个元素

          select get_json_object(t.json,'$.id'), get_json_object(t.json,'$.total_number')
          from tb_json_test1 t ;
        • json_tuple:UDTF函数,一次性取出多个JSON字符串的元素

          select t1.json,t2.*
          from tb_json_test1 t1
          lateral view json_tuple(t1.json, 'id', 'total_number') t2 as c1,c2;
    • JSONSerDe

      • 功能:可以直接在加载数据文件的时候解析JSON格式

      • 配置:修改hive-env.sh

        export HIVE_AUX_JARS_PATH=/export/server/hive-2.1.0-bin/hcatalog/share/hcatalog/hive-hcatalog-core-2.1.0.jar
      • 重启hiveserver2

      • 创建表

        create table tb_json_test2 (
        id string,
        ids array<string>,
        total_number int)
        ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
        STORED AS TEXTFILE;
        --加载数据
        load data local inpath '/export/data/hivedata.json' into table tb_json_test2;
      • 查询数据

  • 小结

    • Json处理的函数有哪些?

      • 方式一:JSON函数

        • get_json_object(jsonString,“$.元素名称”):一次只能取一个

        • json_tuple(jsonString,“ . 元 素 名 称 ” , “ .元素名称”,“ .元素名称”,“.元素名称”,“$.元素名称”……)

          • UDTF函数
          • 一次取多个
        • 应用:数据中的某个字段是JSON格式的

          id        name        age     info【JSON】
          1       张三      18          {addr:上海……}
      • 方式二:通过JSONSerde来加载JSON格式的文件

        • 数据就是一个json文件,每一条数据就是一个完整的JSON字符串

          json1
          json2
          json3
          ……

知识点10:Hive函数:窗口聚合函数

  • 目标掌握窗口聚合函数的使用

  • 路径

    • step1:常见的分析需求
    • step2:窗口的基本语法
    • step3:窗口聚合函数
  • 实施

    • 常见的分析需求

      • 需求1:统计得到每个部门薪资最高的那个员工薪水

        selectdeptno,max(salary)
        from tb_emp
        group by deptno;
      • 需求2:统计得到每个部门薪资最高的前两名的薪水

        selectdeptno,max(salary)
        from tb_emp
        group by deptno
        order by salary;
      • 问题:分组一组只能返回一条,怎么办?

        • 需求中出现了关键词每个、各个、不同,要么做分组,要么做分区

        • 分组:group by:一组返回一条

        • 分区:窗口函数partition by:一组返回多条

    • 窗口的基本语法

      funName(参数) over (partition by col [order by col]  [window_szie])
      • partition by:分区,将相同分区的数据放在一起

      • order by:分区内部按照某个字段进行排序

      • window_szie:窗口大小,指定的是函数处理数据的范围

        -- N preceding :前N行
        -- N following :后N行
        -- current row:当前行
        -- unbounded preceding 表示从前面的起点,第一行
        -- unbounded following:表示到后面的终点,最后一行
    • 窗口聚合函数

      max/min/avg/count/sum
      • 创建数据

        vim /export/data/window.txt
        cookie1,2018-04-10,1
        cookie1,2018-04-11,5
        cookie1,2018-04-12,7
        cookie1,2018-04-13,3
        cookie2,2018-04-13,3
        cookie2,2018-04-14,2
        cookie2,2018-04-15,4
        cookie1,2018-04-14,2
        cookie1,2018-04-15,4
        cookie1,2018-04-16,4
        cookie2,2018-04-10,1
        cookie2,2018-04-11,5
        cookie2,2018-04-12,7
      • 创建表

        --建库
        create database db_function;
        use db_function;
        --建表
        create table itcast_f1(
        cookieid string,
        daystr string,
        pv int
        ) row format delimited fields terminated by ',';
        --加载
        load data local inpath '/export/data/window.txt' into table itcast_f1;
        --本地模式
        set hive.exec.mode.local.auto=true;
      • 需求1:实现分区内起始行到当前行的pv累加,指定排序

        select cookieid,daystr,pv,sum(pv) over (partition by cookieid order by daystr) as pv1
        from itcast_f1;

  - 如果指定了partition by和order by,没有指定窗口大小- 默认窗口:分区的第一行到当前行- 需求2:实现分区内起始行到当前行的pv累加,不指定排序```sqlselect cookieid,daystr,pv,sum(pv) over(partition by cookieid ) as pv2from itcast_f1;```

- 需求3:实现分区内起始行到当前行的pv累加,指定窗口```sqlselect cookieid,daystr,pv,sum(pv) over (partition by cookieid order by daystr rows between unbounded preceding and current row) as pv3from itcast_f1;```

- 需求4:实现分区内指定前N行到当前行的pv累加```sqlselect cookieid,daystr,pv,sum(pv) over (partition by cookieid order by daystr rows between 3 preceding and current row) as pv4from itcast_f1;```

- 需求5:实现分区内指定前N行到后N行的pv累加 ```sqlselect cookieid,daystr,pv,sum(pv) over(partition by cookieid order by daystr rows between 3 preceding and 1 following) as pv5from itcast_f1;```

- 需求6:实现分区内指定当前行到最后一行的pv累加   ```sqlselect cookieid,daystr,pv,sum(pv) over(partition by cookieid order by daystr rows between current row and unbounded following) as pv6from itcast_f1;```

  • 小结

    • 窗口函数的语法及关键字的含义是什么?

      • 语法

        functionName(参数) over (partition by col order by col 【window_size】)
      • 含义

        • partition by:分区,将相同分区的数据放在一起
        • order by:排序,基于分区内部排序
        • window_size:基于分区内部计算的窗口大小

知识点11:Hive函数:窗口位置函数

  • 目标掌握窗口位置函数的使用

  • 路径

    • step1:first_value
    • step2:last_value
    • step3:lag
    • step4:lead
  • 实施

    • first_value

      • 功能:取每个分区内某列的第一个值

      • 语法:FIRST_VALUE(col) over (partition by col1 order by col2)

      • 示例

        use db_emp;
        --取每个部门薪资最高的员工姓名
        selectempno,ename,salary,deptno,FIRST_VALUE(ename) over (partition by deptno order by salary desc) as first
        fromdb_emp.tb_emp;

  • last_value

    • 功能:取每个分区内某列的最后一个值

    • 语法:LAST_VALUE() over (partition by col1 order by col2)

    • 注意:一定要 注意默认窗口的计算范围

    • 示例

      --取每个部门薪资最低的员工编号
      selectempno,ename,salary,deptno,LAST_VALUE(empno) over (partition by deptno order by salary desc) as last
      fromdb_emp.tb_emp; 无法实现
      ```sql--取每个部门薪资最低的员工编号selectempno,ename,salary,deptno,LAST_VALUE(empno) over (partition by deptno order by salary desc rows between unbounded preceding and unbounded following) as lastfromdb_emp.tb_emp;
  • lag

    • 功能:取每个分区内某列的前N个值

    • 语法:LAG(col,N,defaultValue) over (partition by col1 order by col2)

      • col:取分区内某一列的值
      • N:向前偏移N个单位
      • defaultValue:如果取不到的默认值
    • 示例

      selectempno,ename,salary,deptno,LAG(salary,1,0) over (partition by deptno order by salary) as deptno2
      fromdb_emp.tb_emp;

  • lead

    • 功能:取每个分区内某列的后N个值

    • 语法:LEAD(col,N,defaultValue) over (partition by col1 order by col2)

      • col:取分区内某一列的值
    • N:向后偏移N个单位

      • defaultValue:如果取不到的默认值
    • 示例

      selectempno,ename,salary,deptno,
      LEAD(salary,1,0) over (partition by deptno order by salary) as deptno2
      fromdb_emp.tb_emp;

  • 小结

    • first_value的功能及语法?

      • 功能:取分区内部某一列第一条
      • 语法:first_value(col)
    • last_value的功能及语法?
      • 功能:取分区内部某一列最后一条
      • 语法:last_value(col)
    • lag的功能及语法?
      • 功能:取分区内某一列的向前偏移N个单位的值
      • 语法:lag(col,N,default)
    • lead的功能及语法?
      • 功能:取分区内某一列的向后偏移N个单位的值
      • 语法:lead(col,N,default)

知识点12:Hive函数:窗口分析函数

  • 目标掌握窗口分析函数的使用

  • 路径

    • step1:row_number
    • step2:rank
    • step3:dense_rank
    • step4:ntil
  • 实施

    • row_number

      • 功能:用于实现分区内记录编号

      • 语法:row_number() over (partition by col1 order by col2)

      • 特点:如果值相同,继续编号

      • 示例

        --统计每个部门薪资最高的前两名
        selectempno,ename,salary,deptno,row_number() over (partition by deptno order by salary desc) as numb
        fromdb_emp.tb_emp;
    • rank

      • 功能:用于实现分区内排名编号[会留空位]

      • 语法:rank() over (partition by col1 order by col2)

      • 特点:如果值相同,编号相同,会留下空位

      • 示例

        --统计每个部门薪资排名
        selectempno,ename,salary,deptno,rank() over (partition by deptno order by salary desc) as numb
        fromdb_emp.tb_emp;

  • dense_rank

    • 功能:用于实现分区内排名编号[不留空位]

    • 语法:dense_rank() over (partition by col1 order by col2)

    • 特点:如果值相同,编号相同,不留空位

    • 示例

      --统计每个部门薪资排名
      selectempno,ename,salary,deptno,dense_rank() over (partition by deptno order by salary desc) as numb
      fromdb_emp.tb_emp; 

  • ntil

    • 功能:将每个分区内排序后的结果均分成N份【如果不能均分,优先分配编号小的】

    • 语法:NTILE(N) over (partition by col1 order by col2)

    • 示例

      --统计每个部门薪资排名,将每个部门的薪资分为两个部分,区分高薪和低薪
      selectempno,ename,salary,deptno,NTILE(2) over (partition by deptno order by salary desc) as numb
      fromdb_emp.tb_emp; 
  • 小结

    • row_number、rank与dense_rank的功能与区别?

      • 功能:做编号
      • 区别
        • row_number:如果值相同,继续编号
        • rank:如果值相同,编号相同,但是会留下空位
        • dense_rank:如果值相同,编号相同,不留空位

知识点13:Hive函数:窗口函数案例

  • 目标:使用窗口函数实现以下需求案例

  • 路径

    • step1:存款金额累计求和
    • step2:连续登陆用户统计
  • 实施

    • 存款金额累计求和

      • 数据:用户id【userid】、存款月份【month】、存储金额【money】

        A 2015-01 5
        A   2015-01 15
        B   2015-01 5
        A   2015-01 8
        B   2015-01 25
        A   2015-01 5
        A   2015-02 4
        B   2015-02 6
        B   2015-02 10
        B   2015-02 5
        A   2015-03 7
        B   2015-03 9
        A   2015-03 11
        B   2015-03 6
      • 需求:统计每个人每个月存款的金额和累计总金额

        +-------------+----------+---------+-------------+--+
        | a.userid    | a.month  | money   | accumulate  |
        +-------------+----------+---------+-------------+--+
        | A           | 2015-01  | 33      | 33          |
        | A           | 2015-02  | 10      | 43          |
        | A           | 2015-03  | 16      | 59          |
        | B           | 2015-01  | 30      | 30          |
        | B           | 2015-02  | 15      | 45          |
        | B           | 2015-03  | 17      | 62          |
        +-------------+----------+---------+-------------+--+ 
      • 分析

        • 先拿到前面三列:每个人在每个月的存储总金额

          selectuserid,month,sum(money) as 这个月的总金额
          from table
          group by userid,month;
        • 再做窗口聚合

          • partition by userid
          • order by month
    • 连续登陆用户统计

      • 数据:用户id【userid】,登陆日期【logindate】

        A,2021-03-22
        B,2021-03-22
        C,2021-03-22
        A,2021-03-23
        C,2021-03-23
        A,2021-03-24
        B,2021-03-24
      • 需求:统计连续登录N天的用户(N>=2)

        • 连续登录2天的用户是哪些:A,C

        • 连续登录3天的用户是哪些:A

      • 分析

        • 连续登录2天

          • 方案一:构建笛卡尔积

            userid1 logindate1 userid2 logindate2
            • userid1 = userid2 and date_add(logindate1,1) = logindate2
          • 方案二:窗口函数

            selectuserid,logindate,date_add(logindate,1) , --当前登录日期的后一天lead(logindate,1,0) over (partition by userid order by logindate) as nextlogin
            from table;
               logindate        nextday         nextlogin
            A   2021-03-22      2021-03-23      2021-03-23
            A   2021-03-23      2021-03-24      2021-03-24
            A   2021-03-24      2021-03-25      0
            B   2021-03-22      2021-03-23      2021-03-24
            B   2021-03-24      2021-03-25      0
            C   2021-03-22      2021-03-23      2021-03-23
            C   2021-03-23      2021-03-24      0

            连续登录2天:nextday = nextlogin

            selectuserid,logindate,date_add(logindate,2) , --当前登录日期的后两天lead(logindate,2,0) over (partition by userid order by logindate) as nextlogin
            from table;
               logindate        nextday         nextlogin
            A   2021-03-22      2021-03-24      2021-03-24
            A   2021-03-23      2021-03-25      0
            A   2021-03-24      2021-03-26      0
            B   2021-03-22      2021-03-24      0
            B   2021-03-24      2021-03-26      0
            C   2021-03-22      2021-03-24      0
            C   2021-03-23      2021-03-25      0

            连续登录3天:nextday = nextlogin

    • 一般应用场景

      • 分区窗口聚合:每个分区的聚合的结果
      • 分区排序
      • 位置偏移
  • 小结

    • 根据思路,自己通过代码实现

知识点14:Hive优化:参数优化

  • 目标掌握Hive中常见的参数优化

  • 路径

    • step1:MapReduce参数
    • step2:Hive参数
  • 实施

    • MapReduce参数

      • 推测执行

        • 问题:经常运行一个Mapreduce程序,有多个MapTask和ReduceTask,由于网络或者资源故障导致有一个Task一直不能运行结束

        • 解决:开启推测执行

          • 如果appmaster发现某个Task一直不能结束,会在另外节点上启动同一个Task,谁先运行结束,另外一个会被kill
        • 属性

          mapreduce.map.speculative=true
          mapreduce.reduce.speculative=true
          hive.mapred.reduce.tasks.speculative.execution=true
      • JVM重用

        • 问题:每次每个Task都会申请一个JVM进程来运行程序,JVM进程需要内存等资源

          • 每个Task运行完成以后,这个JVM就被销毁了
        • 解决:申请了一个JVM进程的资源以后,可以运行多个Task

          • 实现资源复用

          • 配置

            set  mapreduce.job.jvm.numtasks=10
    • Hive参数

      • Fetch Task

        • Hive自带了小型计算引擎,一部分简单的SQL语句不走Mapreduce,直接由Fetch Task处理

        • 属性

          hive.fetch.task.conversionExpects one of [none, minimal, more].Some select queries can be converted to single FETCH task minimizing latency.Currently the query should be single sourced not having any subquery and should not haveany aggregations or distincts (which incurs RS), lateral views and joins.0. none : disable hive.fetch.task.conversion1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only2. more    : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)
        • none:不启用fetch抓取

        • minimal

        • more

      • 严格模式

        • 老版本的属性:hive.mapred.mode=nonstrict/strict
        • 如果为严格模式:hive会限制一些SQL语句的运行
        • 新版本的属性
        • hive.strict.checks.type.safe
          • 是否允许一些风险性的类型比较
          • bigints and strings.
            • bigints and doubles.
        • hive.strict.checks.cartesian.product
          • 是否允许笛卡尔的产生
      • 并行执行

        • Hive在解析SQL时,默认不会并行执行Stage,只会单个Stage执行
      • 设置并行度,提高Hive解析编译的性能

          set hive.exec.parallel=true;              //打开任务并行执行
        set hive.exec.parallel.thread.number=16;  //同一个sql允许最大并行度,默认为8。
      • 压缩

        • 先配置Hadoop中的压缩

          • 设置Mapreduce的shuffle的中间输出压缩
      • 属性

        #配置多个Mapreduce中的中间Mapreduce的结果压缩
        hive.exec.compress.intermediate=true
  • 小结

    • MapReduce可以做哪些优化?

      • 推测执行
      • JVM重用
    • Hive中可以做哪些参数优化?
      • Fetch Task
      • 严格模式
      • 并行执行
      • 压缩

知识点15:Hive优化:SQL优化

  • 目标掌握Hive中的SQL优化的基本规则

  • 实施

    • 基本规则:PPD

      谓词下推 Predicate Pushdown(PPD)的思想简单点说就是在不影响最终结果的情况下,尽量将过滤条件提前执行。谓词下推后,过滤条件在map端执行,减少了map端的输出,降低了数据在集群上传输的量,降低了Reduce端的数据负载,节约了集群的资源,也提升了任务的性能。
    • 示例

      • where与having

        • 能在where中过滤的就不要在having中过滤
      • join

        • 需求:订单表a【1000万 orderid pid 】、商品表b【100万 pid pname】,获取每个订单中商品的信息

          select * from a join b on a.pid = b.pid
        • step1:先将所有订单中出现的商品id过滤出来:c[10万]

          select distinct pid from a;
        • step2:让订单中的商品id与商品表进行关联,得到这些商品id的商品信息:d[10万条]

          select
          from c join  b on c.pid = b.pid 
        • step3:a与djoin

          selectfrom  a join d a.pid = d.pid
  • 小结

    • Hive默认开启了自动谓词下推,只要掌握原则即可

知识点16:Hive优化:表设计优化

  • 目标掌握Hive中表设计的优化方案

  • 路径

    • step1:分区表
    • step2:分桶表
    • step3:文件格式
  • 实施

    • 分区表:优化底层MapReduce输入,提高性能

    • 分桶表:提前将数据分桶存储,提高Join性能

    • 文件格式

      • 创建表时可以指定

        STORED AS file_format
      • 默认格式:textfile

        file_format:: SEQUENCEFILE| TEXTFILE    -- (Default, depending on hive.default.fileformat configuration)| RCFILE      -- (Note: Available in Hive 0.6.0 and later)| ORC         -- (Note: Available in Hive 0.11.0 and later)| PARQUET     -- (Note: Available in Hive 0.13.0 and later)| AVRO        -- (Note: Available in Hive 0.14.0 and later)| JSONFILE    -- (Note: Available in Hive 4.0.0 and later)| INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname
      • 工作中一般会选用存储文件格式

        • 二进制:SEQUENCEFILE
        • 列式存储:rcfile、orc、parquet
      • 列式存储的优点

        • 相同的数据,存储占用的空间更小

        • 列式存储:对于SQL分析读取列比较方便

          col1       col2        col3
          1           a           c
          2           b           d
          • 按行存储

            1            a           c    2          b           d
          • 列式存储

            1       2       a           b           c       d
          • SQL:select col1 from table

            • 按行存储:将每一行都读取出来,然后过滤第一列
            • 按列存储:直接读取对应的列
        • 构建文件数据索引

      • 测试

        • 参考:《Hive实现列式存储parquet与orc对比测试》
  • 小结

    • 常见的文件格式有哪些?

      • 默认:textfile
      • 二进制:sequencefile
      • 列式存储:rcfile,orc,parquet
    • 列式存储的优点是什么?
      • 占用空间更小
      • 列式存储,列的读取更多
      • 构建列式索引

知识点17:数据倾斜:现象原因

  • 目标了解数据倾斜的现象、原因

  • 路径

    • step1:现象
    • step2:原因
  • 实施

    • 现象

      • 运行一个程序,这个程序的某一个Task一直在运行,其他的Task都运行结束了,进度卡在99%或者100%
    • 原因

      • 基本原因:这个ReduceTask的负载要比其他Task的负载要高

        • ReduceTask的数据分配不均衡
      • MapTask会不会有数据倾斜的问题?不会
    • 根本原因:分区的规则

      • 默认分区:根据K2的Hash值取余reduce的个数

        • 优点:相同的K2会由同一个reduce处理
        • 缺点:可能导致数据倾斜
      • 举例:

        • Map输出的数据

          K 2          V2
          hadoop      1
          hive        1
          hadoop      1
          hive        1
          hadoop      1
          hadoop      1
          hadoop      1
          hadoop      1
          hadoop      1
          hbase       1
        • Reduce0

          hadoop       1
          hadoop      1
          hadoop      1
          hadoop      1
          hadoop      1
          hadoop      1
          hadoop      1
        • Reduce1

          hive     1
          hive        1
          hbase       1
  • 小结

    • 了解数据倾斜的现象及原因

知识点18:数据倾斜:解决方案

  • 目标掌握数据倾斜的解决方案

  • 路径

    • step1:数据倾斜的场景
    • step2:解决方案
  • 实施

    • 数据倾斜的场景

      • group by / count(distinct)
      • join
    • 解决方案

      • group by / count(distinct)

        • 开启Combiner

          hive.map.aggr=true
        • 随机分区

          • 方式一:开启参数

            hive.groupby.skewindata=true
            • 开启这个参数以后,底层会自动走两个MapReduce
        • 第一个MapReduce自动实现随机分区

          • 第二个MapReduce做最终的聚合

          • 方式二:手动指定

            distribute by rand()
      • join

        • 尽量避免走Reduce Join
        • Map Join
          • 尽量将不需要参加Join的数据过滤,将大表转换为小表
          • 构建分桶Bucket Map Join
  • 小结

    • 哪些场景下会产生数据倾斜以及怎么解决?

      • group by / count(distinct)

        • 开启Combiner
        • 实现随机分区
      • join:避免reduce join

大数据笔记30—Hadoop基础篇13(Hive优化及数据倾斜)相关推荐

  1. 【大数据笔记】hadoop基础——各组件介绍

    目录 故事背景 Hadoop 与大数据之间到底是什么关系? 1.数据存储:HDFS,一个分布式文件系统 2. 数据分析:MapReduce 计算引擎 HDFS(Hadoop 分布式文件系统) MapR ...

  2. 大数据笔记16—java基础篇12(JDBC 、连接池、事务)

    目录 JDBC jdbc概述 jdbc入门案例 API详解 jdbc工具类 预编译执行平台 1.SQL注入问题(安全问题) 2API详解:预处理对象(PreparedStatement) 使用连接池重 ...

  3. 大数据笔记9—java基础篇5(API)

    java_API API String类 创建字符串对象的区别对比 String字符串的特点 字符串的比较 例题(String) 例题1. 模拟登陆 例题2遍历字符串 例题3.案例 :统计字符次数 例 ...

  4. 大数据笔记8—java基础篇4(面向对象-封装-继承-多态)

    面向对象 一.面向对象 1.面向过程 1.2.举例 1.3.总结 二.面向对象 1.简述 2.举例 3.思想特点 2.1.类的定义格式 2.1.1.简述 2.2.2.格式 2.3.3.示例 三.类的使 ...

  5. 大数据笔记10—java基础篇6(集合1-Collection)

    集合 集合(Collection) 一.迭代器<iterator> 案例一 二.并发修改异常 三.Collection集合 案例一(Collection练习) 案例二(Collection ...

  6. 大数据笔记11—java基础篇7(集合2-Map)

    目录Map Map集合 2.1 Map入门 2.2 Map集合的成员方法 Collections类 斗地主案例 苟有恒,何必三更眠五更起: 最无益,莫过一日曝十日寒. Map集合 概述: Map集合是 ...

  7. 菜鸟学习笔记:Java基础篇2(变量、运算符、流程控制语句、方法)

    菜鸟学习笔记:Java基础篇2 变量 基本概念 变量作用域 final关键字 运算符 算术运算符 比较运算符 逻辑运算符 位运算符 赋值运算符 条件运算符 运算符优先级 Java三种流程控制语句 顺序 ...

  8. 菜鸟学习笔记:Java基础篇7(包装类、时间相关类、文件类、异常处理类)

    菜鸟学习笔记:Java其他常用类 基本数据类型包装类 时间处理和文件处理相关类 Date时间类 SimpleDateFormat Calendar日历类 文件类 异常机制 异常的概念 Java异常处理 ...

  9. 菜鸟学习笔记:Java基础篇6(数组、字符串)

    菜鸟学习笔记:Java常用类(数组.字符串) 数组 概述 数组的定义 二维数组 数组查找和排序 查找 排序 数组运用--字符串 不可变字符序列(String) 可变字符序列(StringBuilder ...

最新文章

  1. BZOJ3632:外太空旅行(最大团,DFS)
  2. uglifyjs压缩js文件
  3. python爬虫基础教程115_Python解析网页源代码中的115网盘链接实例
  4. 20145240 《信息安全系统设计基础》第三周学习总结
  5. anaconda下安装python,Windows下Anaconda的安装和简单使用方法
  6. mybatis使用in语句作为查询条件
  7. 根据中文修改英文翻译,重新生成英文翻译文件(保证原有文件的顺序不变)
  8. 用mac的chrome浏览器调试Android手机的网页
  9. 读书:海明威的《老人与海》
  10. java web调用exe文件_从网页WEB上调用本地应用程序(java)
  11. jks签名文件转pk8
  12. java声音变音代码实现_大话音频变声原理 附简单示例代码
  13. 插画师如何确定自己的风格?教你如何一步步找到自己绘画风格!
  14. android隐藏虚拟按键的几种方式
  15. win10 1809无法更新(扩展EFI分区)
  16. 中国医科大学2021年12月《五官科护理学》作业考核试题
  17. 技术大佬们都是怎么学习的?
  18. macOS:删除DNS
  19. SMTP邮件postfix
  20. HDU-1728---逃离迷宫(BFS)

热门文章

  1. Redis中间件总结
  2. curl_exec函数
  3. 自制wpf年会抽奖小软件
  4. MySQL之MYISAM和INODB
  5. 写给地方网站的创业新手(转载)
  6. 老婆为什么是别人的好?
  7. Matlab的parfor的使用条件
  8. 1、direct X 的简介
  9. 在配置Intel realsense (D435i)时遇到的问题
  10. 百度AI实现m:n人脸搜索