2020年,新年快乐! 重新搭建了下博客,开始定期更新模式。
本文是前段时间阅读«hive权威指南»总结的笔记。
hiveql可以用来查询hdfs等分布式文件系统的数据。
我们经常会使用到hiveql来查询数据(在不涉及大量的数据迭代处理操作)。
本文大部分内容引用自«hive权威指南»。
基础 - 数据类型 #
基本数据类型 #
| 数据类型 | 长度 | 例子 | 
|---|---|---|
| tinyint | 1byte有符号整数 | |
| smallint | 2byte有符号整数 | |
| int | 4byte有符号整数 | |
| bigint | 8byte有符号整数 | |
| boolean | 布尔类型 | |
| float | 单精度浮点数 | |
| double | 双精度浮点数 | |
| string | 字符序列 | |
| timestamp | ||
| binary | 字节数组 | 
复合数据类型 #
| 数据类型 | 描述 | 示例 | 
|---|---|---|
| struct | ||
| map | ||
| array | 
数据库和表操作 #
数据库操作 - database #
创建数据库 - create #
hive> create database test;
判断是否存在:
hive> create database if not exists test;
为数据库添加描述信息:
hive> create database test comment "This is a example";
为数据库添加key-value属性信息:
hive> create database test
	> with dbproperties ('creator' = 'L0phTg', 'date' = '2019-08-23');
查看所有数据库 - show #
hive> show databases;
正则匹配:
hive> show databases like 'info.*';
查看数据库的描述信息 - describe #
hive> desc database test;
查看更多信息:
hive> desc database extended test;
使用数据库 - use #
即设置目标数据库为当前工作目录。
hive> use test;
删除数据库 - drop #
hive默认不允许用户删除一个包含有表的数据库。
hive> drop database if exists test;
如果想要强制删除库和库中的所有表,可以使用cascade关键字。
hive> drop database if exists test cascade;
表操作 - table #
查看表 #
- 
显示当前工作数据库中的表。 hive> show tables;
- 
显示指定数据库中的表。 hive> show tables in mydb;
- 
正则匹配表名。 hive> show tables 'employee.*';
- 
查看表的详细信息。 hive> desc extended mydb.employees;
创建表 #
- 
创建。 hive> create table mytable;
- 
额外的信息。 hive> create table if not exists mydb.employees ( name string comment 'Employee name', salary float comment 'employee salary', subordinates array<string> comment 'Names of subordinates' ) comment 'Descirption of the table' tblproperties ('creator'='L0phTg', 'date'='2019-08-23') location '/user/hive/warehouse/mydb.db/employees';
表分区 #
- 
新建分区。 数据分区,依次按照year、month、day对表进行分区。 hive> create table AccessRecord ( name string, job string ) partitioned by (year int, month int, day int);分区字段一旦建好,表现得就和普通的字段一样。 分区可以提高查询性能。 
- 
查看分区。 hive> show partitions AccessRecord;
- 
分区过滤查询。 hive> show partitions AccessRecord(year=2019);
删除表 #
hive> drop table if exists mytable;
修改表 #
大多数表属性可以通过Alter table语句来进行修改。这种操作会修改元数据,但不会修改数据本身。
- 
表重命名。 hive> alter table log_messages rename to logmsgs;
- 
增加表分区。 hive> alter table log_messages add if not exists > partition (year=2019, month=8, day=1) > partition (year=2019, month=8, day=2) > partition (year=2019, month=8, day=3);
- 
删除某个分区。 hive> alter table log_messages drop if exists partition(year=2019, month=9, day=3);
- 
修改列信息。(用户可以对某个字段进行重命名,并修改其位置、类型或者注释)。 hive> alter table log_messages > change column hms hours_minutes_seconds int > comment 'The hours, minutes, and seconds part of the timestamp' > after severity; # after表示将字段移动到severity字段的后面使用first关键字,可以将这个字段移动到第一个位置。 
- 
增加列。 hive> alter table log_messages add columns ( app_name string comment 'Application Name', session_id long comment 'The current session id' );
- 
删除或者替换列。 hive> alter table log_messages replace columns ( hours_mins_secs int comment 'hour, minute, seconds, from timestamp', severity string comment 'The message severity' message string comment 'The reset of the message' );这条语句重命名了之前的hms字段并且从之前的表定义的模式中移除了字段server和process_id。(因为是alter语句,所以只有表的元数据信息改变了) 
数据操作 #
hive没有行级别的数据插入、数据更新和删除操作。那么往表中装载数据的唯一途径就是使用一种大量的数据装载操作。
load - 装载文件数据到内部表中 #
通过关键字overwrite来装载数据到表中。
hive> load data local inpath '$(env:HOME)/california-employees'
	> overwrite into table employees
	> partition (country = 'US', state = 'CA');
