原文地址:https://zhuanlan.zhihu.com/p/132720059
基本概念
- 外部表EXTERNAL:删除表并不会删除数据,但描述表的元数据信息会被删除掉。
- 分区表:使用分区来水平分散压力,将数据以一种符合逻辑的方式进行组织,比如分层存储。创建分区表的语法如下:
CREATE TABLE IF NOT EXISTS employees (
name STRING,
salary FLOAT,
subordinated ARRAY<STRING>,
deductions MAP<STRING, FLOAT>,
address STRUCT<street:STRING, city:STRING, state:STRING, zip:INT>
) PARTITIONED BY (year INT, month INT, day INT) --按照州划分数据
LOCATION '/user/hive/warehouse/mydb.db/employees';
这些数据会存储在对应的employees
的目录下,Hive会创建号可以反应分区结构的子目录,如:
当用set hive.mapred.mode=strict;
将Hive设置为strict
格式时,如果对分区表进行查询而WHERE子句没有加分区过滤,则会禁止提交这个任务;
可以用SHOW PARTITIONS查看表中存在的所有分区;若存在很多个分区,可以在此基础上增加一个或多个指定语句进行查看,利用SHOW PARTITIONS employees PARTITION(country='US');
语句进行过滤查询;
表操作
- 创建表
CREATE TABLE IF NOT EXISTS mydb.employees (
name STRING COMMENT 'Employee name',
salary FLOAT COMMENT 'Employee salary',
subordinated ARRAY<STRING> COMMENT 'Names of subordinates',
deductions MAP<STRING, FLOAT> COMMENT 'Keys are deductions names, values are percentages',
address STRUCT<street:STRING, city:STRING, state:STRING, zip:INT> COMMENT 'Home address'
)COMMENT 'Description of the table'
TBLPROPERTIES ('creator'='me', 'created_at'='2012-01-02 10:00:00', ...)
--TBLPROPERTIES作用是按键-值对的格式为表增加额外的文档说明
LOCATION '/user/hive/warehouse/mydb.db/employees';
--Hive会自动增加两个表属性:1.last_modified_by保存最后修改这个表的用户名;2.last_modified_time保存最后一次修改的新纪元时间秒。
- 查看表
SHOW TABLES
命令可列举出所有的表;
USE mydb;
SHOW TABLES;
也可以使用DESCRIBE EXTENDED mydb.employees
命令来查看表详细结构信息,使用FORMATTED
关键字替代EXTENDED
关键字,可以提供更多输出信息。这个命令也可以显示出分区键。
- 删除表
DROP TABLE IF EXISTS employees;
- 修改表
①表重命名
ALTER TABLE log_messages RENAME TO logmsgs;
②增加、修改和删除表分区
ALTER TABLE log_messages ADD IF NOT EXISTS
PARTITION (year = 2011, month = 1, day = 1) LOCATION '/logs/2011/01/01'
PARTITION (year = 2011, month = 1, day = 2) LOCATION '/logs/2011/01/02'
PARTITION (year = 2011, month = 1, day = 3) LOCATION '/logs/2011/01/03'
...; --增加多个分区
ALTER TABLE log_message
PARTITION (year = 2011, month = 12, day = 2)
SET LOCATION 's3n://ourbucket/logs/2011/01/02'; --修改分区路径
ALTER TABLE log_messages
DROP IF EXISTS
PARTITION (year = 2011, month = 12, day = 2)
③修改列信息
ALTER TABLE log_message
CHANGE COLUMN hms hours_minutes_seconds INT
COMMENT 'The hours, minutes, and seconds part of the timestamp'
AFTER severity; --FIRST将字段移动到第一个位置
④增加列
ALTER TABLE log_messages ADD COLUMNS (
app_name STRING COMMENT 'Application name',
session_id LONG COMMENT 'The current session id'
);
若新增字段中某个或多个字段位置是错误的,则需要使用ALTER COLUMN 表名 CHANGE COLUMN
语句逐一调整字段位置。
⑤删除或者替换列
ALTER TABLE log_messages REPLACE COLUMNS (
hours_mins_secs INT COMMENT 'hour, minute, second from timestamp',
severity STRING COMMENT 'The message severity',
message STRING COMMENT 'The rest of the message'
);
ALTER
语句只改变表的元信息数据。
⑥修改表属性
ALTER TABLE log_messages SET TBLPROPERTIES (
'notes' = 'The process id is no longer captures; this column is always NULL'
)
⑦修改存储属性
ALTER TABLE log_messages
PARTITION (year = 2012, month = 1, day = 1)
SET FILEFORMAT SEQUENCEFILE;
数据操作
- 向表中装载数据
该命令先创建分区目录,然后再将数据拷贝到该目录下。
LOAD DATA LOCAL INPATH '${env:HOME}/california-employees' --LOCAL本地文件系统路径 省略则为分布式文件系统中的路径
OVERWRITE INTO TABLE employees
PARTITION (country = 'US', state = 'CA')
- 通过查询语句向表中插入数据
INSERT OVERWRITE TABLE employees --OVERWRITE会覆盖之前分区中的内容,无OVERWRITE或为INSERT INTO则是追加
PARTITION (country = 'US', state = 'OR')
SELECT * FROM staged_employees se
WHERE se.cnty = 'US' AND se.st = 'OR'
动态分区插入
INSERT OVERWRITE TABLE employees
PARTITION (country = 'US', state)
SELECT ..., se.cnty, se.st
FROM staged_employees se
WHERE se.cnty = 'US'; --country字段为静态分区,state为动态分区,静态分区键必须在动态分区键之前
- 导出数据
拷贝文件夹或者文件的方法
hadoop fs -cp source_path target_path
或者
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/ca_employees'
SELECT name, salary, address
FROM employees
WHERE se.state = 'CA'
附录:动态分区属性
属性名称缺省值描述hive.exec.dynamic.partitionfalse设置成true,表示开启动态分区功能hive.exec.dynamic.partition.modestrict设置成nonstrict,表示允许所有分区都是动态的hive.exec.max.dynamic.partitions.pernode100每个mapper或reducer可以创建的最大动态分区个数hive.exec.max.dynamic.partitions+1000一个动态分区创建语句可以创建的最大动态分区个数hive.exec.max.created.files100000全局可以创建的最大文件个数
数据查询
SELECT ...
FROM ...
- SELECT ... FROM语句
①使用正则表达式来指定列
SELECT symbol, `price.*`
FROM stocks;
②使用列值进行计算
SELECT upper(name)
, salary
, deductions["Federal Taxes"]
, round(salary * (1 - deductions["Federal Taxes"])) --返回DOUBLE类型的最近整数
FROM employees;
③CASE ... WHEN ... THEN 句式
在利用SQL进行数据分析过程中,这种方法经常用到,用于处理单个列的查询结果。
SELECT name
, salary
, CASE WHEN salary < 50000.0 THEN 'low'
WHEN salary >= 50000.0 AND salary < 70000.0 THEN 'middle'
WHEN salary >= 70000.0 AND salary < 100000.0 THEN 'high'
ELSE 'very high' END AS bracket
FROM employees;
Hive可以避免进行MapReduce的情况:①本地模式查询,即简单读取目录下文件;②WHERE过滤条件只是分区字段
④谓语操作词(类似于=、<、>这种操作符)
关于浮点数的比较:当用户写一个浮点数,Hive会将该值保存为DOUBLE型的,0.2对于FLOAT类型是0.2000001,而对于DOUBLE类型是0.200000000001。
SELECT name
, salary
, deductions['Federal Taxes']
FROM employees
WHERE deductions['Federal Taxes'] > 2;
--修改成符合预期的
--WHERE deductions['Federal Taxes'] > cast(0.2 AS FLOAT)
⑤LIKE和RLIKE
查找所有住址的街道名称中含有单词Chicago或Ontario的雇员名称和街道信息如下:
SELECT name
, address.street
FROM employees
WHERE address.street RLIKE '.*(Chicago|Ontario).*'
- GROUP BY 语句
SELECT year(ymd)
, avg(price_close)
FROM stocks
WHERE exchange = 'NASDAQ' AND symbol = 'AAPL'
GROUP BY year(ymd)
HAVING avg(price_close) > 50.0;
- JOIN语句
类型:
①INNER JOIN内连接
②LEFT OUTER JOIN左外连接
③外连接OUTER JOIN
④RIGHT OUTER JOIN右外连接
⑤FULL OUTER JOIN完全外连接
⑥LEFT SEMI-JOIN左半开连接
⑦笛卡尔积JOIN
⑧map-side JOIN:所有表中只有一张表是小表,可以在最大的表通过mapper的时候将小表完全放到内存中,Hive可以在map端执行连接过程,和内存中的小表进行逐一匹配,从而省略掉常规连接操作所需要的reduce过程。
SELECT /*+MAPJOIN(d) */ s.ymd
, s.symbol
, s.price_close
, d.dividend
FROM stocks s JOIN dividends d ON s.ymd = d.ymd AND s.symbol = d.symbol
WHERE s.symbol = 'AAPL';
JOIN优化的点在于用户需要保证连续查询中的表的大小从左到右是依次增加的。
- ORDER BY和SORT BY
SORT BY只会在每个reducer中对数据进行排序,即局部排序过程,保证每个reducer的输出数据都是有序的。两者的对比:
SELECT s.ymd
, s.symbol
, s.price_close
FROM stocks s
ORDER BY s.ymd ASC, s.symbol DESC;
--SORT BY s.ymd ASC, s.symbol DESC;
若reducer的个数大于1,SORT BY的结果是局部有序的,ORDER BY的结果是全局有序的。
补充:含有SORT BY的DISTRIBUTE BY
SELECT s.ymd
, s.symbol
, s.price_close
FROM stocks s
DISTRIBUTE BY s.symbol
SORT BY s.symbol DESC, s.ymd ASC;
如上DISTRIBUTE BY
保证具有相同股票交易码的记录会分发到同一个reducer中进行处理,然后使用SORT BY
来排序。
- CLUSTER BY语句
上面语句等价于
SELECT s.ymd
, s.symbol
, s.price_close
FROM stocks s
CLUSTER BY s.symbol;
- 类型转换
cast(value AS TYPE)
为类型转换函数,浮点数转换成整数用round()或者floor()函数
,BINARY类型
只支持将BINARY类型
转换为STRING类型
。
- 抽样查询
①采用rand()函数
SELECT *
FROM numbers
TABLESAMPLE(BUCKET 3 OUT OF 10 ON rand()) s;
分桶语句中的分母表示的是数据将会被散列的桶的个数,而分子表示将会选择的桶的个数。
②数据块抽样
基于行数按照输入路径下的数据块百分比进行的抽样
SELECT *
FROM numbersflat
TABLESAMPLE(0.1 PERCENT) s;
- UNION ALL
与SQL相同
索引
- 创建索引
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.';
- 重建索引
ALTER INDEX employees_index
ON TABLE employees
PARTITION (country = 'US')
REBUILD;
- 显示索引
SHOW FORMATTED INDEX ON employees;
- 删除索引
DROP INDEX IF EXISTS employees_index ON TABLE employees;
附录
- Hive内置数学函数
- 聚合函数
可以通过设置属性
SET hive.map.aggr=true
命令来提高聚合的性能。
- 表生成函数
- 其他内置函数
在数据分析实习中经常用到的函数主要是聚合函数、日期处理函数、正则表达式、字符串处理函数,后面争取对于这些常用的函数做一下详细解释。