Hive
数据仓库工具。可以把Hadoop下的原始结构化数据变成Hive中的表
支持一种与SQL几乎完全相同的语言HiveQL。除了不支持更新、索引和事务,几乎SQL的其它特征都能支持
可以看成是从SQL到Map-Reduce的映射器
提供shell、JDBC/ODBC、Thrift、Web等接口
Hive简介
起源自facebook由Jeff Hammerbacher领导的团队
构建在Hadoop上的数据仓库框架
设计目的是让SQL技能良好,但Java技能较弱的分析师可以查询海量数据
2008年facebook把hive项目贡献给Apache
Hive现状
Hadoop生态圈中的重要项目
企业级数据仓库的主流架构之一
解决“即席查询”的问题
注意Cloudera的Impala项目,号称比Hive要快3-30倍
兼容SQL是目前大数据产品的风向标
Hive的组件不体系架构
用户接口:shell, thrift, web等
Thrift服务器
元数据库,如Derby, Mysql等
解析器
Hadoop
Hive安装
内嵌模式:元数据保持在内嵌的Derby中,只允许一个会话连接
本地独立模式:在本地安装Mysql,把元数据放到Mysql内
远程模式:元数据放置在远程的Mysql数据库
Hive shell
创建表:
hive> create table stu(
id int,
name string
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE;
从本地文件系统中导入数据到Hive表
hive> load data local inpath 'stu.txt' into table stu;
HDFS上导入数据到Hive表
hive> load data inpath '/home/stu/add.txt' into table stu;
从别的表中查询出相应的数据并导入到Hive表中
hive> insert into table stu
select id, name from stubak;
在创建表的时候通过从别的表中查询出相应的记录并插入到所创建的表中
hive> create table stutest
as
select id, name from stu;
查询
hive> select * from stu;
表连接
hive> select ta.ca, tb.cb from ta join tb on (ta.id=tb.id);
JDBC/ODBC接口
用户可以像连接传统关系数据库一样使用JDBC戒ODBC连接Hive
目前还不成熟
JDBC的具体连接过程
1.使用jdbc的方式连接Hive,首先做的事情就是需要启动hive的Thrift Server,否则连接hive的时候会报connection refused的错误。
启动命令:hive --service hiveserver
2.新建java项目,然后将hive/lib下的所有jar包和hadoop的核心jar包hadoop-*-core.jar添加到项目的类路径上。
3.样板代码
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Class.forName("org.apache.hadoop.hive.jdbc.HiveDriver");
Connection connection = DriverManager.getConnection("jdbc:hive://localhost:10000/default", "", "");
String dropSql = "drop table pokes";
String createSql = "create table pokes (foo int,bar string)";
String insertSql = "load data local inpath '/home/grid/hive/kv1.txt' overwrite into table pokes";
String querySql = "select bar from pokes limit 5";
Statement statement = connection.createStatement();
statement.execute(dropSql);
statement.execute(createSql);
statement.execute(insertSql);
ResultSet rs=statement.executeQuery(querySql);
while(rs.next()){
System.out.println(rs.getString("bar"));
}
}
Web接口
启动:[grid@hadoop1 ~]$ hive --service hwi
假设hive部署在 192.168.0.104 机器上,conf/hive-default.xml文件都是默认值,那么我们直接在浏览器中输入:http://192.168.0.104:9999/hwi/ 就可以访问了
Hive的数据放在哪儿?
数据在HDFS的warehouse目录下,一个表对应一个子目录
桶与reduce
本地的/tmp目录存放日志和执行计划
关于数据类型
存储格式:缺省分隔符
DDL操作
Data Defining Language
定义数据库
定义表
改变数据库存放目录,缺省存放目录由hive.metastore.warehouse.dir指定,可以使用以下命令覆盖
hive> create database testdb1
location '/my/db/testdb1';
观看数据库描述
hive> create database testdb1
comment 'all test tables';
hive> describe database testdb1;
hive> create database testdb1
with dbproperties ('creator'='grid','date'='2015-02-15');
hive> describe database extended testdb1;
切换数据库
hive> use testdb1;
显示当前数据库
hive> set hive.cli.print.current.db=true;
删除和更改数据库,默认不允许用户删除一个包含有表的数据库
hive> drop database if exists testdb1;
级联删除,在删除库之前删除全部的表
hive> drop database if exists testdb1 cascade;
hive> alter database testdb1 set dbproperties ('edited-by' = 'tiger');
列出表
hive> show tables;
观看表的描述
hive> describe extended testdb1.tb1;
hive> describe testdb1.tb1.cl1;
外部表
Hive 创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。这样外部表相对来说更加安全些,数据组织也更加灵活,方便共享源数据。
创建外部表
create external table if not exists etb2
(
id int,
name string
)
row format delimited fields terminated by ','
location '/data/etb2';
创建分区表
create table employees
(
name string,
age int
)
partitioned by (city string);
分区表的存储:会变成一个子目录里面的一系列文件
Strict模式及其对操作的影响
hive> set hive.mapred.mode=strict; 此时查询一定要带上分区条件
hive> set hive.mapred.mode=nonstrict;
列出分区
hive> show partitions employees partition(city='WH');
指定存储格式
create table employees
(
name string,
age int
)
row format delimited
fields terminated by '\001'
collection items terminated by '\002'
map keys terminated by '\003'
lines terminated by '\n'
stored as textfile;
删除和更改表
hive> drop table if exists employees;
hive> alter table employees rename to tb_employees;
hive> alter table tb_employees add if not exists
partition(city='SH') location '/employees/SH'
partition(city='TJ') location '/employees/TJ';
hive> alter table tb_employees partition(city='SH')
set location '/employees/SH1';
列操作
ALTER TABLE log_messages
CHANGE COLUMN hms hours_minutes_seconds INT --列重命名
COMMENT 'The hours, minutes, and seconds part of the timestamp' --列注释
AFTER severity; --更改字段位置
--新增列
ALTER TABLE log_messages ADD COLUMNS (
app_name STRING COMMENT 'Application name',
session_id LONG COMMENT 'The current session id');
--REPLACE COLUMNS 先删除现存列,然后再增加新列。替换列只能在表使用自带SerDe(DynamicSerDe,MetadataTypedColumnsetSerDe, LazySimpleSerDe and ColumnarSerDe)时使用
ALTER TABLE log_messages REPLACE COLUMN (
hours_mins_secs INT COMMENT 'hour, minute, seconds from timestamp',
severity STRING COMMENT 'the message severity',
message STRING COMMENT 'the rest of the message');
DML操作
Data Manipulation Language
传统意义的DML包括Insert,delete,update操作
Hive不支持行级别的insert、delete、update,将数据放入表中的唯一办法是批量载入(bulk load),或使用Hive以外的其它方法。作为数据仓库平台,这种操作逻辑尚可接受。
--Load data
LOAD DATA LOCAL INPATH '${env:HOME}/california-exmployees'
OVERWRITE INTO TABLE employees
PARTITION (country = 'US', state = 'CA');
--insert overwrite
INSERT OVERWRITE TABLE employees PARTITION (country = 'US', state = 'OR')
SELECT * FROM staged_employees se WHERE se.cnty = 'US' AND se.st = 'OR';
FROM staged_employees se INSERT OVERWRITE TABLE employees
PARTITION (country = 'US', state = 'OR') SELECT * WHERE se.cnty = 'US' AND se.st = 'OR'
PARTITION (country = 'US', state = 'CA') SELECT * WHERE se.cnty = 'US' AND se.st = 'CA'
PARTITION (country = 'US', state = 'IL') SELECT * WHERE se.cnty = 'US' AND se.st = 'IL';
--Dynamic Partition Inserts 动态分区
set hive.exec.dynamic.partition=true;
set hive exec.dynamic.partition.mode=nonstrict;
set hive.exec.max.dynamic.partitions.pernode=1000;
INSERT OVERWRITE TABLE employees PARTITION (country, state)
SELECT ..., se.cnty, se.st FROM staged_employees se;
INSERT OVERWRITE TABLE employees PARTITION (country = 'US', state)
SELECT ..., se.cnty, se.st FROM staged_employees se WHERE se.cnty = 'US';
--Create table ... as select ...
CREATE TABLE ca_employees
AS SELECT name, salary, address FROM employees WHERE se.state='CA';
导出数据
由于数据文件本身是文本明文,所以可以直接使用hdfs的拷贝文件导出
如果需要改劢数据格式,可以使用insert overwrite,如下例
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/ca_employees'
SELECT name, salary, address FROM employees WHERE se.state='CA';
查询语句select
大部分语句的语法和常见的关系型数据库Oracle,MySQL等类似,实现的是它们的一个子集
SELECT name, subordinates FROM employees;
使用正则表达式
SELECT symbol, `price.*` FROM stocks;
SELECT name, salary, address FROM employees WHERE address.street LIKE '%Ave.';
explode函数
hive> SELECT array(1,2,3) FROM dual;
[1,2,3]
hive> SELECT explode(array(1,2,3)) AS element FROM src;
1
2
3
--Nested Select
FROM (
SELECT upper(name), salary, deductions["Federal Taxes"] as fed_taxes,
round(salary * (1 - deductions[Federal Taxes])) as salary_minus_fed_taxes
FROM employees
) e
SELECT e.name, e.salary_minus_fed_taxes WHERE e.salary_minus_fed_taxes > 10000;
PS:deductions 是MAP类型
聚组操作优化
SET hive.map.aggr = true;
SELECT count(*), avg(salary) FROM employees;
连接操作
支持大部分常见的关系型数连接方式(各种内连接,外连接,半连接等)
连接是缓慢的操作!
使用“map-side joins”优化连接
MapJoin顾名思义,就是在Map阶段进行表之间的连接。而不需要进入到Reduce阶段才进行连接。这样就节省了在Shuffle阶段时要进行的大量数据传输。从而起到了优化作业的作用。
MapJoin的原理:
即在map 端进行join,其原理是broadcast join,即把小表作为一个完整的驱动表来进行join操作。
SELECT /*+ MAPJOIN(d) */ s.ymd, s.symbol, s.price_close, d.divided
FROM stocks s JOIN dividends d ON s.ymd = d.ymd AND s.symbol = d.symbol
WHERE s.symbol = 'AAPL';
set hive.auto.convert.join=true; --hive 0.11之后,在表的大小符合设置时自动使用MapJoin
SELECT s.ymd, s.symbol, s.price_close, d.divided
FROM stocks s JOIN dividends d ON s.ymd = d.ymd AND s.symbol = d.symbol
WHERE s.symbol = 'AAPL';
--hive.auto.convert.join.noconditionaltask=true
--hive.auto.convert.join.noconditionaltask.size=10000
--hive.mapjoin.smalltable.filesize=25000000
排序
Order by 、sort by 、Distribute by 、Cluster by
1、order by 会对输入做全局排序,因此只有一个reducer
2、sort by 不是全局排序,其在数据进入reducer前完成排序
3、根据 distribute by 指定的内容将数据分到同一个reducer
4、Cluster by
除了具有 Distribute by 的功能外,还会对该字段进行排序。因此,常常认为 cluster by = distribute by + sort by
bucket
抽样查询是数据分析里常见的操作,Hive可以直接支持
SELECT * FROM numbers TABLESAMPLE(BUCKET 3 OUT OF 10 ON rand()) s;
块级抽样
SELECT * FROM numbersflat TABLESAMPLE(0.1 PERCENT) s;
视图与索引
Hive具有与关系型数据库基本类似的视图功能
Hive只有非常简单的索引(早期甚至没有索引),关系型数据库的索引是用B+树算法实现的,Hive的索引叧是简单地把排序数据放到另外一个表中
CREATE INDEX employees_index ON TABLE employees (country)
AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler'
WITH DEFERRED REBUILD
IDXPROPERTIES ('creator'='me', 'created_at'='some_time')
IN TABLE employees_index_table
PARTITIONED BY (country, name)
COMMENT 'Employees indexed by country and name.';
位图索引
Hive 0.8开始引入,适合列上有大量重复值的场景
CREATE INDEX employees_index ON TABLE employees (country)
AS 'BITMAP'
WITH DEFERRED REBUILD
IDXPROPERTIES ('creator'='me', 'created_at'='some_time')
IN TABLE employees_index_table
PARTITIONED BY (country, name)
COMMENT 'Employees indexed by country and name.';
执行计划 Explain