赞
踩
Hive是一个建立在Hadoop基础之上的数据仓库工具,以HiveQL(类SQL)的操作方式让我们能够轻松的实现分布式的海量离线数据处理。而不必去编写调试繁琐的MR程序。
数据仓库是一个面向主题的,稳定的,集成的,反应历史数据的数据存储工具,他主要支持管理者的决策分析。
Hive安装非常简单,解压之后即可直接运行,不需要太多配置,前提是要配置JAVA_HOME和HADOOP_HOME。并且Hadoop要全量启动(五个进程)
schematool -dbType derby -initSchema
在/home/app/apache-hive-2.3.6-bin/bin目录下执行
./hive
create database jtdb;
结论1:Hive中的数据库,其实就是HDFS中/user/hive/warehouse目录下的以.db结尾的文件夹。
create table tb_user(id int,name string);
结论2:Hive中的表其实就是HDFS中对应数据库文件夹下的一级文件夹。
insert into table tb_user values(1,"dongcc");
结论3:Hive在必要的时候会将HQL编译为MR来执行,上图展示了变异后的MR执行的过程。
结论4:hive中的数据在HDFS中以文件的形式存储在其所在表的文件夹中。
结论5:默认数据库default没有自己单独的文件夹,其下的表直接存放在/user/hive/warehouse下。
Load data local inpath '/home/data/book1.txt' into table table_name;
其中,local关键字为标识从本地文件系统中读取文件,如果不加,默认从HDFS中读取指定文件。
Hive没有将描述数据库、表、数据之间关系的元数据直接存放在HDFS中,而是存放在了传统的关系型数据库中,这样保证了元数据可以快速的进行增删改查。
Hive原生的将元数据保存在了内置的Derby数据库中。
Derby存在的问题:过于轻量级,性能较低,安全性不高,不适合生产。
这种情况我们是无法忍受的,实际开发中不会使用Derby来做Hive的元数据库。所以我们要将他替换掉。以mysql为例。
<?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驱动包上传到hive的lib目录中即可
/home/app/apache-hive-2.3.6-bin/lib
进入mysql客户端(命令行)执行
grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option;
flush privileges;
schematool -dbType mysql -initSchema
内部表和外部表
创建语句:
create table table_name (id int,name string) row format delimited fields terminated by '\t';
加载数据:
load data local inpath '文件路径' into table table_name;
删除表:
drop table table_name;
删除表时,连同数据一起被删除。
再次加载数据一样可以被管理到。
Hive中先有数据后创建表来管理数据的表叫做外部表。
创建表:在创建之前先要有数据。
create external table table_name (id int ,name string) row format delimited fields terminated by '\t' location 'HDFS中文件所在路径';
删除表:
drop table table_name;
外部表在删除时,只会将元数据信息删掉,而不会删除数据本身。
再次加载数据一样可以被管理。
在hive中数据的面向主题存储就是由表的分区来实现的。
create table table_name (id int,name string) partitioned by (country string) row format delimited fields terminated by '\t';
与普通表相比只是多了partitioned by (country string)
load data local inpath '文件位置' overwrite into table table_name partition (country='CHN');
经过查看HDFS中存储发现:
分区在表所在目录中以文件夹形式存在,数据落在分区目录中,并且分区文件夹以分区类型=分区名定义如上图country=CHN;
另外在select * from tb_par;时发现:
分区信息查询结果中展示多出了一列,这并不是给数据增加了一个字段。而是单独的分区信息绑定,当然你可以把它当做一个字段来使用,比如作为条件查询。
创建多级分区表:
create table table_name (id int,name string) partitioned by (country string, gender string) row format delimited fields terminated by '\t';
加载数据:
load data local inpath '/home/data/JPA_female.txt' overwrite into table tb_par2 partition (country='JPA',gender='female');
查看元数据:发现分区就是多了几级目录。
查询多级分区目录:
select * from tb_par2 where gender = 'female' and country = 'JPA';
注意:在实际的生产中分区不是随意设置的,也不是越多越好,而是将经常查询的维度设置为分区即可!
在测试过程中,每次都将全表数据加载进来会花费非常多的时间,而随意截取部分数据进行测试又不具有代表性,这时我们可以使用分桶的方法,来减少测试数据量,并使结果具有较高的代表性。
创建测试数据表:
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 table_name (id int,name string) clustered by (id) into 4 buckets row format delimited fields terminated by ',';
开启分桶模式:
Hive默认未开启多个reduce,分桶需要多个reduce同时工作,所以这里要开启分桶模式:
set hive.enforce.bucketing=true;
然后进行导入:这个过程时间较长,桶越多时间越长。
insert into table table_name select * from tb_data;
数据顺序发生了改变,查看HDFS存储发现整个文件被拆分成四部分,自动命名0~3;
select * from table_name tablesample (bucket x out of y on id);
其中x为第几个桶,不能大于总桶数, y为选取数据的步长(几个桶取一次数据)。Y应为桶数的因数或倍数,当y大于桶数时,选取结果非整桶抽取,而是抽取每桶中的y除以桶数分之一,即:1/(y/桶数)
按百分比取样:整表数据额百分之三十
select * from table_name tablesample(30 percent);
在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优势更大。但是在业务逻辑非常复杂的情况下还是需要开发MapReduce程序更加直接有效。
不能。传统数据库要求能够为系统提供实时的增删改查,而Hive不支持行级别的增删改,查询的速度也不比传统关系型数据库,而是胜在吞吐量高,所以不能作为关系型数据库来使用。
Hive的使用中需要将HQL编译为MR来运行,所以在执行效率上要低于直接运行MR程序。但是对于我们来说,由于只需要编写调试HQL,而不用开发调试复杂的MR程序,所以工作效率能够大大提高。
Hive不支持行级别的增删改的根本原因在于他的底层HDFS本身不支持。在HDFS中如果对整个文件的某一段或某一行内容进行增删改,势必会影响整个文件在集群中的存放布局。需要对整个集群中的数据进行汇总,重新切块,重新发送数据到每个节点,并备份,这样的情况是得不偿失的。所以HDFS的设计模式使他天生不适合做这个事
HDFS只提供追加写的API. 如果非要跟新,HDFS就得先把整个文件全部下载下来,修改完了,再重新覆盖上传 ,效率极低.
Hive是什么? 是一个基于Hadoop的数据仓库客户端,使用SQL的方式操作.内置了非常丰富的函数库.并且支持自定义函数.
数据仓库? 一个面向主题的,稳定的,集成的,反应历史数据的数据存储系统,一般为管理者提供决策分析的数据支持.
内部表: 先创建表然后在表中写数据
外部表: 托管表:先有数据,然后根据数据文件的格式,创建表结构,然后将表结构映射在数据上
内部表删除数据时,元数据和表数据都会被删除,外部表删除时,元数据会被删除,表数据则不会被删除
分区表:Hive作为数据仓库实现面向主题的唯一方式.
分桶表:只在测试阶段使用,为了解决,数量大,并且数据依据时间或者类似其他维度有规律.测试时如果全量原始数据加载测试,耗时太长,如果随意抽取部分数据结果不具有代表性,可能会影响判断. 此时,使用分桶表来解决这个数据抽样问题
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。