zoukankan      html  css  js  c++  java
  • 大数据学习----day27----hive02------1. 分桶表以及分桶抽样查询 2. 导出数据 3.Hive数据类型 4 逐行运算查询基本语法(group by用法,原理补充) 5.case when(练习题,多表关联)6 排序

    1. 分桶表以及分桶抽样查询

    1.1 分桶表

    对Hive(Inceptor)表分桶可以将表中记录按分桶键(某个字段对应的的值)的哈希值分散进多个文件中,这些小文件称为桶。  

     如要按照name属性分为3个桶,就是对name属性值的hash值对3取摸,按照取模结果对数据分桶。如取模结果为0的数据记录存放到一个文件,取模为1的数据存放到一个文件,取模为2的数据存放到一个文件。

     分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区,特别是之前所提到过的要确定合适的划分大小这个疑虑(可能某个分区的数据过大)。

     分区针对的是数据的存储路径;分桶针对的是数据文件

     把表或分区划分成bucket有两个理由

    • 更快,桶为表加上额外结构,链接相同列划分了桶的表,可以使用map-side join更加高效。
    • 取样sampling更高效。没有分区的话需要扫描整个数据集。

    数据如下(student.txt)

    (1)创建分桶表

    create table buck_demo(id int, name string)
    clustered by(id) 
    into 4 buckets
    row format delimited fields terminated by '	';

    (2)建一个普通的stu表

    create table stu(id int, name string)
    row format delimited fields terminated by '	';

    (3)向普通的stu表中导入数据

    load data local inpath "/root/hive/student.txt" into table buck_demo;

    (4)设置分桶表的属性

     set hive.enforce.bucketing=true;     -- 开启分桶
     set mapreduce.job.reduces=-1;         --  默认reduce个数

    (5)将数据导入分桶表(不能用load直接导入,会报错)

    insert into table buck_demo
    select id, name from stu;

    (6)查看结果

     1.2 分桶抽样查询 

     对于非常大的数据集,有时用户需要使用的是一个具有代表性的查询结果而不是全部结果。Hive可以通过对表进行抽样来满足这个需求。

     从大量的数据中根据某个字段的hashcode%y(样本的个数 ,桶数)获取部分样本数据,对抽样的表是没有要求的 , 分桶表普通表都可以 

    例:查询表buck_sku中的数据

    hive (default)> select * from  buck_demo tablesample(bucket 1 out of 4 on id);

    注:tablesample是抽样语句,语法:TABLESAMPLE(BUCKET x OUT OF y) ,其中y为数据按照字段分的份数,x为从数据中获取第几份,x<=y

    查询结果:

    2. 导出数据

    2.1 将查询的数据导出到本地的文件夹中

     insert  overwrite  local  directory "路径"
          select *  from tbname ;

    例:将stu表中查出的数据导入/root/hive/stu中

    (1)导出的数据无分割符

     insert  overwrite  local  directory "/root/hive/stu"
          select *  from stu ;

    结果

     可见,导入到本地后的数据是被格式化的(无分割符)

    (2)导出的数据可以自定义分割符    

    1 insert  overwrite  local  directory "/root/hive/stu2/"
    2 ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' 
    3 select *  from stu ;

    结果:

     2.2 将数据导出到HDFS系统中

      同2.1(只是去掉local)

    2.3 直接在linux的终端执行hivesql命令的方式将数据导出数据  

    补充:  

    hive -e   sql语句
    hive -f   sql内容的文件

    例如,需求同2.1

    hive -e  "use mydb1;select * from stu;"   >  // >>  /root/hive/res.txt

    此处一个“>”表示覆盖导出,“>>”表示追加导出

    2.4 export的形式

     export   导出特殊格式 结合 inport导入使用

    export  table  tbname  to  "文件夹"

    3 Hive的数据类型(见文档)

    3.1 基本数据类型

      见文档

    3.2  集合数据类型

     Hive有三种复杂数据类型ARRAY、MAP 和 STRUCT。ARRAY和MAP与Java中的Array和Map类似,而STRUCT与C语言中的Struct类似,它封装了一个命名字段集合,复杂数据类型允许任意层次的嵌套

    4 逐行运算查询基本语法     

    4.1 select....from tb_name(省略号处的用法)  

    select 运算关键字
        1 获取变量
        2 打印常量
        3 执行算术运算
        4 调用函数
          from  数据集
    遍历每行执行一次

    以查询stu表为例

    select
    id   ,  --表中的字段名 (遍历表中的每行数据 获取这个变量名的值 展示)
    name  ,
    id+1   newid1 , -- 1002.0  隐式类型转换
    cast(id as int) +1  intid,   -- 强制转换 1002
    "hello"+name  helloname ,-- null+any  null
    concat("hello " , name) newname , -- 每行执行
    "tomcat" , 
    1+1,
    current_database()   --  当前数据库
    from
    stu ;

    结果

    4.2 where,group by的用法

    (1) where......
    where表示对表中所有原始数据的过滤,其后面可接:>   >=    <   <=    and     or     in    like     not null      between and,与where对应的即是having,having表示对表中分组后的数据进行过滤
    (2)group by 分组,在前面使用如下聚合函数

      sum  avg   min   max    count

    补充:group by 的用法和原理(https://blog.csdn.net/hengji666/article/details/54924387)

    为什么不能够select * from Table group by id,为什么一定不能是*,而是某一个列或者某个列的聚合函数,group by 多个字段可以怎么去很好的理解呢?不过最后还是转过来了

    =========正文开始===========

      先来看下表1,表名为test:

     

    表1

      执行如下SQL语句:

    1  SELECT name FROM test

    2  GROUP BY name

     你应该很容易知道运行的结果,没错,就是下表2:

     

    表2

      可是为了能够更好的理解“group by”多个列“和”聚合函数“的应用,我建议在思考的过程中,由表1到表2的过程中,增加一个虚构的中间表:虚拟表3。下面说说如何来思考上面SQL语句执行情况:

    1.FROM test:该句执行后,应该结果和表1一样,就是原来的表。

    2.FROM test Group BY name:该句执行后,我们想象生成了虚拟表3,如下所图所示,生成过程是这样的:group by name,那么找name那一列,具有相同name值的行,合并成一行,如对于name值为aa的,那么<1 aa 2>与<2 aa 3>两行合并成1行,所有的id值和number值写到一个单元格里面。

     

    3.接下来就要针对虚拟表3执行Select语句了:

    (1)如果执行select *的话,那么返回的结果应该是虚拟表3,可是id和number中有的单元格里面的内容是多个值的,而关系数据库就是基于关系的,单元格中是不允许有多个值的,所以你看,执行select * 语句就报错了。

    (2)我们再看name列,每个单元格只有一个数据,所以我们select name的话,就没有问题了。为什么name列每个单元格只有一个值呢,因为我们就是用name列来group by的。

    (3)那么对于id和number里面的单元格有多个数据的情况怎么办呢?答案就是用聚合函数,聚合函数就用来输入多个数据,输出一个数据的。如cout(id),sum(number),而每个聚合函数的输入就是每一个多数据的单元格。

    (4)例如我们执行select name,sum(number) from test group by name,那么sum就对虚拟表3的number列的每个单元格进行sum操作,例如对name为aa的那一行的number列执行sum操作,即2+3,返回5,最后执行结果如下:

     

    (5)group by 多个字段该怎么理解呢:如group by name,number,我们可以把name和number 看成一个整体字段,以他们整体来进行分组的。如下图

    (6)接下来就可以配合select和聚合函数进行操作了。如执行select name,sum(id) from test group by name,number,结果如下图:

    例:
    数据

     创建表

     create table groupdemo(
     uid string ,
     name string ,
     age int ,
     gender string ,
     address string
     )
     row format delimited fields terminated by "," ;
     load data local inpath "/hive/groupdemo.txt" into table groupdemo ;
    View Code

    sql语句

     select 
     gender ,
     address,
     count(*)  num
     from 
     groupdemo 
     -- where....
     group  by  gender  , address
     -- having num >=2     -- 对分组后的数据进行过滤
     order by num  desc , address  asc
     limit  1  , 2   --  数字一 数据的起始行(0开始计数) 数字二是显示的行数
    View Code

    5. case when

     案例:

    数据

     

    需求:

    求出不同部门男女各多少人。结果如下:

     (1)建表

    create table case_demo(
    name string ,
    dname string ,
    gender string
    )
    row format delimited fields terminated by "	";
    load data local inpath "/root/hive/case.txt" into table case_demo;

    (2)初步尝试

    select
    dname , gender ,
    count(*)   // count(字段) 若字段为null 则不会统计
    from
    case_demo
    group  by dname , gender  ;

    此处的group by用法见4

    (3)第一种语法

    select
    dname ,
    sum(case gender when "男" then 1 else 0 end)  M ,
    sum(case gender when "女" then 1 else 0 end)  F
    from
    case_demo 
    group by dname 
    ;

    结果(此案例答案)

    第二种语法

    select
    * ,
    case  
      when  dname="A" then "销售部" 
      when  dname="B" then "财务部"
      else "" end  cname
    from
    case_demo  ;

     5.2 练习

     有三张表,如下

    准备:

    建立三张表并导入相应的数据

    工资表

    create table gz(
    uid int,
    jb int,
    jj int,
    tc int,
    deptno int
    )
    row format delimited fields terminated by ",";
    load data local inpath "/hive/salary.txt" into table gz;
    View Code

    部门表

    create table bm(
    deptno string ,
    name string
    )
    row format delimited fields terminated by ",";
    load data local inpath "/hive/bm.txt" into table bm;
    View Code

    员工信息表

    create table yg(
    uid int,
    name string,
    gender string,
    age int
    )
    row format delimited fields terminated by ",";
    load data local inpath "/hive/yuangong.txt" into table yg;
    View Code

     (1)求出公司中每个员工的姓名和三类收入中最高那种收入的类型

     sql语句(自己的写法)如下

    select
    yg.name,greatest(gz.jb, gz.jj, gz.tc) max_salary,
    case
    when gz.jb == greatest(gz.jb, gz.jj, gz.tc) then "jb"
    when gz.jj == greatest(gz.jb, gz.jj, gz.tc) then "jj"
    when gz.tc == greatest(gz.jb, gz.jj, gz.tc) then "tc"
    else "" end category
    from
    yg
    join gz
    on gz.uid=yg.uid;

    自己犯的错误:

     when后面不能使用max_salary来代替greatest(gz.jb, gz.jj, gz.tc)

    结果

    改进:使用子查询

    select
    yg.name,
    t.max_sal ,
    t.category
    from
    yg
    join
     (select
     uid ,
     greatest(jb , jj , tc) max_sal,
     case when jj == greatest(jb , jj , tc) then "jj"
     when jb == greatest(jb , jj , tc) then "jb"
     when tc == greatest(jb , jj , tc) then "tc"
     end  category
     from
     gz ) t
    on yg.uid = t.uid;
    View Code

    (2)求出公司中每个岗位(部门)的薪资综合

     自己犯的错:

    select bm.name,sum(gz.jb+gz.jj+gz.tc)
    from bm join gz on
    bm.deptno = gz.deptno ;
    sum(gz.jb+gz.jj+gz.tc)表示求选中的字段对应值的总和,其得到的时一个值,而bm.name为多个值,这样没法查询(sum一般时在分组后使用)

     第一步:获取包含用户名,salary,部门编号的表

    select * from bm join gz on bm.deptno = gz.deptno ;

    结果

     第二步:在第一步的基础上进行分组聚合

    select name, 
    sum(jb+jj+tc) total_salary 
    from
    (select * from bm join gz on bm.deptno = gz.deptno) t 
    group by name;

    结果

     (3)求出公司中每个岗位不同性别员工薪资总和

    知识补充:多表关联的两种方式(以此例为例)

    // 第一种:from 表A join 表B on。。。join 表C on ... 
    select yg.gender,gz.jj ,gz.jb,gz.tc,bm.name from gz join yg on gz.uid=yg.uid join bm on gz.deptno=bm.deptno
    
    // 第二种:from 表A join 表B join 表C on 表A与表B关联条件 and 与表C关联的条件
    select yg.gender,gz.jj ,gz.jb,gz.tc,bm.name from yg join gz join bm on yg.uid = gz.uid and gz.deptno = bm.deptno

    第二种关联形式一定要注意关联条件的顺序

    思路:需求中存在三个表中的字段,所以先要将三张表管关联起来,然后进行分组聚合

    select
    name,gender,
    sum(jb+jj+tc) total_salary 
    from
    (select yg.gender,gz.jj ,gz.jb,gz.tc,bm.name from gz join yg on gz.uid=yg.uid join bm on gz.deptno=bm.deptno) t 
    group by 
    name,gender;

    结果

     (4)求出公司中不同性别、不同年龄阶段(20-30,31-40,41-50)的员工薪资总和

     思路:先对表进行关联操作,获取包含性别,年龄阶段(使用case when 获取)工资的表,然后进行分组聚合

    第一步:获取包含需要字段的表

    select 
    gender,age_level,gz.jb,gz.jj,gz.tc 
    from
    (select gender,uid,
    case
    when age >=20 and age <=30 then "20~30"
    when age >=31 and age <=40 then "31~40"
    when age >=41 and age <=50 then "41~50"
    else "" end age_level
    from yg ) t
    join gz on gz.uid=t.uid

    结果

     第二步:分组聚合

    select
    gender, age_level,
    sum(jb+jj+tc) total_salary
    from
    (select 
    gender,age_level,gz.jb,gz.jj,gz.tc 
    from
    (select gender,uid,
    case
    when age >=20 and age <=30 then "20~30"
    when age >=31 and age <=40 then "31~40"
    when age >=41 and age <=50 then "41~50"
    else "" end age_level
    from yg ) t
    join gz on gz.uid=t.uid
    ) t1
    group by 
    gender, age_level

    结果

     6. 排序

    order by:全局排序
    sort by:每个区内排序

    6.1 设置reduce的个数

    set mapreduce.job.reduces=n;

    查看reduce任务的个数

    set mapreduce.job.reduces;

    6.2 案例:以stu表为例,stu表结构如下

     (1)不指定分区字段

    设置reduce的个数为3(即3个分区)

     sql语句:

    insert overwrite  local directory "/hive/stu_sort/"
    row format delimited fields terminated by "	"
      select * from stu distribute by  sname  sort by sid  desc ;

    结果

     (2)指定分区字段  distribute by  name(按照name的hashcode值 mod reduce任务的个数  从而得到分区数)

    insert overwrite  local directory "/root/hive/stu_sort1/"
    row format delimited fields terminated by "	"
      select * from stu distribute by  name  sort by id  desc ;

    结果

     (3)cluster by

    当分区字段和排序字段相同时,可以直接使用cluster by 相同的字段,下面两种sql写法等价

    select * from stu cluster by id;
    select * from emp distribute by id sort by id;

    (4)小结

      1 order by  全局排序  desc  asc 
      2 sort by   区内排序   默认分区
      3 distribute by  指定分区字段 结合 sort by 区内排序
      4 cluster by  当  distribute by  和 sort by 是同一个字段 且升序的时候使用cluster by 替代
        (只能升序)

      

  • 相关阅读:
    古代汉语:含义“死”的归类
    Inesa 路由器登录信息
    调试第三方源码
    暑假作业日总结
    暑假作业日总结
    暑假作业日总结
    暑假作业日总结
    暑假作业日总结
    暑假作业:《大道至简》读后感
    暑假作业日总结
  • 原文地址:https://www.cnblogs.com/jj1106/p/12107420.html
Copyright © 2011-2022 走看看