Hive
一、了解 Hadoop 生态的中的 Hive
1、简介
- 分布式存储大型数据集的查询和管理
- hive 通过类 sql 的 hql 语句转化为 hadoop 的 map reduce 程序,然后去 hadoop hdfs 中查询后返回结果
- hive 是对 map reduce 的一层封装
2、历史
起源自 facebook 由 Jeff Hammerbacher 领导的团队
构建在 Hadoop 上的数据仓库框架
设计的目的是让 Java 技能较弱的分析师可以通过类 SQL 查询海量数据
2008 年 facebook 把 hive 项目贡献给 Apache
二、Hive 组件与体系架构
1、组件
用户接口 : shell Client、thrift(自动生成Java代码)、web UIThrift 服务器:提供了可以远程访问其他进程的功能,也提供使用 JDBC 和 ODBC 访问 hive 的功能,这些都是基于 Thirft 实现的元数据库 (MetAStore) "Derby,Mysql" 等解析器 : 输入 SQL 映射为 MapReduce 的 jobHadoop : Hive 的数据都是放在 Hadoop 里面的
2、构架图

3、端口
| 端口 | 说明 | 详细 |
|---|---|---|
| 0 0.0.0.0:10000 | hiveserver 服务端口 | Thrift Server 服务器 |
三、Hive 安装
1、三种安装模式
- 1) 内嵌模式 元数据保持在内嵌的 Derby 数据库中,一次只能有一个连接会话。
- 2) 本地独立模式 在本地安装 Mysql , 把元数据放到 Mysql 中
- 3) 远程模式 元数据放到远程的 Mysql 数据库中
2、我们采用 cloudera manager 部署
四、操作 Hive
提醒事项
(读本章前,请选阅读 hive-problem.md 你会少走很多弯路,以后把遇到的问题都整理到 hive-problem.md 文档下)
1、Hive Sql
- 部署完成以后,通过 shell 命令操作
- 更多语法参见:链接
1) 显示所有数据库SHOW DATABASES;2) 使用指定数据库use x_DATABASE;3) 显示所有表SHOW TABLEs;4) 删除表DROP TABLE xxx;5) 删除数据库DROP DATABASE xxx;6) 创建表看下面的详细说明7) 重命名表 student to student2ALTER TABLE student rename to student2;8) 列操作-- 增加列ALTER TABLE student add columns(sage int comment "the student's age");-- 替换,仅保存被替换的列(可以用来删除)ALTER TABLE student replace columns(s1 string ,s2 int, s2 int);-- 重命名列ALTER TABLE TABLE_name CHANGE old_col_name new_col_name String;-- 修改列的数据类型ALTER TABLE TABLE_name CHANGE [COLUMN] col_old_name col_new_name column_type [COMMENT col_comment] [FIRST|AFTER column_name]如:ALTER TABLE TABLE_name CHANGE status status INT;9) 查看表结构DESC student;-- 查看表结构信息(表目录/格式等详信息)DESC formatted table;-- 查看表的分区详细信息(表分区目录/格式等详信息)DESC formatted table PARTITION(p_a='a',p_b='b');9.1) 表属性修改操作-- 修改表 SERDEPROPERTIES 信息ALTER TABLE table SET SERDEPROPERTIES('hbase.columns.mapping'='XXX');-- 修改表 TBLPROPERTIES 信息ALTER TABLE table SET TBLPROPERTIES('a'='XXX');10) 分区信息查看分区SHOW PARTITIONS db.tb;SHOW PARTITIONS db.tb PARTITION(p_dt);SHOW PARTITIONS db.tb PARTITION(p_dt='2017-04-08');添加分区ALTER TABLE table ADD IF NOT EXISTS PARTITION (p_dt = '2015-07-13')删除分区ALTER TABLE table DROP IF EXISTS PARTITION (p_dt = '2015-06-28');11) 截断表 (貌似无用)RUNCATE TABLE student;12) 按照模板复制表CREATE TABLE empty_TABLE_name LIKE TABLE_name;13) 查看数据库结构DESC DATABASE dbname;14) 查看创建表语句SHOW CREATE TABLE tb_name;15) 创建数据指定文件路径,注意加引号CREATE DATABASE db_name LOCATION '/user/hive/uba_log';16) 查询数据保存到文件中hive -e "SELECT * FROM access_log.access_log_20150326 WHERE hostname='api.angejia.com' LIMIT 1" >> /tmp/log.log17) 通过 sql 通过文件执行,把结果输出到文件中bin/hive -f sql.q >> /tmp/log.log18) CASE 字句CASEWHENa.account_type = 1 THEN 'broker'WHENa.account_type = 2 THEN 'agcy'ELSE'CCC'END AS start_and_end19) JOINLEFT JOIN 返回左边所有符合 WHERE 语句的记录,右表匹配不上的的字段值用 NULL 代替RIGHT JOIN 返回右边表所有符合 WHERE 语句的记录。左表匹配不上的的字段值用 NULL 代替NOT IN 查询ONbs_tb.a_1 = on_tb.b_1WHEREon_tb.a_1 is null20) 排序参考文章:http://wenku.baidu.com/link?url=j_mZCBQ7R_f_XOBjfYVSECVbS7e7qV9ajmc46_V_pN8ClJp2i-1k4mlEKQxNyr5hYYZGyHZbrrCDLGqjCmoMJtRUk_vg4QCSsR9ANZFvdbqORDER BY解释:会对输入做全局排序,因此只有一个reducer问题:1、在hive.mapred.mode = strict 模式下 必须指定 LIMIT 否则执行会报错2、原因: 在order by 状态下所有数据会到一台服务器进行reduce操作也即只有一个reduce,如果在数据量大的情况下会出现无法输出结果的情况SORT BY解释:sort by 不是全局排序,其在数据进入(reducer前完成排序)问题:1、如果用sort by进行排序,并且设置 (mapred.reduce.tASks>1), 则sort by只保证每个reducer的输出有序,不保证全局有序2、sort by 的数据只能保证在同一 reduce 中的数据可以按指定字段排序3、使用sort by 你可以指定执行的reduce 个数 (SET mapred.reduce.tASks=<number>),对输出的数据再执行归并排序,即可以得到全部结果。distribute by解释:按照指定的字段,对数据进行划分到不同的,输出 reduce 文件中人话:就是把结果按照 p_dt(如日期) 划分到同类型的 reduce 文件中例子:SELECTid,p_dtFROMTABLE_ndistribute byp_dtCluster By解释:cluster by 除了具有 distribute by 的功能外还兼具 sort by 的功能。问题:但是排序只能是倒序排序,不能指定排序规则为 ASC 或者DESC组合使用FROMrecord2SELECTyear,temperaturedistribute byyearsort byyear ASC,temperature DESC;21) 模糊匹配LIKERLIKE '正则'22) 字段类型转换WHERE cASt(aa AS float) < 1000;23) DESCRIBEDESCRIBE invites; 显示表结构DESCRIBE function substr; 显示函数用法DESCRIBE EXTENDED valid_records; 显示函数用法24) TBLPROPERTIES 表级属性,如是否外部表,表注释等SHOW TBLPROPERTIES db_name.tb_name;transient_lAStDdlTime 最后创建修改表时间25) 统计(分析和描述)统计表的分区状态ANALYZE TABLE [TABLEName] PARTITION([p_dt]) COMPUTE STATISTICS noscan;1. 案例ANALYZE TABLE db_name.tb_name PARTITION(p_dt) COMPUTE STATISTICS noscan;ANALYZE TABLE db_name.tb_name PARTITION(p_dt='2016-04-01') COMPUTE STATISTICS noscan;26) LOCKS 查看表锁S 共享锁: 读锁, 事物 T 锁上对象 A 被后, 可读, 不可写. 其他事物在对象 A 上不可再加锁、不可改、只可读.X 互斥锁: 写锁, 事物 T 锁上对象 A 被后, 可读, 可写. 其他事物在对象 A 不可再加锁、不可读、不可改.SHOW LOCKS; 显示所有锁SHOW LOCKS db_name.tb_name extended; 显示表锁SHOW LOCKS db_name.tb_name PARTITION(p_dt='xx'); 显示指定分区锁UNLOCK TABLE dw_db.dw_product_safe_use_log PARTITION(p_dt='xx'); 解锁分区27) 修复表(根据文件修复分区)MSCK REPAIR TABLE table_name28) 设置提交任务提交队列 mapred-site.xmlmapreduce.job.queuename=root.default29) FROM INSERT 语法FROM (SELECT * FROM db.tb WHERE type = 'x') AS mINSERT OVERWRITE TABLE db.tb_2 PARTITION(type)SELECT m.*;
2、HIVE DDL
2.1、创建表
*) 分隔符语法CREATE TABLE employees(name STRING,salary FLOAT,-- 数组类型subordinates ARRAY(STRING),-- MAPdeductions MAP(STRING,FLOAT),-- 映射address STRUCT<street:STRING,city:STRING,state:STRING,zip:INT>)--必须写在下面的子句之前(stored AS 除外)ROW FORMAT DELIMITED--Hive 将使用 ^A 做为列分隔符FIELDS TERMINATED BY '\001'--Hive 将使用 ^B 做为集合元素间分隔符COLLECTION ITEMS TERMINATED BY '\002'--Hive 将使用 ^C 做为 MAP 的键值之间的分隔符MAP KEYS TERMINATED BY '\003'-- 到目录前为止 Hive 对于 lines terminated by 公支持 \n 也就是说行与行之间分隔符只能是 \nLINES TERMINATED BY '\n'STORED AS TEXTFILE;文本分隔符:\n 文本文件的换行符^A 分隔字段(列),在 CREATE TABLE 语句中可以使用八进制编码(\001)表示^B 分隔 ARRAY 或者 STRUCT 中的元素,或用于 MAP 中键值对之间的分隔,使用八进制编码(\002)表示^C 用于 MAP 中键和值之间的分隔,使用八进制编码(\003)表示1) 普通表CREATE TABLE student(sid int,sname string)ROW FORMAT DELIMITEDFIELDS TERMINATED BY '\001'LINES TERMINATED BY '\n'STORED AS TEXTFILE;2) 创建分区表 (ds 为分区字段)CREATE TABLE student_index(sid int , sname string) PARTITIONed by (ds string)ROW FORMAT DELIMITEDFIELDS TERMINATED BY '\001'LINES TERMINATED BY '\n'STORED AS TEXTFILE;3) 创建二级分区表 (teacher、nickname 为分区字段,加上备注)CREATE TABLE clASsmem_index_1(student string,age int) PARTITIONed by(teacher string comment 'the teacher',nickname string comment 'the nickname')ROW FORMAT DELIMITEDFIELDS TERMINATED BY '\001'LINES TERMINATED BY '\n'STORED AS TEXTFILE;4) 创建 PARQUET 文件格式的表CREATE TABLE parquet_TABLE_name (x INT, y STRING) STORED AS PARQUET;INSERT OVERWRITE TABLE parquet_TABLE_name SELECT * FROM other_TABLE_name;OR-- 使用目标表的数据, 创建一张 parquet 格式的表CREATE TABLE IF NOT EXISTS parquet_TABLE_nameSTORED AS PARQUETASSELECT * FROM other_TABLE_name LIMIT 10;5) 创建 SEQUENCEFILE 文件格式的表CREATE TABLE sequencefile_TABLE_name (x INT, y STRING) STORED AS SEQUENCEFILE;INSERT OVERWRITE TABLE sequencefile_TABLE_name SELECT * FROM other_TABLE_name;6) 创建 ORC 格式的数据表CREATE TABLE orc_TABLE_name (x INT, y STRING) STORED AS ORC;INSERT OVERWRITE TABLE orc_TABLE_name SELECT * FROM other_TABLE_name;7) 创建任意格式表(案例是 TEXTFILE)CREATE TABLE IF NOT EXISTS other_tableROW FORMAT DELIMITEDFIELDS TERMINATED BY ','STORED AS TEXTFILEASSELECT a,b FROM table;
2.2、生产环境的创建表
可以事先把数据写入到 hadoop hdfs 中 hive 表的对应目录中,这样就可以先创建表,再导入数据了。如案例 1)
1) 创建内部(内部表根据数据库创建时的路径指定到对应的目录下)数据表,<正则格式化>CREATE TABLE access_log_20150326 (request_time string,upstream_response_time string,remote_addr string,request_length string,upstream_addr string,server_date string,server_time string,hostname string,method string,request_uri string,http_code string,bytes_sent string,http_referer string,user_agent string,gzip_ratio string,http_x_forwarded_for string,auth string,mobile_agent string)ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'WITH SERDEPROPERTIES ("input.regex" = "(.*?)\\t(.*?)\\t(.*?)\\t(.*?)\\t(.*?)\\t\\[(.+?)T(.+?)\\+.*?\\]\\t(.*?)\\t(.*?)\\s(.*?)\\s.*?\\t(.*?)\\t(.*?)\\t(.*?)\\t(.*?)\\t(.*?)\\t(.*?)\\t(.*?)\\t(.*?)","output.format.string" = "%1$s %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s %10$s %11$s %12$s %13$s %14$s %15$s %16$s %17$s %18$s")STORED AS TEXTFILE;2) 创建内部(内部表根据数据库创建时的路径指定到对应的目录下)数据表,<json 格式化>CREATE TABLE `uba_web_visit_log_20150326`(`uid` string COMMENT 'FROM deserializer',`ccid` string COMMENT 'FROM deserializer',`referer` string COMMENT 'FROM deserializer',`url` string COMMENT 'FROM deserializer',`guid` string COMMENT 'FROM deserializer',`client_time` string COMMENT 'FROM deserializer',`page_param` string COMMENT 'FROM deserializer',`client_param` string COMMENT 'FROM deserializer',`server_time` string COMMENT 'FROM deserializer',`ip` string COMMENT 'FROM deserializer',`agent` string COMMENT 'FROM deserializer')ROW FORMAT SERDE'org.apache.hadoop.hive.contrib.serde2.JsonSerde'3) 创建外部表(关键字 EXTERNAL),分区表,并且指定表的路径 <FIELDS格式化',' COLLECTION格式化'\t'>CREATE EXTERNAL TABLE student_index(sid int ,sname string) PARTITIONed by (ds string)ROW FORMAT DELIMITEDFIELDS TERMINATED BY '\001'LINES TERMINATED BY '\n'STORED AS TEXTFILE-- 指定表的数据源,可写可不写LOCATION 'hdfs://NameNode:8020/user/test/student_index';
3、导入数据
三种模式
- 从本地文件导入数据
- HDFS上导入数据到Hive表
- 从别的表中查询出相应的数据并导入到Hive表中
3.1、 从本地文件导入数据
hive表默认的分隔符是’\001’
*** 执行本地导入,OVERWRITE 表示覆盖hive> LOAD DATA LOCAL INPATH '/root/student_two.txt' OVERWRITE INTO TABLE student;向分区表导入数据(ds为分区字段名称,ds=111 表示把匹配111的数据,导入到当前表目录的一个文件中)LOAD DATA LOCAL INPATH '/home/hadoop/DATA/student_index.log' OVERWRITE INTO TABLE student_index PARTITION(ds='111');查看 dfs 文件接口hive> dfs -ls /user/hive/warehouse/jASon_test.db/wyp;
3.2、HDFS上导入数据到Hive表
*** hdfs 导入hive> LOAD DATA INPATH '/home/wyp/add.txt' OVERWRITE INTO TABLE wyp;
3.3、从别的表中查询出相应的数据并导入到 Hive 表中
1) *** 如果需要分区插入设置线下hive> SET hive.exec.dynamic.PARTITION.mode=nonstrict;2)*** 其他表导入数据(其中 age 是动态的分区)hive> INSERT INTO TABLE testPARTITION (age)SELECT id, name,tel, age FROM wyp;
4、hive TABLE 导出数据
三种方式
- (1)导出到本地文件系统
- (2)导出到 HDFS 中
- (3)导出到 Hive 的另一个表中
4.1、导出到本地文件系统
row format delimitedFIELDS TERMINATED BY '\001' 字段分隔符是 '\001'LINES TERMINATED BY '\n' 行分隔符是 '\n'语法:INSERT OVERWRITE LOCAL directory <to_file_dir><row format delimited><FIELDS TERMINATED BY '\001'><LINES TERMINATED BY '\n'><fields><FROM_TABLE_name>命令:INSERT OVERWRITE LOCAL directory 'to_file_dir'row format delimitedFIELDS TERMINATED BY '\001'LINES TERMINATED BY '\n'SELECT fields FROM FROM_TABLE_name;
4.2、导出到 HDFS 中
4.3、导出到 Hive TABLE 的另一个表中
语法:INSERT INTO TABLE<to_TABLE_name><PARTITION (age='25')><fields><FROM_TABLE_name>命令:INSERT INTO TABLE uba_web_visit_log_template_20150331SELECT * FROM uba_web_visit_log_20150331;
5、表说明
5.1、表类型:
1) 普通表一个表,就对应一个表名对应的文件目录。2) 外部表 关键字 EXTERNAL内部表 : 在DROP的时候会从HDFS上删除数据,外部表 : 在DROP的时候会从HDFS不会删除。EXTERNAL 关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION),Hive 创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。具体sql如下Sql代码CREATE EXTERNAL TABLE `test_1`(id INT,name STRING,city STRING)3) 分区表有分区的表可以在创建的时候使用 PARTITIONED BY 语句。一个表可以拥有一个或者多个分区,每一个分区单独存在一个目录下。而且,表和分区都可以对某个列进行 CLUSTERED BY 操作,将若干个列放入一个桶(bucket)中。也可以利用SORT BY 对数据进行排序。这样可以为特定应用提高性能.分区表实际是一个文件夹,表名即文件夹名。每个分区,实际是表名这个文件夹下面的不同文件。分区可以根据时间、地点等等进行划分。比如,每天一个分区,等于每天存每天的数据;或者每个城市,存放每个城市的数据。每次查询数据的时候,只要写下类似 WHERE pt=2010_08_23这样的条件即可查询指定时间得数据
5.2、注意事项
Hive不支持一条一条的用INSERT语句进行插入操作,也不支持update的操作。数据是以LOAD的方式,加载到建立好的表中。数据一旦导入,则不可修改。要么DROP掉整个表,要么建立新的表,导入新的数据。数据类型TINYINTSMALLINTINTBIGINTBOOLEANFLOATDOUBLESTRING如果数据需要压缩,使用 [STORED AS SEQUENCE] 。默认采用 [STORED AS TEXTFILE]。
6、视图
创建视图CREATE VIEW view_1 ASSELECTid,name,quanpinFROMdb_sync.angejia__city;删除视图DROP VIEW IF EXISTS TABLE_name;动态视图CREATE IF NOT EXISTS VIEW TABLE_name ASSELECTid,name,quanpinFROMdb_sync.angejia__city;