通常情况下指定的路径应该是一个目录,而不是单独的文件。
insert - 通过查询语句向表中插入数据 #
insert语句允许用户通过查询语句向目标表中插入数据。
hive> insert overwrite table employees
	> partition (count = 'US', state = 'OR')
	> select * from staged_employees se
	> where se.cnty = 'US' and se.st = 'OR';
这里使用了overwrite关键字,因此之前分区中的内容将会被覆盖掉。
如果这里使用了into关键字,那么hive会以追加的方式写入数据而不会覆盖掉之前存在的内容。
单个查询语句创建表 #
hive> create table ca_employees
	> as select name, salary, address
	> from employees
	> where se.state = 'CA';
Select 查询操作 #
select … from … #
hive> select name, salary from employees;
John Doe 	10000.0
Mary Smith 	8000.0
Todd Jones  7000.0
Bill King   6000.0
表别名查询 #
hive> select e.name, e.salary from employees e;
引用集合数据类型的元素 #
hive> select name, subordinate from employees;
John Doe 		["Mary Smith", "Todd Jones"]
Mary Smith		["Bill King"]
Todd Jones		[]
Bill King		[]
hive> select name, subordinate[0] from employees;
John Doe 		Mary Smith
Mary Smith		Bill King
Todd Jones		NULL
Bill King		NULL
引用Map元素 #
hive> select name, deductions["State Taxes"] from employees;
John Doe 		0.05
Mary Smith		0.05
Todd Jones 		0.03
Bill King		0.03
引用Struct中的元素 #
hive> select name, address.city from employees;
John Doe 		Chicago
Mary Smith		Chicago
Todd Jones		Oak Park
Bill King		Obscuria
使用正则表达式指定列 #
hive> select symbol, 'price.*' from stocks;
AAPL 143.33 123.33 132.43 133.34 155.33
AAPL ...
...
...
使用列值进行计算 #
用户不但可以选择表中的列,还可以使用函数和算术表达式来操作列值。
hive> select upper(name), salary, deductions("Federal Taxes"),
	> round(salary * (1 - deductions["Federal Taxes"])) from employees;
