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 '\001'
 LINES TERMINATED BY '\n'
 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 '\001'
LINES TERMINATED BY '\n'
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)

posted @ 2020-12-31 17:33  等木鱼的猫  阅读(163)  评论(0编辑  收藏  举报