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)