JOHN DOE 	10000.0		0.2 	8000  # 数据是我随便写的,
MARY SMITH	8000.0		0.2		6400
TODD JONES  7000.0 		0.15 	5900
BILL KING   6000.0		0.15	5100
算术表达式 #
| 运算符 | 类型 | 描述 | 
|---|---|---|
| A + B | 数值 | 相加 | 
| A - B | 数值 | 相减 | 
| A * B | 数值 | 相乘 | 
| A / B | 数值 | 相除 | 
| A % B | 数值 | 取余 | 
| A & B | 数值 | 与 | 
| A | B | 数值 | 或 | 
| A ^ B | 数值 | 亦或 | 
| ~A | 数值 | 取反 | 
函数 #
- 
数学函数 返回值类型 样式 描述 bigint round(double d) double round(double d, int n) bigint floor(double d) double rand() rand(int seed) double exp(double d) 
- 
聚合函数 聚合函数是一类比较特殊的函数,可以对多行进行一些计算,然后得到一个结果值。 hive> select count(*), avg(salary) from employees; 4 77500.0返回值类型 样式 描述 bigint count(*) 计算总行数,包括含有NULL的行 bigint count(expr) 计算提供的expr表达式的值非NULL的行数 bigint count(distinct expr[,expr_.]) 计算expr表达式的值去重后非NULL的行数 double sum(col) 计算指定列的和 double sum(distinct col) 计算指定列去重后的和 double avg(col) 计算指定列的值的平均值 double avg(distinct col) 计算指定列去重后的平均值 double min(col) 计算指定列的最小值 double max(col) 计算指定列的最大值 array collect_set(col) 返回col的集合的数组 
- 
表生成函数(将单列扩展成多列或者多行)。 hive> select explode(subordinates) as sub from employees; Mary Smith Todd Jones Bill King如果某行subordinates的字段为空的话,将不会产生新的记录。 当使用表生成函数时,Hive要求使用列别名。 返回值类型 样式 描述 N行结果 explode(array arr) N行结果 explode(map mapp) 数组的类型 explode(array a) 结果插入表中 inline(array<struct[,struct]>) tuple json_tuple(string jsonStr, p1, p2, …, pn) tuple parse_url_tuple(url, partname1, partname2, …, partNameN), N >= 1 N行结果 stack(int n, col1, …, colM) 
- 
其它内置函数。 返回值类型 样式 描述 string ascii(string s) string base64(binary bin) binary binary(string s) / binary(binary b) type定义的类型 cast(< expr >) as ( ) string concat(binary s1, binary s2, …) string concat(string s1, string s2, …) string concat_ws(string separator, string s1, string s2, …) string concat_ws(binary separator, binary s1, binary s2, …) context_ngrams string decode(binary bin, string charset) binary encode(string src, string charset) int find_in_set(string s, string commaSeparatedString) 返回s出现的位置,没有找到则返回NULL string format_number(number x, int d) 将数值转换为"#,###,###“格式字符串,并保留d位小数。 string get_json_object(string json_string, string path) 从给定路径上的json字符串中抽取json对象,并返回这个对象的json字符串形式 boolean in test in (val1, val2,) boolean in_file(string s, string filename) 如果file中有完整的s匹配的话,则返回true int instr(string str, string substr) int length(string s) 计算字符串s的长度 int locate(string substr,string str[,int pos]) 查询substr在strpos后出现的位置 string lower(string s) string upper(string s) string ltrim(string s) 将s前面出现的空格全部去除 string parse_url(string url, string partname[,string key]) string regexp_extract(string subject, string regex_pattern, string index) 抽取subject中符合正则表达式regex_pattern的第index个部分的子字符串 string regex_replace(string s, string regex, string replacement) 按照java正则表达式regex将字符串s中符合条件的部分替换为replacement所指定的字符串a. string repeat(string s, int n) 重复输出n次字符串s string reverse(string s) 反转字符串 string rtrim(string s) 将s后面出现的空格全部去除掉 string trim(string s) 将s前后面出现的空格全部取出掉 string from_unixtime(bigint unixtime[,string format]) 将时间秒数转换为utc时间, 并用字符串表示, 可以通过format指定时间格式 bigint unix_timestamp() bigint unix_timestamp(string data) 输入字符串格式"yyyy-MM-dd HH:mm:ss” string to_date(string timestamp) 返回yyyy-MM-dd部分 timestamp from_utc_timestamp(timestamp timestamp, string timezone) 将其转换为指定时区的时间戳 timestamp to_utc_timestamp(timestamp timestamp, string timezone) 转换为utc下的时间戳 int year(string date) int month(string date) int day(strig date) int hour(string date) int minute(string date) int second(string date) 
limit - 限制输出 #
hive> select name, salary from employees limit 2;
john doe 	11000.0
mary smith	8000.0
where - 过滤字段 #
select语句用于选取字段,where语句用于过滤条件。
where语句使用谓词表达式。有几种谓词表达式可以使用and和or相连接,当谓词表达式的计算结果为true时,相应的行被保留并输出。
hive> select * from employees
	> where country = 'US' and state = 'CA';
