@R星校长
Hive SerDe - Serializer and Deserializer
SerDe 用于做序列化和反序列化。
构建在数据存储和执行引擎之间,对两者实现解耦。
Hive 通过 ROW FORMAT DELIMITED 以及 SERDE 进行内容的读写。
row_format
: DELIMITED
[FIELDS TERMINATED BY char [ESCAPED BY char]]
[COLLECTION ITEMS TERMINATED BY char]
[MAP KEYS TERMINATED BY char]
[LINES TERMINATED BY char]
:SERDE serde_name [WITH SERDEPROPERTIES (property_name=
property_value,property_name=property_value, ...)]
Hive 正则匹配
CREATE TABLE logtbl (
host STRING,
identity STRING,
t_user STRING,
time STRING,
request STRING,
referer STRING,
agent STRING)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input.regex" = "([^ ]*) ([^ ]*) ([^ ]*) \\[(.*)\\] \"(.*)\" (-|[0-9]*) (-|[0-9]*)"
)
STORED AS TEXTFILE;
使用 “笔记/localhost_access_log.2016-02-29.txt” 导入。
192.168.57.4 - - [29/Feb/2016:18:14:35 +0800] "GET /bg-upper.png HTTP/1.1"
304 -
将该文件上传到 node4 的 /root/data 目录
[root@node4 data]# pwd
/root/data
[root@node4 data]# ls
localhost_access_log.2016-02-29.txt person01.txt person02.txt
[root@node4 data]# mv localhost_access_log.2016-02-29.txt logtbl.txt
[root@node4 data]# ls
logtbl.txt person01.txt person02.txt
Node4 hive load 数据到对应的表中
hive> load data local inpath '/root/data/logtbl.txt' into table logtbl;
Loading data to table default.logtbl
Table default.logtbl stats: [numFiles=1, totalSize=1759]
OK
Time taken: 0.463 seconds
hive> select * from logtbl;
Beeline 要与 HiveServer2 配合使用
https://cwiki.apache.org/confluence/display/Hive/Home#Home-UserDocumentationHiveServer2(HS2)是一种使客户端能够对 Hive 执行查询的服务。 HiveServer2 是已被废弃的 HiveServer1 (仅支持单客户端访问)的继承者。HS2 支持多客户端并发和身份验证。它旨在为 JDBC 和 ODBC 等开放 API 客户端提供更好的支持。HS2 是一个作为复合服务运行的进程,它包括基于 Thrift 的 Hive 服务(TCP 或 HTTP)和 WebUI 的 Jetty Web 服务器。
服务端启动 hiveserver2
如果让让该进程在后台执行:
nohup hiveserver2 & #关闭的话通过kill -9 pid
客户的通过 beeline 两种方式连接到 hive
1、方式一:
beeline -u jdbc:hive2://node3:10000/default [-n hiveuser -p pass]
[root@node4 ~]# beeline -u jdbc:hive2://node3:10000/default -n root -p 123
0: jdbc:hive2://node3:10000/default> !quit #退出
2、方式二:
% bin/beeline
beeline> !connect jdbc:hive2://<host>:<port>/<db>;auth=noSasl hiveuser pass
beeline
beeline> !connect jdbc:hive2://node3:10000/default root 123
The Beeline Shell 工作在嵌入式模式和远程模式.在嵌入式模式下,它运行嵌入式 Hive(类似于 HiveCLI),而远程模式是用于在 Thrift 上连接到单独的HiveServer2 进程。从 Hive0.14 开始,当 Beeline 与 HiveServer2 一起使用时,它还会打印来自 HiveServer2 的日志消息,以供它执行到 STDERR 的查询。远程 HiveServer2 模式推荐用于生产使用,因为它更安全,不需要为用户授予直接 HDFS/metastore 访问权限。
生产环境启动方式:1. 结束掉 node3 上的 hiveserver2 进程,通过如下命令启动 hive 元数据服务
hive --service metastore
2.在 node4 上启动 hiveserver2
3.分为开发人员和运营人员:
(1) 开发人员:再打开一个 xshell 连接到 node4 上,然后通过 hive 命令启动,通过命令行模式进行开发与调试。
(2) 运营人员:使用开发好的项目(可以通过 javaweb 项目,使用 jdbc 方法 node4 上提供的接口,设计成 BS 架构的项目),通过浏览器进行操作。
扩展案例:node2 上如何通过 beeline 向表中 load 本地文件中的数据?
假设文件中的数据如下:
11,小明11,lol-book-movie,beijing:xisanqi-shanghai:pudong
12,小明12,lol-book-movie,beijing:xisanqi-shanghai:pudong
13,小明13,lol-book-movie,beijing:xisanqi-shanghai:pudong
14,小明14,lol-book-movie,beijing:xisanqi-shanghai:pudong
15,小明15,lol-movie,beijing:xisanqi-shanghai:pudong
操作步骤:
A. node2 上的数据准备工作
[root@node2 ~]# mkdir data
[root@node2 ~]# cd data
[root@node2 data]# vim data3
将数据放入该文件
B. Beeline 连接
[root@node2 data]# beeline -u jdbc:hive2://node4:10000/default -n root -p 123
C. Load本地数据:
0: jdbc:hive2://node4:10000/default> load data local inpath '/root/data/data3' into table person;
Error: Error while compiling statement: FAILED: SemanticException Line 1:23 Invalid path ''/root/data/data3'': No files matching path file:/root/data/data3 (state=42000,code=40000)
明明存在 /root/data/data3 啊,为何会有这样的提示呢?这是因为 beeline 通常被用来执行 sql 操作,如果非要通过它实现加载本地文件,需要再对应的hiveserver2 服务器(也就是 node4)上,存在 /root/data/data3 文件。
D. 将 data3 文件从 node2 拷贝到 node4 对应目录下,然后在 node2 上再次执行 load 操作。
先拷贝文件
[root@node2 ~]# scp /root/data/data3 node4:/root/data/
data3
避免 node2 上文件困扰,也可以将 node2 上的 /root/data/data3 删除
再次执行 load
E. 再次执行 load ,抛出以下异常:
Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.AccessControlException): Permission denied: user=anonymous, access=WRITE, inode="/user/hive_remote/warehouse/person":root:supergroup:drwxr-xr-x
这是因为默认通过匿名用户登录的,权限不足。解决办法,beeline 连接断开,然后以 root 用户登录,再次执行 load 即可。
[root@node2 data]# beeline -u jdbc:hive2://node4:10000/default -n root
0: jdbc:hive2://node4:10000/default> load data local inpath '/root/data/data3' into table person;
INFO : Loading data to table default.person from file:/root/data/data3
INFO : Table default.person stats: [numFiles=1, numRows=0, totalSize=290, rawDataSize=0]
No rows affected (1.419 seconds)
0: jdbc:hive2://node4:10000/default> select * from person;
+------------+--------------+-------------------------+--------------------------------------------+--+
| person.id | person.name | person.likes | person.address |
+------------+--------------+-------------------------+--------------------------------------------+--+
| 11 | 小明11 | ["lol","book","movie"] | {
"beijing":"xisanqi","shanghai":"pudong"} |
| 12 | 小明12 | ["lol","book","movie"] | {
"beijing":"xisanqi","shanghai":"pudong"} |
| 13 | 小明13 | ["lol","book","movie"] | {
"beijing":"xisanqi","shanghai":"pudong"} |
| 14 | 小明14 | ["lol","book","movie"] | {
"beijing":"xisanqi","shanghai":"pudong"} |
| 15 | 小明15 | ["lol","movie"] | {
"beijing":"xisanqi","shanghai":"pudong"} |
+------------+--------------+-------------------------+--------------------------------------------+--+
5 rows selected (0.178 seconds)
服务端启动 hiveserver2 后,在 java 代码中通过调用 hive 的 jdbc 访问默认端口 10000 进行连接、访问。
演示 hive 项目(hive_demo_idea)
运算符 | 类型 | 说明 |
---|---|---|
A = B | 所有原始类型 | 如果A与B相等,返回TRUE,否则返回FALSE |
A == B | 无 | 失败,因为无效的语法。 SQL使用”=”,不使用”==”。 |
A <> B | 所有原始类型 | 如果A不等于B返回TRUE,否则返回FALSE。如果A或B值为”NULL”,结果返回”NULL”。 |
A < B | 所有原始类型 | 如果A小于B返回TRUE,否则返回FALSE。如果A或B值为”NULL”,结果返回”NULL”。 |
A <= B | 所有原始类型 | 如果A小于等于B返回TRUE,否则返回FALSE。如果A或B值为”NULL”,结果返回”NULL”。 |
A > B | 所有原始类型 | 如果A大于B返回TRUE,否则返回FALSE。如果A或B值为”NULL”,结果返回”NULL”。 |
A >= B | 所有原始类型 | 如果A大于等于B返回TRUE,否则返回FALSE。如果A或B值为”NULL”,结果返回”NULL”。 |
A IS NULL | 所有类型 | 如果A值为”NULL”,返回TRUE,否则返回FALSE |
A IS NOT NULL | 所有类型 | 如果A值不为”NULL”,返回TRUE,否则返回FALSE |
A LIKE B | 字符串 | 如 果A或B值为”NULL”,结果返回”NULL”。字符串A与B通过sql进行匹配,如果相符返回TRUE,不符返回FALSE。B字符串中 的””代表任一字符,”%”则代表多个任意字符。例如: (‘foobar’ like ‘foo’)返回FALSE,( ‘foobar’ like ‘foo _ _’或者 ‘foobar’ like ‘foo%’)则返回TURE |
A RLIKE B | 字符串 | 如 果A或B值为”NULL”,结果返回”NULL”。字符串A与B通过java进行匹配,如果相符返回TRUE,不符返回FALSE。例如:( ‘foobar’ rlike ‘foo’)返回FALSE,(’foobar’ rlike ‘^f.*r$’ )返回TRUE。 |
A REGEXP B | 字符串 | 与RLIKE相同。 |
运算符 | 类型 | 说明 |
---|---|---|
A + B | 所有数字类型 | A和B相加。结果的与操作数值有共同类型。例如每一个整数是一个浮点数,浮点数包含整数。所以,一个浮点数和一个整数相加结果也是一个浮点数。 |
A – B | 所有数字类型 | A和B相减。结果的与操作数值有共同类型。 |
A * B | 所有数字类型 | A和B相乘,结果的与操作数值有共同类型。需要说明的是,如果乘法造成溢出,将选择更高的类型。 |
A / B | 所有数字类型 | A和B相除,结果是一个double(双精度)类型的结果。 |
A % B | 所有数字类型 | A除以B余数与操作数值有共同类型。 |
A & B | 所有数字类型 | 运算符查看两个参数的二进制表示法的值,并执行按位”与”操作。两个表达式的一位均为1时,则结果的该位为 1。否则,结果的该位为 0。 |
A|B | 所有数字类型 | 运算符查看两个参数的二进制表示法的值,并执行按位”或”操作。只要任一表达式的一位为 1,则结果的该位为 1。否则,结果的该位为 0。 |
A ^ B | 所有数字类型 | 运算符查看两个参数的二进制表示法的值,并执行按位”异或”操作。当且仅当只有一个表达式的某位上为 1 时,结果的该位才为 1。否则结果的该位为 0。 |
~A | 所有数字类型 | 对一个表达式执行按位”非”(取反)。 |
运算符 | 类型 | 说明 |
---|---|---|
A AND B | 布尔值 | A和B同时正确时,返回TRUE,否则FALSE。如果A或B值为NULL,返回NULL。 |
A && B | 布尔值 | 与”A AND B”相同 |
A OR B | 布尔值 | A或B正确,或两者同时正确返返回TRUE,否则FALSE。如果A和B值同时为NULL,返回NULL。 |
A | B | 布尔值 | 与”A OR B”相同 |
NOT A | 布尔值 | 如果A为NULL或错误的时候返回TURE,否则返回FALSE。 |
! A | 布尔值 | 与”NOT A”相同 |
函数 | 类型 | 说明 |
---|---|---|
map | (key1, value1, key2, value2, …) | 通过指定的键/值对,创建一个map。 |
struct | (val1, val2, val3, …) | 通过指定的字段值,创建一个结构。结构字段名称将COL1,COL2,… |
array | (val1, val2, …) | 通过指定的元素,创建一个数组。 |
函数 | 类型 | 说明 |
---|---|---|
A[n] | A是一个数组,n为int型 | 返回数组A的第n个元素,第一个元素的索引为0。如果A数组为[‘foo’,‘bar’],则A[0]返回’foo’和A[1]返回”bar”。select likes[0] from person; |
M[key] | M是Map |
返回关键值对应的值,例如mapM为 {‘f’ -> ‘foo’, ‘b’ -> ‘bar’, ‘all’ -> ‘foobar’},则M[‘all’] 返回’foobar’。select address[‘beijing’] from person; |
S.x | S为struct | 返回结构x字符串在结构S中的存储位置。如 foobar {int foo, int bar} foobar.foo的领域中存储的整数。 |
返回类型 | 函数 | 说明 |
---|---|---|
BIGINT | round(double a) | 四舍五入 |
DOUBLE | round(double a, int d) | 小数部分d位之后数字四舍五入,例如round(21.263,2),返回21.26 |
BIGINT | floor(double a) | 对给定数据进行向下舍入最接近的整数。例如floor(21.2),返回21。 |
BIGINT | ceil(double a), ceiling(double a) | 将参数向上舍入为最接近的整数。例如ceil(21.2),返回22. |
double | rand(), rand(int seed) | 返回大于或等于0且小于1的平均分布随机数(依重新计算而变) |
double | exp(double a) | 返回e的n次方 |
double | ln(double a) | 返回给定数值的自然对数 |
double | log10(double a) | 返回给定数值的以10为底自然对数 |
double | log2(double a) | 返回给定数值的以2为底自然对数 |
double | log(double base, double a) | 返回给定底数及指数返回自然对数 |
double | pow(double a, double p) power(double a, double p) | 返回某数的乘幂 |
double | sqrt(double a) | 返回数值的平方根 |
string | bin(BIGINT a) | 返回二进制格式 |
string | hex(BIGINT a) hex(string a) | 将整数或字符转换为十六进制格式 |
string | unhex(string a) | 十六进制字符转换由数字表示的字符。 |
string | conv(BIGINT num, int from_base, int to_base) | 将 指定数值,由原来的度量体系转换为指定的试题体系。例如CONV(‘a’,16,2),返回。参考:’1010′ http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_conv |
double | abs(double a) | 取绝对值 |
int double | pmod(int a, int b) pmod(double a, double b) | 返回a除b的余数的绝对值 |
double | sin(double a) | 返回给定角度的正弦值 |
double | asin(double a) | 返回x的反正弦,即是X。如果X是在-1到1的正弦值,返回NULL。 |
double | cos(double a) | 返回余弦 |
double | acos(double a) | 返回X的反余弦,即余弦是X,,如果-1<= A <= 1,否则返回null. |
int double | positive(int a) positive(double a) | 返回A的值,例如positive(2),返回2。 |
int double | negative(int a) negative(double a) | 返回A的相反数,例如negative(2),返回-2。 |
返回类型 | 函数 | 说明 |
---|---|---|
int | size(Map |
返回的map类型的元素的数量 |
int | size(Array) | 返回数组类型的元素数量 |
select id,size(likes),size(address) from person;
Int->bigint 自动转换,bigint->int 需要强制类型
返回类型 | 函数 | 说明 |
---|---|---|
指定 “type” | cast(expr as |
类型转换。例如将字符 "1″ 转换为整数:cast('1′ as bigint),如果转换失败返回 NULL。 |
返回类型 | 函数 | 说明 |
---|---|---|
string | from_unixtime(bigint unixtime[, string format]) | UNIX_TIMESTAMP参数表示返回一个值’YYYY- MM – DD HH:MM:SS’或YYYYMMDDHHMMSS.uuuuuu格式,这取决于是否是在一个字符串或数字语境中使用的功能。该值表示在当前的时区。 |
bigint | unix_timestamp() | 如果不带参数的调用,返回一个Unix时间戳(从’1970- 01 – 0100:00:00′到现在的UTC秒数)为无符号整数。 |
bigint | unix_timestamp(string date) | 指定日期参数调用UNIX_TIMESTAMP(),它返回参数值’1970- 01 – 0100:00:00′到指定日期的秒数。 |
bigint | unix_timestamp(string date, string pattern) | 指定时间输入格式,返回到1970年秒数:unix_timestamp(’2009-03-20′, ‘yyyy-MM-dd’) = 1237532400 |
string | to_date(string timestamp) | 返回时间中的年月日: to_date(“1970-01-01 00:00:00″) = “1970-01-01″ |
string | to_dates(string date) | 给定一个日期date,返回一个天数(0年以来的天数) |
int | year(string date) | 返回指定时间的年份,范围在1000到9999,或为”零”日期的0。 |
int | month(string date) | 返回指定时间的月份,范围为1至12月,或0一个月的一部分,如’0000-00-00′或’2008-00-00′的日期。 |
int | day(string date) dayofmonth(date) | 返回指定时间的日期 |
int | hour(string date) | 返回指定时间的小时,范围为0到23。 |
int | minute(string date) | 返回指定时间的分钟,范围为0到59。 |
int | second(string date) | 返回指定时间的秒,范围为0到59。 |
int | weekofyear(string date) | 返回指定日期所在一年中的星期号,范围为0到53。 |
int | datediff(string enddate, string startdate) | 两个时间参数的日期之差。 |
int | date_add(string startdate, int days) | 给定时间,在此基础上加上指定的时间段。 |
int | date_sub(string startdate, int days) | 给定时间,在此基础上减去指定的时间段。 |
返回类型 | 函数 | 说明 |
---|---|---|
T | if(boolean testCondition, T valueTrue, T valueFalseOrNull) | 判断是否满足条件,如果满足返回一个值,如果不满足则返回另一个值。 |
T | COALESCE(T v1, T v2, …) | 返回一组数据中,第一个不为NULL的值,如果均为NULL,返回NULL。 |
T | CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END | 当a=b时,返回c;当a=d时,返回e,否则返回f。 |
T | CASE WHEN a THEN b [WHEN c THEN d]* [ELSE e] END | 当值为a时返回b,当值为c时返回d。否则返回e。 |
select substr(key,13,2),
case when birthday<'1970' then '50up'
when birthday<'1980' then '40-50'
when birthday<'1985' then '35-40'
when birthday<'1990' then '30-35'
when birthday<'1994' then '26-30'
when birthday<'2000' then '20-25'
else 'other' end,
count(1)
from hiveTable
返回类型 | 函数 | 说明 |
---|---|---|
int | length(string A) | 返回字符串的长度 |
string | reverse(string A) | 返回倒序字符串 |
string | concat(string A, string B…) | 连接多个字符串,合并为一个字符串,可以接受任意数量的输入字符串 |
string | concat_ws(string SEP, string A, string B…) | 链接多个字符串,字符串之间以指定的分隔符分开。 |
string | substr(string A, int start) substring(string A, int start) | 从文本字符串中指定的起始位置后的字符。 |
string | substr(string A, int start, int len) substring(string A, int start, int len) | 从文本字符串中指定的位置指定长度的字符。 |
string | upper(string A) ucase(string A) | 将文本字符串转换成字母全部大写形式 |
string | lower(string A) lcase(string A) | 将文本字符串转换成字母全部小写形式 |
string | trim(string A) | 删除字符串两端的空格,字符之间的空格保留 |
string | ltrim(string A) | 删除字符串左边的空格,其他的空格保留 |
string | rtrim(string A) | 删除字符串右边的空格,其他的空格保留 |
string | regexp_replace(string A, string B, string C) | 字符串A中的B字符被C字符替代 |
string | regexp_extract(string subject, string pattern, int index) | 通过下标返回正则表达式指定的部分。regexp_extract(‘foothebar’, ‘foo(.*?)(bar)’, 2) returns ‘bar.’ |
string | parse_url(string urlString, string partToExtract [, string keyToExtract]) | 返回URL指定的部分。parse_url(‘http://facebook.com/path1/p.php?k1=v1&k2=v2#Ref1′, ‘HOST’) |
string | get_json_object(string json_string, string path) | select a.timestamp, get_json_object(a.appevents, ‘$.eventid’), get_json_object(a.appenvets, ‘$.eventname’) from log a; |
string | space(int n) | 返回指定数量的空格 |
string | repeat(string str, int n) | 重复N次字符串 |
int | ascii(string str) | 返回字符串中首字符的数字值 |
string | lpad(string str, int len, string pad) | 返回指定长度的字符串,给定字符串长度小于指定长度时,由指定字符从左侧填补。 |
string | rpad(string str, int len, string pad) | 返回指定长度的字符串,给定字符串长度小于指定长度时,由指定字符从右侧填补。 |
array | split(string str, string pat) | 将字符串转换为数组。实现wordcount |
int | find_in_set(string str, string strList) | 返回字符串str第一次在strlist出现的位置。如果任一参数为NULL,返回NULL;如果第一个参数包含逗号,返回0。 |
array |
sentences(string str, string lang, string locale) | 将字符串中内容按语句分组,每个单词间以逗号分隔,最后返回数组。 例如sentences(‘Hello there! How are you?’) 返回:( (“Hello”, “there”), (“How”, “are”, “you”) ) |
array |
ngrams(array |
SELECT ngrams(sentences(lower(tweet)), 2, 100 [, 1000]) FROM twitter; |
array |
context_ngrams(array |
SELECT context_ngrams(sentences(lower(tweet)), array(null,null), 100, [, 1000]) FROM twitter; |
返回类型 | 函数 | 说明 |
---|---|---|
bigint | count(*) , count(expr), count(DISTINCT expr[, expr_., expr_.]) | 返回记录条数。 |
double | sum(col), sum(DISTINCT col) | 求和 |
double | avg(col), avg(DISTINCT col) | 求平均值 |
double | min(col) | 返回指定列中最小值 |
double | max(col) | 返回指定列中最大值 |
double | var_pop(col) | 返回指定列的方差 |
double | var_samp(col) | 返回指定列的样本方差 |
double | stddev_pop(col) | 返回指定列的偏差 |
double | stddev_samp(col) | 返回指定列的样本偏差 |
double | covar_pop(col1, col2) | 两列数值协方差 |
double | covar_samp(col1, col2) | 两列数值样本协方差 |
double | corr(col1, col2) | 返回两列数值的相关系数 |
double | percentile(col, p) | 返回数值区域的百分比数值点。0<=P<=1,否则返回NULL,不支持浮点型数值。 |
array |
percentile(col, array(p~1,\ [, p,2,]…)) | 返回数值区域的一组百分比值分别对应的数值点。0<=P<=1,否则返回NULL,不支持浮点型数值。 |
double | percentile_approx(col, p[, B]) | Returns an approximate pth percentile of a numeric column (including floating point types) in the group. The B parameter controls approximation accuracy at the cost of memory. Higher values yield better approximations, and the default is 10,000. When the number of distinct values in col is smaller than B, this gives an exact percentile value. |
array |
percentile_approx(col, array(p~1, [, p,2_]…) [, B]) | Same as above, but accepts and returns an array of percentile values instead of a single one. |
array |
histogram_numeric(col, b) | Computes a histogram of a numeric column in the group using b non-uniformly spaced bins. The output is an array of size b of double-valued (x,y) coordinates that represent the bin centers and heights |
array | collect_set(col) | 返回无重复记录 |
返回类型 | 函数 | 说明 |
---|---|---|
数组 | explode(array |
数组一条记录中有多个参数,将参数拆分,每个参数生成一列。 |
json_tuple | get_json_object 语句:select a.timestamp, get_json_object(a.appevents, ‘$.eventid’), get_json_object(a.appenvets, ‘$.eventname’) from log a; json_tuple语句: select a.timestamp, b.* from log a lateral view json_tuple(a.appevent, ‘eventid’, ‘eventname’) b as f1, f2 |
比如 wordcount 案例中,将一行内容的每个单词进行切割。
自定义函数包括三种UDF、UDAF、UDTF
UDF(User-Defined-Function) 一进一出
UDAF(User- Defined Aggregation Funcation) 聚集函数,多进一出。Count/max/min
UDTF(User-Defined Table-Generating Functions) 一进多出,如 lateral view explore()
使用方式 :在 HIVE 会话中 add 自定义函数的 jar 文件,然后创建 function 继而使用函数
比如数据脱敏 13834564321->138****4321
1、UDF函数可以直接应用于select语句,对查询结构做格式化处理后,再输出内容。
2、编写UDF函数的时候需要注意一下几点:
a)自定义UDF需要继承org.apache.hadoop.hive.ql.UDF。
b)需要实现evaluate函数,evaluate函数支持重载。
package cn.gtjin;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
public class TuoMin extends UDF {
public Text evaluate(final Text s) {
if (s == null) {
return null;
}
String phone = s.toString();
String str = phone.substring(0, 3) + "****"+
phone.substring(7);
return new Text(str);
}
}
3、步骤
a)把程序打包放到目标机器 node4 的目录 /root/data/ 中;
b)进入 hive 客户端,添加 jar 包:
hive>add jar /root/data/hive_demo_idea.jar;
c)创建临时函数:
hive>CREATE TEMPORARY FUNCTION tuomin AS 'cn.gtjin.TuoMin';
d)表和数据准备
数据准备:
[root@node4 data]# pwd
/root/data
[root@node4 data]# vim acc.txt
1,guanyu,13688774321
2,zhaoyun,13812349876
创建表,并添加数据
hive>create table account(id int,name string,phone string) ROW FORMAT DELIMITED
FIELDS TERMINATED BY ',';
OK
Time taken: 0.088 seconds
hive> load data local inpath '/root/data/acc.txt' into table account;
Loading data to table default.account
Table default.account stats: [numFiles=1, totalSize=43]
OK
Time taken: 0.393 seconds
e)查询 HQL 语句:
hive> select id,name,tuomin(phone) from account;
OK
1 guanyu 136***4321
2 zhaoyun 138***9876
Time taken: 0.072 seconds, Fetched: 2 row(s)
e)销毁临时函数:hive> drop temporary function tuomin;
注:也可以将 b 和 c 改为(扩展):
[root@node4 data]# hdfs dfs -put hive_demo_idea.jar /usr
hive> DROP TEMPORARY FUNCTION tuomin;
OK
Time taken: 0.008 seconds
hive> CREATE TEMPORARY FUNCTION tuomin AS 'cn.gtjin.TuoMin' using jar 'hdfs://node1:8020/usr/hive_demo_idea.jar';
converting to local hdfs://node1:8020/usr/hive_demo_idea.jar
Added [/tmp/37c7aeca-ff11-4f3f-a170-0b6a3019094b_resources/hive_demo_idea.jar] to class path
Added resources: [hdfs://node1:8020/usr/hive_demo_idea.jar]
OK
Time taken: 0.07 seconds
hive> select id,name,tuomin(phone) from account;
OK
1 guanyu 136***4321
2 zhaoyun 138***9876
Time taken: 0.1 seconds, Fetched: 2 row(s)
多行进一行出,如sum()、min(),用在 group by 时
1.必须继承
org.apache.hadoop.hive.ql.exec.UDAF(函数类继承)
org.apache.hadoop.hive.ql.exec.UDAFEvaluator(内部类Evaluator实现UDAFEvaluator接口)
2.Evaluator需要实现 init、iterate、terminatePartial、merge、terminate这几个函数
init():类似于构造函数,用于UDAF的初始化
iterate():接收传入的参数,并进行内部的轮转,返回boolean
terminatePartial():无参数,其为iterate函数轮转结束后,返回轮转数据,类似于hadoop的Combiner
merge():接收terminatePartial的返回结果,进行数据merge操作,其返回类型为boolean
terminate():返回最终的聚集函数结果
开发一个功能同:
Oracle的wm_concat()函数
Mysql的group_concat()
创建 student 表
create table student(
id int,
info struct<name:string,age:int>
)
row format delimited
fields terminated by ','
collection items terminated by ':';
向这个 student 表中插入数据
[root@node4 data]# vim stu.txt
1,tuhao:25
2,diaosi:26
将数据加载到表中:
hive> load data local inpath '/opt/data/stu.txt' into table student;
hive> select * from student;
OK
1 {
"name":"tuhao","age":25}
2 {
"name":"diaosi","age":26}
hive>select id,info.name,info.age from student;
OK
1 tuhao 28
2 diaoshi 35
record_time:通话时间
imei:基站编号
cell:手机编号
drop_num:掉话的秒数
duration:通话持续总秒数
创建原始数据表
create table jizhan(
record_time string,
imei int,
cell string,
ph_num int,
call_num int,
drop_num int,
duration int,
drop_rate double,
net_type string,
erl int)
row format delimited fields terminated by ',';
上传数据到 node4 , 改名,然后加载到表
hive> load data local inpath '/root/data/cdr_info.csv' into table jizhan;
Loading data to table default.jizhan
Table default.jizhan stats: [numFiles=1, totalSize=57400917]
OK
Time taken: 1.315 seconds
hive> select * from jizhan limit 10;
OK
record_time NULL cell NULL NULL NULL NULL NULL net_type NULL
2011-07-13 00:00:00+08 356966 29448-37062 0 0 0 0 0
2011-07-13 00:00:00+08 352024 29448-51331 0 0 0 0 0
2011-07-13 00:00:00+08 353736 29448-51331 0 0 0 0 0
2011-07-13 00:00:00+08 353736 29448-51333 0 0 0 0 0
2011-07-13 00:00:00+08 351545 29448-51333 0 0 0 0 0
2011-07-13 00:00:00+08 353736 29448-51343 1 0 0 8 0
2011-07-13 00:00:00+08 359681 29448-51462 0 0 0 0 0
2011-07-13 00:00:00+08 354707 29448-51462 0 0 0 0 0
2011-07-13 00:00:00+08 356137 29448-51470 0 0 0 0 0
Time taken: 0.086 seconds, Fetched: 10 row(s)
创建结果表 jizhan_result
create table jizhan_result(
imei string,
drop_num int,
duration int,
drop_rate double
);
select imei,sum(drop_num) sdrop,sum(duration ) sdura,
sum(drop_num)/sum(duration) drop_rate
from jizhan
insert into jizhan_result
group by imei
order by drop_rate desc;
Select * from jizhan_result limit 10;
[root@node4 data]# hdfs dfs -mkdir /usr/wordcount
[root@node4 data]# hdfs dfs -put wc.txt /usr/wordcount
[root@node4 data]# hdfs dfs -ls /usr
drwxr-xr-x - root supergroup 0 2020-02-05 11:28 /usr/wordcount
[root@node4 data]# hdfs dfs -ls /usr/wordcount
Found 1 items
-rw-r--r-- 2 root supergroup 265 2020-02-05 11:28 /usr/wordcount/wc.txt
hive> create external table wc(line string) location '/usr/wordcount';
OK
Time taken: 0.053 seconds
hive> select * from wc;
OK
hello tom
hi lucy
hive hadoop
node zk
create table wc_count(word string,count int);
select split(line,' ') from wc;
OK
["hello","tom"]
["hi","lucy"]
["hive","hadoop"]
select explode(split(line,' ')) from wc;
hello
tom
hi
lucy
select word,count(word)
from (select explode(split(line,' ')) word from wc) tmp
group by word;
c 1
hadoop 1
hello 3
hi 3
hive 1
java 1
lucy 2
node 1
tom 1
zk 2
我们想将结果保存到 wc_count 表中
insert into wc_count
select word,count(word) count
from (select explode(split(line,' ')) word from wc) tmp
group by word;
通过 ${} 方式进行引用,其中 system、env 下的变量必须以前缀开头。
1、修改配置文件 ${HIVE_HOME}/conf/hive-site.xml
2、启动 hive cli 时,通过 --hiveconf key=value 的方式进行设置
例:hive --hiveconf hive.cli.print.header=true
3、进入 cli 之后,通过使用set命令设置
注意:2 和 3 两种方式设置的参数只在当前会话有效。
在 hive CLI 控制台可以通过 set 对 hive 中的参数进行查询、设置
set 设置:
set hive.cli.print.header=true;
set查看
set hive.cli.print.header;
查看该参数的值
set;查看hive的所有参数。
hive历史操作命令集
~/.hivehistory
hive 参数初始化配置
当前用户家目录下的 .hiverc 文件
如: ~/.hiverc
如果没有,可直接创建该文件,将需要设置的参数写到该文件中,hive 启动运行时,会加载改文件中的配置。
[root@node4 ~]#vim .hiverc
set hive.cli.print.header=true;
[root@node4 ~]#hive
hive>
开启支持动态分区
set hive.exec.dynamic.partition=true;
默认:true
set hive.exec.dynamic.partition.mode=nostrict;
默认:strict 严格模式(比如订单表以秒为单位创建分区,将会导致特别多的分区,严格模式一般不允许,但是非严格模式允许)。
nostrict: 非严格模式
案例演示:
创建原始数据表
create table person21(
id int,
name string,
age int,
gender string,
likes array<string>,
address map<string,string>
)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':';
load data local inpath '/root/data/person21.txt' into table person21;
create table person22(
id int,
name string,
likes array<string>,
address map<string,string>
)
partitioned by(age int,gender string)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':';
加载数据
insert overwrite table person22 partition(age, gender)
select id, name,likes, address,age, gender distribute by age, gender;
from person21
或简写为:
insert overwrite table person22 partition(age, gender)
select id, name,likes, address,age, gender;
from person21
注意:分区字段一定要写到最后面,否则容易出错。
show partitions person22;
#查询某表上的 分区
相关参数
set hive.exec.max.dynamic.partitions.pernode;
每一个执行 mr 节点上,允许创建的动态分区的最大数量(100)
set hive.exec.max.dynamic.partitions;
所有执行 mr 节点上,允许创建的所有动态分区的最大数量(1000)
set hive.exec.max.created.files;
所有的 mr job 允许创建的文件的最大数量(100000)
分桶表是对列值取哈希值的方式,将不同数据放到不同文件中存储。
对于 hive 中每一个表、分区都可以进一步进行分桶。
由列的哈希值除以桶的个数来决定每条数据划分在哪个桶中。
适用场景:
对比 MR 的 HashPartition
数据抽样( sampling )
set hive.enforce.bucketing=true;
默认:false;设置为 true 之后,mr 运行时会根据 bucket 的个数自动分配reduce task 个数。(用户也可以通过 mapred.reduce.tasks 自己设置 reduce 任务个数,但分桶时不推荐使用)
注意:一次作业产生的桶(文件数量)和 reduce task 个数一致。
insert into table bucket_table select columns from tbl;
insert overwrite table bucket_table select columns from tbl;
select * from bucket_table tablesample(bucket 1 out of 4 on columns);
TABLESAMPLE 语法:
TABLESAMPLE(BUCKET x OUT OF y)
x:表示从哪个 bucket 开始抽取数据
y:必须为该表总 bucket 数的倍数或因子
当表总 bucket 数为 32 时
例:
CREATE TABLE psn31( id INT, name STRING, age INT)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
测试数据:
[root@node4 ~]# vim bucket
1,tom,11
2,cat,22
3,dog,33
4,hive,44
5,hbase,55
6,mr,66
7,alice,77
8,scala,88
加载原始数据:
hive> load data local inpath '/root/bucket' into table psn31;
创建分桶表
CREATE TABLE psnbucket( id INT, name STRING, age INT)
CLUSTERED BY (age) INTO 4 BUCKETS
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
desc formatted psnbucket;
莫忘记开始分桶支持:
set hive.enforce.bucketing=true;
从源数据表向分桶表中添加数据:
insert into table psnbucket select id, name, age from psn31;
抽样
hive> select id, name, age from psnbucket tablesample(bucket 2 out of 4 on age);
OK
id name age
3 dog 33
7 alice 77
[root@node4 ~]# hdfs dfs -cat /user/hive_remote/warehouse/psnbucket/000001_0
7,alice,77
3,dog,33
总结:分区是分目录存储,分桶是将表中的数据分文件存储。