Hive是什么?
hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行.
Hive是构建在Hadoop之上的数据仓库平台,它的创造是为了让非Java程序员更方便使用MapReduce
Hive的工作原理:
接收到一个sql后:
①.词法分析/语法分析:使用antlr将SQL语句解析成抽象语法树-AST
②.语义分析:从Megastore获取模式信息,验证SQL语句中队表名,列名,以及数据类型的检查和隐式转换,以及Hive提供的函 数和用户自定义的函数(UDF/UAF)
③.逻辑计划生产:生成逻辑计划-算子树
④.逻辑计划优化:对算子树进行优化,包括列剪枝,分区剪枝,谓词下推等
⑤.物理计划生成:将逻辑计划生产包含由MapReduce任务组成的DAG的物理计划
⑥.物理计划执行:将DAG发送到Hadoop集群进行执行
⑦.将查询结果返回
Hive架构图:
Hive的用户接口主要有三个: CLI, Client 和 WebUI. 其中最常用的是CLI, CLI启动的时候, 会同时启动一个Hive副本; Client是Hive的客户端, 用户通过连接Hive Server (Thrift Server)连接至Hive, 在启动Client模式时, 需要指出Hive Server所在节点,并且在该节点启动Hive Server; WUI是通过浏览器访问Hive.
Hive将元数据存储在数据库中, 如mysql、derby. Hive中的元数据包括表的名字, 表的列和分区及其属性, 表的属性(是否为外部表等), 表的数据所在目录等.
解释器、编译器、优化器完成HQL查询语句从词法分析、语法分析、编译、优化以及查询计划的生成. 生成的查询计划存储在HDFS中,并在随后有MapReduce调用执行。
Hive的数据存储在HDFS中, 大部分的查询、计算由MapReduce完成(包含*的查询,比如select * from tbl不会生成MapRedcue任务)。
Hive中表的分类:
内部表:
CREATE TABLE table_name
删除表时,元数据与数据都会被删除
外部表:
CREATE EXTERNAL TABLE table_name
删除外部表只删除metastore的元数据,不删除hdfs中的表数据
结构一样,但是数据不一样 ----like
create table bws like te;
结构一样,数据也一样----as
create table bws2 as select * from tes;
Hive添加数据的几种方式:
①将本地的数据导入到hive中:load data local inpath '/root/tes.txt' into table test.usr;
②从hdfs集群导入数据:load data inpath 'hdfs://node01:9000/user/tes.txt' into table test.te;
③insert into---内外部表,不适应于分区
④from table1
insert into(overwrite) tables2 --------overwrite会覆盖该表原有的数据
select id ,name
对数据的约束(外部文件数据的格式),在建表时加上:
ROW FORMAT DELIMITED : 行格式分隔
FIELDS TERMINATED BY ’,’ : 字段之间使用空格分隔
COLLECTION ITEMS TERMINATED BY ‘,’ : 集合(就是这的数据)使用逗号分隔
MAP KEYS TERMINATED BY ‘:’ : 键值对使用冒号分隔
LINES TERMINATED BY ‘\t’ : 记录之间使用换行符分隔
分区:
分区可以把指定范围或指定值的数据放在一起,这样更方便查询,可以减少扫描成本
1.静态分区:必须在表定义时指定对应的partition字段
①单分区建表语句:create table day_table (id int, content string) partitioned by (dt int);
上传数据:load data local inpath '/root/tes.txt' into table test.usr partition (age=10);
②双分区建表语句:create table hour(id int, content string) partitioned by (dt int, hour int);
先以dt为文件夹,再以hour子文件夹区分
增加分区:alter table hour add partition(dt=10,hour=40);
删除分区:alert table tablename drop partiton(dt=20,hour=40); ---如果该dt分区下没有别的分区,会将dt分区也删除
2.动态分区:动态分区只有在 SQL 执行时才能决定
修改权限的方式:①、conf/hive-site.xml
②、在hive内部使用set进行相应的设置
③、hive启动的时候设置 hive --hiveconf hive.exec.dynamic.partiton=true
修改权限:set hive.exec.dynamic.partiton=true //开启动态分区
修改默认状态:set hive.exec.dynamic.partition.mode=nostrict //默认strict,至少有一个静态分区
创建分区表:
create table psn1(
id int,
name string,
likes array<String>,
address map<string ,string>
)
partitioned by (age int ,sex string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ’,’
COLLECTION ITEMS TERMINATED BY ‘,’
MAP KEYS TERMINATED BY ‘:’
LINES TERMINATED BY ‘\n’
写入数据:
from psn1 //已经存在的表格并且要有数据
insert overwrite table pas2 partiton (age,sex)
select * distribute by age,sex
分桶:
对Hive(Inceptor)表分桶可以将表中记录按分桶键的哈希值分散进多个文件中,这些小文件称为桶
开启分桶:set hive.enforce.bucketing=true
创建桶:
create table psnbucket1 (
id int,
name string,
age int)
clustered by (age) into 4 buckets
row format delimited
fields terminated by ','
加载数据:insert into table psnbucket select id,name,age from psn1
抽样:select * from bucket_table tablesample(bucket 1 out of 4 on 分桶字段)
自定义函数:
自定义函数分为三种:
UDF:一对一 继承UDF类,重写evaluate方法
UDAF:多对一
UDTF:一对多
示例:
①
package com.nb.lpq;
import org.apache.hadoop.hive.ql.exec.UDF;
public class TestUdf extends UDF{
/**
* 把传入的参数转化为小写
*
*/
public String evaluate(String input){
if(input == null)
return null;
return input.toLowerCase();
}
/*public static void main(String[] args) {
String abc = evaluate("ABC");
System.out.println(abc);
}*/
}
②把该项目打成jar包,上传到linux集群
③将集群中的jar包上传到hive中:add jar /opt/software/jars/UDF.jar;
④创建自定义(临时)函数:create temporary function bws as "com.hpe.TestUdf.TestUdf"; 引号里是类的路径
⑤使用函数执行 select bws(value) from test;
创建永久自定义函数:在hive-site.xml文件中添加:
<property>
<name>hive.aux.jars.path</name>
<value>file:///opt/module/hive/lib/app_logs_hive.jar</value>
</property>
注意:value中的值为jar包在Linux中的路径,若是多个jar包,以,(逗号)进行分割
配置成功后,直接创建函数:
create function bws as "com.hpe.TestUdf.TestUdf";
使用Jdbc连接Hive:
①在hive-site.xml文件中必须有如下配置:
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://localhost:3306/hivecreateDatabaseIfNotExist=true</value>
<description>JDBC connect string for a JDBC metastore</description>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
<description>Driver class name for a JDBC metastore</description>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
<description>username to use against metastore database</description>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>root</value>
<description>password to use against metastore database</description>
</property>
②在虚拟机执行命令:hiveserver2
③编写Jdbc代码
package com.nb.lpq;
import java.sql.*;
/**
* @Author KNIGHT
* @Date 2019/6/21 20:12
*/
public class TestJdbc {
private static String driverName = "org.apache.hive.jdbc.HiveDriver";
public static void main(String[] args) throws SQLException {
try {
//加载驱动信息
Class.forName(driverName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.exit(1);
}
//建立连接
Connection conn = DriverManager.getConnection("jdbc:hive2://IP地址:10000/test", "root", "root");
Statement stmt = conn.createStatement();
String tableName = "psn1";
// 删除表,创建表
// stmt.execute("drop table if exists " + tableName);
// stmt.execute("create table " + tableName + " (key int, value string)");
// System.out.println("Create table success!");
// 展示表
String sql = "show tables '" + tableName + "'";
ResultSet resultSet = stmt.executeQuery(sql);
if(resultSet.next())
System.out.println(resultSet.getString(1));
}
}