谓词操作符 #
| 操作符 | 支持的数据类型 | 描述 | 
|---|---|---|
| A = B | 基本数据类型 | |
| A <=> B | 基本数据类型 | 如果A和B都为NULL则返回NULL | 
| A == B | 没有 | |
| A <> B, A != B | 基本数据类型 | |
| A < B | 基本数据类型 | |
| A <= B | 基本数据类型 | |
| A > B | 基本数据类型 | |
| A >= B | 基本数据类型 | |
| A [not] between B and C | 基本数据类型 | |
| A is null | 所有数据类型 | |
| A is not null | 所有数据类型 | |
| A [not] like B | string类型 | |
| A rlike B, A regexp B | string类型 | |
like 和 rlike #
like 全文匹配
rlike search匹配
group by - 分组 #
group by语句通常会和聚合函数一起使用,按照一个或者多个列对结果进行分组,然后对每个组执行聚合操作。
hive> select year(ymd), avg(price_close) from stocks
	> where exchange = 'NASDAQ' and symbol = 'AAPL'
	> group by year(ymd);
1984 	25.56777
1985	20.23454
1986	32.43563
1987 	45.12341
having #
对group by语句产生的分组进行条件过滤。
hive> select year(ymd), avg(price_close) from stocks
	> where exchange = "NASDAQ" and symbol = "AAPL"
	> group by year(ymd)
	> having avg(price_close) > 50.0;
1987		53.889
1991		52.495
1992		54.803
1999		57.748
2000		71.748
join - 多个表查询 #
inner join #
内连接:只有两个表都存在与连接标准相匹配的数据才会保留下来。
hive> select a.ymd, a.price_close, b.price_close
	> from stocks a join stocks b on a.ymd = b.ymd
	> where a.symbol = 'AAPL' and b.symbol = 'IBM';
2019-08-01		XXX 	XXX
2019-08-02		XXX		XXX
2019-08-03		XXX		XXX
on 子句支持 and。
left outer join #
hive> select s.ymd, s.symbol, s.price_close, d.dividend
	> from stocks s left outer join dividends d on s.ymd = d.ymd on s.symbol = d.symbol
	> where s.symbol = 'AAPL';
在这种join连接时,join操作符左边表的符合where子句的所有记录将会被返回。join操作符右边表中如果没有符合on后面连接条件的记录时,那么从右边表指定列选择的值将会是NULL。
right outer join #
full outer join #
order by和sort by #
Hive中order by语句和其他sql中的定义是一样的。其会对查询结果集执行一个全局排序。
Hive中提供了一个可供选择的方式,就是sort by。其会在每个reducer中对数据进行排序,也就是执行一个局部排序过程。这可以保证每个reducer的输出数据都是有序的(但并非全局有序)。
ASC表示升序排序。DESC表示降序排序。
hive> select s.ymd, s.price_close
	> from stocks s
	> order by s.ymd ASC, s.symbol DESC;
hive> select s.ymd, s.price_close
	> from stocks s
	> sort by s.ymd ASC, s.symbol DESC;	
Cluster by #
Union all #
union all可以将2个或多个表进行合并。
视图 #
索引 #
Hive中没有普通关系型数据库中键的概念,但是还是可以对一些字段建立索引。一张表的索引数据存储在另外一张表中。
函数 #
发现和描述函数 #
hive> show functions;
abs
acos
and
array
展示对应函数的介绍:
hive> describe function concat;
concat(str1, str2, ... strN) - returns the concatenation of str1, str2, ... strN
展示详细文档:
hive> describe function extended concat;
调用函数 #
在查询中调用函数名即可。
同样,udf同样可以返回一个复杂的对象
标准函数 #
UDF:表示一行数据中的一列或者多列数据作为参数,然后返回结果是一个值
聚合函数 #
UDAF:接受从零行到多行的零个列到多个列,然后返回单一值。
聚合函数通常和group by结合使用
表生成函数 #
UDTF:接受零个或多个输入,然后产生多列或者多行输出。
查询实例 #
解析json查询 #
json为字符串数组格式。
explode: hive的表生成函数只是生成了一种数据的展示方式,而无法在表中产生一个其他的列。
需求:
- 
json拆分为多个列json_tuple select json_name, json_value from database1.tableName lateral view json_tuple(json_string, "name", "value") jsonTable as json_name, json_value where year = 2019 limit 10;
json数组查询 #
需求:
- 
对数组中每个json做处理,做比较。(先explode,再json_tuple) select json_name, json_value from database1.tableName lateral view explode(str_array) explode_table as str_json lateral view json_tuple(str_json, "name", "value") jsonTable as json_name, json_value where year = 2019 limit 10;