hive
Hadoop的MapReduce在海量数据离线处理中遇到的问题
- MR程序代码量较大,开发调试复杂,不适合要求快速得出结果的工作场景.
- Hadoop是用Java开发,MR天生对Java支持最好的,对于其他语言的使用者,不够友好.
- 想要编写一个优秀的MR程序,必须掌握Hadoop的一些底层原理.API冗长繁琐不好记忆.
概念:
Hive是一个基于Hadoop的数据仓库工具(本质是Hadoop的一个客户端),他的出现避免了传统MR开发的弊病,允许开发者使用简单的SQL来实现海量数据的离线处理,并且内置了非常丰富的函数库供开发者直接调用,同时在内置函数不够用的时候还支持UDF(用户自定义函数)
面向仓库
数据仓库是一个面向主题的稳定的,继承的反应历史数据的数据存储系统,一般用于为管理者提供决策分析的数据支持。
安装Hive
hive上传和解压
复制conf文件下的hive-default.xml.template为hive-site.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>hive.default.fileformat</name>
<value>TextFile</value>
</property>
<property>
<!--端口改为你自己的端口,这里是连接数据库中hive数据库-->
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://hadoop01:3306/hive?createDatabaseIfNotExist=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>
<!--连接MySQL的用户名-->
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
<description>username to use against metastore database</description>
</property>
<property>
<!--连接MySQL的密码-->
<name>javax.jdo.option.ConnectionPassword</name>
<value>root</value>
<description>password to use against metastore database</description>
</property>
</configuration>
上传mysql的驱动jar包(官网下载)
# 进入mysql
mysql
# 进入mysql客户端(命令行)执行
grant all privileges on *.* to 'root'@'hadoop01' identified by 'root' with grant option;
flush privileges;
# 初始化
schematool -dbType mysql -initSchema
如果出现错误:
grant all privileges on *.* to 'root'@'hadoop01' identified by 'root' with grant option;
flush privileges;
启动
在/home/app/apache-hive-2.3.6-bin/bin目录下执行
./hive
测试案例
新建数据库
create database test;
查询数据库
show databases;
新建表 (注意 :hive是基于Java开发的,所以字段的属性都是Java的定义类型)
create table tb_user(id int,name string ,age int);
插入数据
insert into tb_user(1,"3",3);
查询数据
select * from tb_user;
其他操作
将本地文件添加到数据库
# 创建表选择分割方式(以"\t"为例 \t是代表分割符)
create table tb_book1 (id int,name string) row format delimited fields terminated by "\t";
# 插入文件
load data local inpath '/home/data/book1.txt' into table tb_book1;
外部表(EXTERNAL_TABLE)
先准备数据,然后将不熬结构投影在准备好的数据之上形成表的形式
create external table tb_name(属性1,属性2) row format delimited fields terminated by "分割符" location "位置";
分区表
是hive实现面向主题的方式(分区不是越多越好)
分区表的建立
create table tb_par(建表属性) partitioned by (分区属性) row format delimited fields terminated by "\t";
例子
create table tb_par(id int,name string) partitioned by (country string) row format delimited fields terminated by "\t";
插入数据
load data local inpath "文件位置" into table tb_par partition (分区信息);
例子
load data local inpath "/home/data/CHN.txt" into table tb_par partition (country="CHN");
load data local inpath '/home/data/JPA_female.txt' overwrite into table tb_par2 partition (country='JPA',gender='female');
追加数据
alter table tb_par add partition ( country = "JPN" ) location "/user/hive/warehouse/jt.db/tb_par/JPN.txt";
分桶表
用于解决在测试环节全量数据参与运算太慢,但随意的抽取部分数据又不具有代表性的问题
建表
create table tb_data (id int,name string) row format delimited fields terminated by ",";
--插入数据
load data local inpath '/home/data/teachers.txt' into table tb_data;
创建分桶的表
--创建桶表
create table tb_name (属性1,属性2,.... ) clustered by (属性) into y bucket
--开启分批次
set hive.enforce.bucketing=true;
--插入数据
insert into table tb_name select * from tb_data;
--查询数据
select * from tb_name;
--分桶查询(x代表第几桶,y代表共几桶,x<y)
select * from tb_name tablesample (bucket x out of y on id);
例子
--创建桶表
create table tb_buc (id int,name string ) clustered by (id ) into 4 bucket
--开启分批次
set hive.enforce.bucketing=true;
--插入数据
insert into table tb_buc select * from tb_data;
--查询数据
select * from tb_buc;
--分桶查询(按桶进行数据取样)
select * from tb_buc tablesample (bucket 4 out of 4 on id);
--分桶查询(按比例 进行数据取样)
select * from table_name tablesample(30 percent);
进阶:hivejdbc
在Hadoop配置文件中加入以下内容
hdfs-site.xml
<property>
<name>dfs.webhdfs.enabled</name>
<value>true</value>
</property>
core-site.xml
<property>
<name>hadoop.proxyuser.root.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.root.groups</name>
<value>*</value>
</property>
启动hiveserver2
在hive安装目录下的bin目录中执行
./hiveserver2
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.tedu</groupId>
<artifactId>flume</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>2.3.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
</dependencies>
</project>
代码
package cn.tedu.flume;
import java.sql.*;
public class HiveJDBC {
private static String driverName = "org.apache.hive.jdbc.HiveDriver";
/**
* @param args
* @throws SQLException
*/
public static void main(String[] args) throws SQLException {
try {
Class.forName(driverName);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.exit(1);
}
Connection con = DriverManager.getConnection("jdbc:hive2://hadoop01:10000/default", "root", "");
Statement stmt = con.createStatement();
String dbName = "test";
String tableName = dbName+".tb_test";
System.out.println("insert into table "+ tableName + " values(1, 'dongcc')");
stmt.execute("drop database if exists " + dbName);
stmt.execute("create database " + dbName);
stmt.execute("drop table if exists " + tableName);
stmt.execute("create table " + tableName + " (key int, value string)");
stmt.execute("insert into table " + tableName + " values(1, 'dongcc')");
// show tables
String sql = "select * from "+tableName;
System.out.println("Running: " + sql);
ResultSet res = stmt.executeQuery(sql);
if (res.next()) {
System.out.println(res.getString(1));
System.out.println(res.getString(2));
}
}
}
补充
数据仓库和关系型数据库的区别:
数据库 | 数据仓库 |
---|---|
面向事务 | 面向主题 |
实时数据 | 历史数据 |
避免冗余 | 有意冗余 |
捕获数据 | 分析数据 |
为用户提供服务 | 为管理者提供服务 |
所有的离线数据处理场景都适用hive吗?
并不是所有场景都适合,逻辑简单又要求快速出结果的场景Hive优势更大。但是在业务逻辑非常复杂的情况下还是需要开发MapReduce程序更加直接有效。
Hive能作为业务系统的数据库使用吗?
不能。传统数据库要求能够为系统提供实时的增删改查,而Hive不支持行级别的增删改,查询的速度也不比传统关系型数据库,而是胜在吞吐量高,所以不能作为关系型数据库来使用。
Hive与传统MR方式处理数据相比能够提高运行效率吗?能够提高工作效率吗?
Hive的使用中需要将HQL编译为MR来运行,所以在执行效率上要低于直接运行MR程序。但是对于我们来说,由于只需要编写调试HQL,而不用开发调试复杂的MR程序,所以工作效率能够大大提高。
Hive为什么不支持行级别的增删改?
Hive不支持行级别的增删改的根本原因在于他的底层HDFS本身不支持。在HDFS中如果对整个文件的某一段或某一行内容进行增删改,势必会影响整个文件在集群中的存放布局。需要对整个集群中的数据进行汇总,重新切块,重新发送数据到每个节点,并备份,这样的情况是得不偿失的。所以HDFS的设计模式使他天生不适合做这个事