zoukankan      html  css  js  c++  java
  • hive

    一.基本介绍

    Hive是基于Hadoop的一个数据仓库工具,底层数据存储在HDFS上;可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能

    Hive本质是将SQL语句转换为MapReduce任务运行

    其他知识:
    DML(data manipulation language)数据操控语言
    常用的select,update,insert,delete;主要用来对数据库的数据进行一些操作
    DDL(data definition language)数据库定义语言
    常用的create,alter,drop;主要是用在定义或改变表的结构,数据类型,表之间的链接和约束等初始化工作上
    DCL(data control language)数据库控制语言
    用来设置或更改数据库用户或角色权限的语句

    元数据:

    存储在hive中数据的描述信息

    hive中元数据包括: 表名, 表的列和分区及其属性,表的属性(内部表和外部表),表的数据所在目录

    Hive 中包含以下数据模型:

      database:在 HDFS 中表现为${hive.metastore.warehouse.dir}目录下一个文件夹

      table:在 HDFS 中表现所属 database 目录下一个文件夹

      external table:与 table 类似,不过其数据存放位置可以指定任意 HDFS 目录路径

      partition:在 HDFS 中表现为 table 目录下的子目录

      bucket:在 HDFS 中表现为同一个表目录或者分区目录下根据某个字段的值进行 hash 散 列之后的多个文件

      view:与传统数据库类似,只读,基于基本表创建

    内部表和外部表的区别:

      删除内部表,删除表元数据和数据

      删除外部表,删除元数据,不删除数据

    优点:

    可扩展性,横向扩展

    延展性

    良好的容错性

    缺点:

    Hive不支持记录级别的增删改

    Hive的查询延时很严重

    Hive不支持事物

    二.常用命令

    数据库中字段不要用大写firstName,可以用下划线first_name

    库:

    ##创建库
    create database t1;   #创建库, 库名大小写不敏感
    create database if not exists t1;
    
    ##查看库
    show databases;   # 显示库名
    
    desc database  mydb2;  #显示库详细信息
    desc database extended mydb2; 
    
    select current_database();  #查看当前使用的库名
    
    show create database t3;  #查看库的创建语句
    
    ##删除库
    drop database db1;  #删除库(库中不含表)
    drop database if exists db2;
    
    drop database if exists t3 cascade; #删除库(库中含表)
    
    #切换库
    use db2; #切换库
    

    ##创建表
    
    CREATE EXTERNAL TABLE IF NOT EXISTS hive_table_user
     (
     userid STRING COMMENT '用户id'
     ,username STRING COMMENT '用户姓名'
     ,sex STRING COMMENT '用户性别'
     ,address STRING COMMENT '家庭地址'
     )
     COMMENT '用户表'
     PARTITIONED BY (pt_d VARCHAR(8) COMMENT '天分区', pt_h VARCHAR(2) COMMENT '小时分区')
     ROW FORMAT DELIMITED
     FIELDS TERMINATED BY '01'
     LINES TERMINATED BY '
    '
     STORED AS ORC
     LOCATION 'hdfs://test01/test02/hive_table_user'  
     TBLPROPERTIES('orc.compress'='ZLIB');
    

    CREATE TABLE

    创建指定名字的表

    EXTERNAL

    表示外部表,建表的同时指定一个指向实际数据的路径

    COMMENT

    为表或字段增加描述
    PARTITIONED BY

    指定分区
    LOCATION

    指定表在HDFS的存储路径

    ##创建默认内部表
    create table student(id int, name string, sex string, age int,department string) row format delimited fields terminated by ",";
    
    ##创建外部表
    create external table student_ext
    (id int, name string, sex string, age int,department string) row format delimited fields terminated by "," location "/hive/student";
    
    ##复制表
    create table student_copy like student;  #加不加external直接决定复制表,和原表的内外无关
    
    use db1;  #进入库,后续操作都在该库中
    
    show tables;  #查看所有表(当前库)
    
    show tables in db2; #查看特定库中所有表
    
    
    show partitions tb1; #查看分区 (表tb1中已有的分区)
    
     #修改表名
    alter table tb1 rename to tb2;
    
    #增加表字段
    alter table tb1 add columns (mathscore int);
    
    #修改表字段
    alter table tb1  change name first_name string; #将name修改为first_name,注意数据类型
    
    ##不支持删除字段
    
    #替换所有字段
    alter table tb1 replace columns (id int,name string,address string)
    
    
    ##分区
    #静态分区,添加一个分区
    alter table tb1 add partition(ptd="20200101")
    #静态分区,添加多个分区
    alter table tb1 add partition(ptd="20200101") partition(ptd="20200102");
    #删除表分区
    alter table tb1 drop partition (ptd="20200101");
    #删除表
    drop table tb1;  #删除内部表:同时删除元数据和数据;删除外部表:只删除元数据
    #清空表
    truncate table tb1;
    
    #查看表中数据条数
    select count(*) from tb1; 
    
    #字段重命名
    select name as first_name from tb1 t;
    
    select name from tb1 t where age>10 and pt_d='20200101';
    
    select name,(case when age>18 then '成年' else '未成年' end )as age_status from tb1 t;
    
    ##插入数据
    
    insert into tb1 (name,age,address,pt_d,pt_h) values('jack','18','china','20200101','14');
    
    
    #join只支持等值链接
    select a.* from a join b on (a.id=b.id and a.name=b.name);
    
    insert overwrite table tb2 partition(pt_d='$date',pt_h='$hour') select tb1.name as first_name,tb1.address from tb1 where tb1.age>18 group by tb1.name;
    

    从本地文件中导入数据给 表

    ###1.在hive中创建表
    use db1;
    create external table if not exists employee(
    	name string comment '姓名'
        ,age int comment '年龄'
        ,address string comment '地址'
    )
    comment '员工信息表'
    partitioned by(pt_d varchar(8) comment '天分区')
    row format delimited fields terminated by ','
    location "hdfs://test/employee"
    
    
    ###2.从本地导入数据
    load data local inpath "/opt/test/employee.txt" into table employee;
    
    ###3.本地数据格式 (分隔符要和建表语句中一致)
    LiHua,20,china
    jack,21,usa
    

    三.sql常用总结

    1.substring

    # 将address按-分割
    select id,name,substring_index(address,'-',1) as city,substring_index(address,'-',-1) as country from employee;
    

    substring_index(str, delim, count) 方法

    str:需要拆分的字符串;

    delim:分隔符,根据此字符来拆分字符串;

    count:当 count 为正数,从左到右数,取第 n 个分隔符之前的所有字符; 当 count 为负数,从右往左数,取倒数第 n 个分隔符之后的所有字符

    2.explode

    explode就是将hive一行中复杂的array或者map结构拆分成多行

    select explode(split(regexp_replace(mvt,'\[|\]',''),'\},\{')) from ods_mvt_hourly where pt_d=20200101 limit 10;
    

    lateral view与explode等udtf就是天生好搭档,explode将复杂结构一行拆成多行,然后再用lateral view做各种聚合

    3.group by

    group_by的意思是根据by对数据按照哪个字段进行分组;

    常用聚合函数: count() , sum() , avg() , max() , min()

    select   字段    from   表名   where    条件     group   by       字段
    
    select   字段    from   表名   group  by    字段    having    过滤条件
    
    student.id student.name student.grade student.salary
    1 zhangsan A 1500
    2 lisi B 3000
    1 zhangsan A 1500
    4 qianwu A 3500
    3 zhaoliu C 2000
    1 huyifei D 2500
    # 查出grade的种类(grade去重)
    select grade from student group by grade;
    
    #slect查的字段必须出现在group中或者查的是字段的聚合函数
    select name,grade from student group by name,grade;
    select name,max(salary) from student group by name,grade;
    

    四.spark sql常用总结

    DataFrame相关

    import org.apache.spark.SparkContext
    import org.apache.spark.sql.SparkSession
    
    val ss = SparkSession.builder()
            .config("spark.sql.crossJoin.enabled","true")
            .config("spark.sql.hive.convertMetastoreParquet","false")
            .config("spark.sql.hive.convertMetastoreOrc","false")
            .enableHiveSupport().getOrCreate()
    val sc=ss.sparkContext
    val sqlContext = ss.sqlContext
    
    //sqlContext传入sql语句,返回DataFrame
    	val sourceDF2=sqlContext.sql("select * from student")
    
        import ss.implicits._
        val sourceDF=Seq(
              ("a","01",1),
              ("a","01",1),
              ("b","02",2),
              ("a","01",3),
              ("b","03",4)
            ).toDF("name","id","age")
    
        sourceDF.printSchema()
    	
    	//select指定列,可以加$也可以 不加
        val df1=sourceDF.select("name")
        val df2=sourceDF.select($"name")
    	
    	//必须加上$表示当前DataFrame,或者直接指定DataFrame
        val df3=sourceDF.select($"name",$"age"+10)
        val df4=sourceDF.select(sourceDF("name"),sourceDF("age")+10)
    
     	val df5=sourceDF.groupBy("name").count()//统计name和相同name个数
        val df6=sourceDF.groupBy("name","id").max("age")//统计name,id,相同保留age最大的
    	
    	//DataFrame注册成表(视图), 然后被sql查询
    	sourceDF.createOrReplaceTempView("student_temp")//一个在Session生命周期中的临时views
    	sourceDF.createGlobalTempView("student_temp2")//不同Session共享的全局临时view
    	val result2=sqlContext.sql("select * from student_temp")
    
     	/**rowRDD指定Schema格式生成DataFrame*/
    
    import org.apache.spark.sql.types._
    import org.apache.spark.sql.Row
    
    	val personRDD=sc.parallelize(
          Seq((1,"apple",101,Array("china","summer"))
            ,(2,"orange",102,Array("usa","winter"))
            ,(3,"strawberry",103,Array("japan","autumn"))
        ))
        //指定schema
        val schema= StructType(
          List(
            StructField("id",IntegerType,false)
            ,StructField("name",StringType,true)
            ,StructField("age",IntegerType,true)
            ,StructField("otherInfo",ArrayType(StringType,true),true)
          )
        )
    
        //RDD映射为rowRDD
        val personRowRDD=personRDD.map(x=>Row(x._1,x._2,x._3,x._4))
        //schema作用到rowRDD生成DataFrame
        val personDF=ss.createDataFrame(personRowRDD,schema)
        //注册表
     	personDF.createOrReplaceTempView("t_person")
    
    import org.apache.spark.SparkContext
    import org.apache.spark.sql.SparkSession
    
    val ss = SparkSession.builder()
            .config("spark.sql.crossJoin.enabled","true")
            .config("spark.sql.hive.convertMetastoreParquet","false")
            .config("spark.sql.hive.convertMetastoreOrc","false")
            .enableHiveSupport().getOrCreate()
    val sc=ss.sparkContext
    val sqlContext = ss.sqlContext
    
    //sqlContext传入sql语句,返回DataFrame
    	val sourceDF2=sqlContext.sql("select * from student")
    
        import ss.implicits._
        val sourceDF=Seq(
              ("a","01",1),
              ("a","01",1),
              ("b","02",2),
              ("a","01",3),
              ("b","03",4)
            ).toDF("name","id","age")
    
        //DataFrame按指定列去重
        val df4=sourceDF.dropDuplicates("name","id")
        df4.show()
    
        //DataFrame全列去重,返回类型为DataSet[Row],再toDF
        val df5=sourceDF.distinct().toDF("name","id","age")
        df5.show()
    
    	//按 name和id分组,重复取age最大的
    	val df2=sourceDF.groupBy("name","id").max("age")
        df2.show()
        //+----+---+--------+
        //|name| id|max(age)|
       // +----+---+--------+
       // |   b| 03|       4|
       // |   a| 01|       3|
       // |   b| 02|       2|
       // +----+---+--------+		
    
    
    

    五.hivesql和mysql用法区别

    1.字符串分割

    hive提供split函数

    select split("a,b,c", ',')[0]; #a
    select split("a,b,c", ',')[2]; #c
    

    mysql提供substring函数

    select substring_index("a,b,c",",",1); #a
    SELECT substring_index(substring_index("a,b,c",',',2),',',-1); #b
    SELECT substring_index(substring_index("a,b,c",',',-2),',',1);#b
    

    六.常见问题

    1.错误 Expression not in GROUP BY key

    在 Group by 子句中,Select 查询的列,要么需要是 Group by 中的列,要么得是用聚合函数(比如 sum、count 等)加工过的列。不支持直接引用非 Group by 的列。这一点和 MySQL 有所区别

    https://help.aliyun.com/document_detail/73777.html

    2.value toDS is not a member of Seq[myPerson]

    def main(args: Array[String]): Unit = {
    	case class myPerson(id:Int,name:String)
    	val sourceDS=Seq(myPerson(1,"tony"),myPerson(2,"jack")).toDS
    }
    

    case class的定义要在引用case class函数的外面。因为我只有一个main函数,所以把case class挪到了外面

    3.com.fasterxml.jackson.databind.JsonMappingException: Incompatible Jackson version: 2.9.2

    因为我的pom.xml配置是spark2.0版本的,因为我的spark2.0版本依赖Jackson版本是2.6+的
    

    所以我们只需要将Jackson2.6版本的引入即可

    <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.6.6</version>
    </dependency>
    

    如果还有错,那么可能是其他包引入了jackson的高版本,在其中将jackson的自动引入剔除即可

    七.参考链接

    Hive学习之路 (七)Hive的DDL操作

    https://www.cnblogs.com/qingyunzong/p/8723271.html

    hive sql语句和mysql用法区别存档

    https://blog.csdn.net/quiet_girl/article/details/85246416

    SQL概述

    https://help.aliyun.com/document_detail/27860.html?spm=a2c4g.11186623.3.3.63f8158ekBecr4

    HIVE存储格式ORC、PARQUET对比

    https://www.cnblogs.com/wuxiaolong4/p/11809291.html

    Spark学习之Spark SQL

    https://www.cnblogs.com/lq0310/p/9842078.html

    1.创建表

    1.1建表语法
    CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name

    [(col_name data_type [COMMENT col_comment], ...)]

    [COMMENT table_comment]

    [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]

    [CLUSTERED BY (col_name, col_name, ...)

    [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]

    [ROW FORMAT row_format]

    [STORED AS file_format]

    [LOCATION hdfs_path]

    1.2参数说明:
    ①EXTERNAL关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION),Hive 创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据
    ②ROW FORMAT 用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,将会使用自带的 SerDe。在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的 SerDe,Hive通过 SerDe 确定表的具体的列的数据
    ③STORED AS 指定用户源文件存储格式,常用的有以下几种: TEXTFILE, 默认格式,建表时不指定默认为这个格式;SEQUENCEFILE,一种Hadoop API提供的二进制文件,使用方便、可分割、可压缩等特点;RCFILE,一种行列存储相结合的存储方式; ORC,hive给出的新格式,属于RCFILE的升级版,性能有大幅度提升.

    1.3样例:

    CREATE EXTERNAL TABLE IF NOT EXISTS hive_table_user
    (
    userid STRING COMMENT '用户id'
    ,username STRING COMMENT '用户姓名'
    ,sex STRING COMMENT '用户性别'
    ,address STRING COMMENT '家庭地址'
    )
    COMMENT '用户表'
    PARTITIONED BY (pt_d VARCHAR(8) COMMENT '天分区', pt_h VARCHAR(2) COMMENT '小时分区')
    ROW FORMAT DELIMITED
    FIELDS TERMINATED BY '01'
    LINES TERMINATED BY ' '
    STORED AS ORC
    LOCATION 'hdfs://test01/test02/hive_table_user'
    TBLPROPERTIES('orc.compress'='ZLIB');

    2.常用的sql命令:
    (1)show tables;
    (2)use db2;
    ...

    #################################################
    ############scala操作hive##################
    import org.apache.spark.sql.{Dataset, SparkSession}

    val ss = SparkSession.builder().getOrCreate()
    val sc = ss.sparkContext
    val sqlContext = ss.sqlContext
    import sqlContext.implicits._

    //读取hive表,获得 Dataset[ROW]
    val contentDF = sqlContext.sql("select userid,mathscore,physicscore,address from user_table where pt_d=20190101").select("userid", "mathscore", "physicscore", "address")
    .where("userid is not null")
    .where("mathscore is not null")
    .where("physicscore is not null")

    删除分区:

    alter table dataTest drop if exists partition(pt_d=20200101)

  • 相关阅读:
    【猫狗数据集】谷歌colab之使用pytorch读取自己数据集(猫狗数据集)
    【python-leetcode480-双堆】滑动窗口的中位数
    hadoop伪分布式之配置文件说明
    hadoop伪分布式之配置日志聚集
    hadoop伪分布式之配置历史服务器
    微服务框架-Spring Cloud
    Spring Cloud和eureka启动报错 解决版本依赖关系
    Spring Cloud提供者actuator依赖
    Eureka 客户端依赖管理模块
    JDK9之后 Eureka依赖
  • 原文地址:https://www.cnblogs.com/ShyPeanut/p/14218093.html
Copyright © 2011-2022 走看看