http:--hive.apache.org/
Hive 是基於Hadoop的一個數據倉庫工具,可以將結構化的數據文件映射成一張表,並提供類SQL查詢功能。
*使用HQL作為查詢接口;
*使用HDFS存儲;
*使用MapReduce計算。
hiveql要結合mapReduce來讀,會有很多想法
靈活性號,自定義函數,自定義存儲格式
groupby#按K來把數據進行分組
orderby#全局排序
join#兩個表進行連接
distribute by#把數據打散,按字段把數據分到不同的文件里面
sort by#會把每個reducer上的數據進行排序,局部排序
cluster by#cluster by 除了具有 distribute by 的功能外還兼具 sort by 的功能。
union all 把多個表進行組合起來形成一個新表
理解hadoop的核心能力,是hive優化的根本
https:--blog.csdn.net/preterhuman_peak/article/details/40649213
長期觀察hadoop處理數據的過程,有幾個顯著的特征:
1.不怕數據多,就怕數據傾斜。
2.對jobs數比較多的作業運行效率相對比較低,比如即使有幾百行的表,如果多次關聯多次匯總,產生十幾個jobs,沒半小時是跑不完的。map reduce作業初始化的時間是比較長的。
3.對sum,count來說,不存在數據傾斜問題。
4.對count(distinct ),效率較低,數據量一多,准出問題,如果是多count(distinct )效率更低。
日志內容,統一規范
Schema 模式,約束
Hive
*處理的數據存儲在HDFS
*分析數據底層的實現MapReduce
*執行程序運行的Yarn
Select substring(ip,0,4) ip_prex from bg_log;
查看表的建立情況
hive> select * from stat_boss_order_paid_tw where dt="2018-06-27";
CREATE TABLE `stat_boss_order_paid_tw`(
`datavalue` string,
`platform` int,
`pay_type` int,
`actcode` string,
`push_channel` int,
`gateway` int,
`ispaid` int,
`renewals` int,
`autorenew` int,
`bfr` int,
`totalpaidp` int,
`total_income` int,
`totalvodp` int,
`total_vod_income` int,
`totalvipp` int,
`total_vip_income` int,
`totalmonthp` int,
`total_month_income` int,
`totalquarterp` int,
`total_quarter_income` int,
`totalsuccessivequarterp` int,
`total_successive_quarter_income` int,
`totalhalfyearp` int,
`total_halfyear_income` int,
`totalyearp` int,
`total_year_income` int,
`totalsuccessiveyearp` int,
`total_successive_year_income` int,
`otherp` int,
`total_other_income` int)
PARTITIONED BY (
`dt` string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.SequenceFileInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat'
LOCATION
'hdfs:--hadoop-bd-ns01/hive/warehouse/hadoopclient_user.db/stat_boss_order_paid_tw'
TBLPROPERTIES (
'transient_lastDdlTime'='1530002639')
Time taken: 0.036 seconds, Fetched: 43 row(s)
察看hdfs文件情況
hive>dfs –du -h hdfs:--hadoop-bd-ns01/hive/warehouse/hadoopclient_user.db/stat_boss_order_paid_tw;
4.4 K 13.1 K hdfs:--hadoop-bd-ns01/hive/warehouse/hadoopclient_user.db/stat_boss_order_paid_tw/dt=2017-11-09
4.8 K 14.3 K hdfs:--hadoop-bd-ns01/hive/warehouse/hadoopclient_user.db/stat_boss_order_paid_tw/dt=2017-11-10
5.3 K 16.0 K hdfs:--hadoop-bd-ns01/hive/warehouse/hadoopclient_user.db/stat_boss_order_paid_tw/dt=2017-11-11
5.0 K 15.0 K hdfs:--hadoop-bd-ns01/hive/warehouse/hadoopclient_user.db/stat_boss_order_paid_tw/dt=2017-11-12
4.7 K 14.1 K hdfs:--hadoop-bd-ns01/hive/warehouse/hadoopclient_user.db/stat_boss_order_paid_tw/dt=2017-11-13
4.8 K 14.5 K hdfs:--hadoop-bd-ns01/hive/warehouse/hadoopclient_user.db/stat_boss_order_paid_tw/dt=2017-11-14
4.6 K 13.9 K hdfs:--hadoop-bd-ns01/hive/warehouse/hadoopclient_user.db/stat_boss_order_paid_tw/dt=2017-11-15
4.6 K 13.7 K hdfs:--hadoop-bd-ns01/hive/warehouse/hadoopclient_user.db/stat_boss_order_paid_tw/dt=2017-11-16
4.6 K 13.9 K hdfs:--hadoop-bd-ns01/hive/warehouse/hadoopclient_user.db/stat_boss_order_paid_tw/dt=2017-11-17
5.3 K 15.8 K hdfs:--hadoop-bd-ns01/hive/warehouse/hadoopclient_user.db/stat_boss_order_paid_tw/dt=2017-11-18
分布式資源隊列問題
hive> select count(*) from stat_boss_order_paid_tw where dt="2018-06-27";
這樣的語句需要申請分布式資源
每次開客戶端CLI set mapred.job.queue.name=de.video;
Job Submission failed with exception 'java.io.IOException(org.apache.hadoop.yarn.exceptions.YarnException: Failed to submit application_1530601329233_1135466 to YARN : User hadoopclient_user cannot submit applications to queue root.default)'
創建表
hive> create table tmg(id int,name string,age int)
> row format delimited --每行為一個記錄
> fields terminated by "\t"; --記錄數據段制表符分割
hive>load data local inpath '/home/Hadoop/order.data'into table tmg; --本地路徑
hive> load data inpath '/order.data2'into table tmg; --hdfs路徑
創建和加載數據可以寫在一起 接起來
創建外部表
Hive中的外部表和表很類似,但是其數據不是放在自己表所屬的目錄中,而是存放到別處,這樣的好處是如果你要刪除這個外部表,該外部表所指向的數據是不會被刪除的,它只會刪除外部表對應的元數據;而如果你要刪除內部表,該表對應的所有數據包括元數據都會被刪除。
hive>create external table torder_ext(id int,name string,money double)
>row format delimited
>fields terminated by ','
>loation '/hive-tmp/order/';
創建外部表
create external table if not exists stock(exchange string,volume int)
row format delimited
fields terminated by ','
location '/data/stocks';
describe extended tablename
管理表 tableType:MANAGED_TABLE
外部表 tableType:EXTERNAL_TABLE
外部表復制表結構,也可以復制管理表的結構
create external table if not exists hdata.employee2
like hdata.employee
location '/data/employee';
查詢存儲
創建表來存儲查詢結果
create table tab_ip_ctas
as
select id new_id,name new_name,ip new_ip,country new_country
from tab_ip_ext
sort by new_id;
向臨時表中追加中間結果數據
Insert overwrite table tab_ip_like select * from tab_ip
Partition 分區
hive >create table tab_ip_part(id int,name string,price double)
hive > partitioned by(country string)
hive >row foamat delimited
hive>rields terminated by ',';
導數據時起作用
load data local inpath '/home/Hadoop/order.data'into table t_order_part partition(country='China');
load data local inpath '/home/Hadoop/order.data.2'into table t_order_part partition(country='forengn');
select * from t_order_part where country='China'and prince>2400;
已有的表添加分區
Alter table tab_cts add partition(partCol='dt') location '/external/hive/dt';--直接指定數據
show partitions tab_ip_part;
hive> select * from stat_boss_order_paid_tw where dt="2018-06-27";
hive> set hive.mapred.mod=strict; --設置嚴格模式,如果語句沒有分區過濾就不執行
hive> set hive.mapred.mod=nonstrict;
hive> show partitions employee; --查看分區
load data local inpath '${env:HOME}/dis_employee_data'
into table employees
partition(contry='US',state='CA'); --兩個分區字段
外部分區表
create external table if not exists log_mesg(
hms int,
server sting)
partitioned by (year int,month int dat int)
row format delimited
fields terminated by '\t';
增加分區
alter table log_mesg add partition(year=2012,month=2,day=1)
location 'hdfs://master_server/data/log_mess/2012/02/01';
可以將前一個月的數據拷貝到s3存儲設備
Hadoop distcp /data/logmess/2012/01/02 s3n://ourbucket/logs/2012/01/02
將分區路徑指向s3
Alter table log_mess partion(year=2012,month=01,day=02)
set location 's3n://ourbucket/logs/2012/01/02'
刪除掉原來分區的數據
Hadoop fs –rmr /data/logmess/2012/01/02
Desc externed log_mess partition(year=2012,month=01,day=02);
輸出結果到hdfs
insert overwrite local directory '/home/Hadoop/hivetemp/test.txt' select * from tab_ip_part where part_flag='part1';
insert overwrite directory '/hiveout.txt' select * from tab_ip_part where part_flag='part1';
hadoop fs –cat /hiveout.txt/*
CLUSTER
create table tab_ip_cluster(id int,name string,ip string,country string)
clustered by(id) into 3 buckets;
load data local inpath '/home/hadoop/ip.txt' overwrite into table tab_ip_cluster;
set hive.enforce.bucketing=true;
insert into table tab_ip_cluster select * from tab_ip;
select * from tab_ip_cluster tablesample(bucket 2 out of 3 on id);
表array
hive >create table tab_array(a array<int>,b array<sting>)
hive >row farmat delimited
hive >fields terminated by '\t'
hive >collection items terminated by ',';
例如數據 allen,jarry,tom 132,222,123
Fengxiang,jin,kol 122,112,123
hive >select a[0] from tab_array; 第一行
hive >select a from tab_array; a字段全部列出
select * from tab_array where array_contains(b,'word');
insert into table tab_array select array(0),array(name,ip) from tab_ext t;
map
create table tab_map(name string,info map<string,string>)
row format delimited
fields terminated by '\t'
collection items terminated by ','
map keys terminated by ':';
示例數據:
marry age:18;height:156;addr:usa
jenny age:20;height:160;addr:Canna;weight:45KG
數據個數可以不一樣
load data local inpath '/home/hadoop/hivetemp/tab_map.txt' overwrite into table tab_map;
insert into table tab_map select name,map('name',name,'ip',ip) from tab_ext;
struct
create table tab_struct(name string,info struct<age:int,tel:string,addr:string>)
row format delimited
fields terminated by '\t'
collection items terminated by ','
數據個數定好了
load data local inpath '/home/hadoop/hivetemp/tab_st.txt' overwrite into table tab_struct;
insert into table tab_struct select name,named_struct('age',id,'tel',name,'addr',country) from tab_ext;
Udf用戶定義函數
Java寫類
方法的修飾符必須為public
package cn.itheima.bigdata.hive;
import org.apache.hadoop.hive.ql.exec.UDF;
public class PhoneToAreaUDF extends UDF
{
public static HashMap<String,String> areaMap=new HashMap();
static{
areaMap.put("136","beijing");
areaMap.put("137","tianjin");
areaMap.put("138","nanjing");
areaMap.put("139","shanghai");
areaMap.put("188","haikou");
}
--用來將手機號翻譯出城市名
public String evaluate(String phoneNum)
{
areaMap.get(phoneNum.substring(0,3));
return area==null?"huoxing":area;
}
--用來求上下行流量的和
private void evaluate(int up_flow,int d_flow)
{
return up_flow+d_flow;
}
}
打成jar包,傳到服務器
hive>add jar /home/hadoop/areaudf.jar;
hive>create temporary function area as 'cn.itheima.bigdata.hive.PhoneToAreaUDF' hive>create table t_flow(phonenum string,up_flow int,d_flow int)
>row format delimited
>fields terminated by ',';
hive>load data local inpath '……';
hive>select phonenum,area(phonenum),area(up_flow,d_flow) from t_flow;
Hive文檔深入閱讀
變量和屬性
hivevar 可讀可寫 用戶自定義變量
hiveconf 可讀可寫 hive相關配置屬性
system 可讀可寫 java定義的配置屬性
env 只可讀 shell環境定義的環境變量
hive變量內部是以java字符串方式存儲的
set命令可以修改變量
訪問系統環境變量,只能讀取變量
hive> set env:HOME;
env:HOME=/home/hadoopclient_user
$ hive --define foo=bar
hive> set foo;
foo=bar
hive> set hivevar:foo;
hivevar:foo=bar
hive> set hivevar:foo=bar2;
hive> set foo;
foo=bar2
hive> set hivevar:foo ;
hivevar:foo=bar2
--define key=value 等價於 –hivevar key= value
hive> create table toss(li int,${hivevar:foo} string); hivevar: 域可以省略
hive> desc toss;
li int
bar2 string
Create/Drop/Truncate Table
一次使用命令
$ hive –S –e "select * from mytable limit 3"> /tmp/myquery
$ cat /tmp/myquery
Name1 10
Name2 20
Name3 30
-S靜音模式,去掉一些"ok""time taken"等無關信息,輸出流寫入本地文件系統。
hive> set hive.cli.print.header=true; 可以設置select * from tableName;額外將字段名第一行打印出來
執行shell命令
hive> !/bin/echo "hello world";
"hello world"
hive> ! pwd ;
/usr/local/hive/bin
Hive中使用dfs命令
hive> dfs -ls /;
Found 2 items
drwxrwxr-x - root supergroup 0 2018-07-16 10:00 /tmp
drwxrwxr-x - root supergroup 0 2018-07-14 00:10 /user
數據類型
類型轉換,講一個s sting 轉換成int ...cast(s as int)...
| TINYINT |
1-byte signed integer, from -128 to 127 |
| SMALLINT |
2-byte signed integer, from -32,768 to 32,767 |
| INT/INTEGER |
4-byte signed integer, from -2,147,483,648 to 2,147,483,647 |
| BIGINT |
8-byte signed integer, from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
| FLOAT |
4-byte single precision floating point number |
| DOUBLE |
8-byte double precision floating point number |
| DOUBLE |
PRECISION |
| DECIMAL |
十進制 was introduced in Hive 0.11.0 (HIVE-2693) and revised in Hive 0.13.0 (HIVE-3976) |
| TIMESTAMP |
整數,浮點數或者字符串Note: Only available starting with Hive 0.8.0+ |
| DATE |
Note: Only available starting with Hive 0.12.0+ |
| INTERVAL |
Note: Only available starting with Hive 1.2.0+ |
| STRING |
字符串文字可以用單引號(')或雙引號(")表示 |
| BINARY |
字節數組 Note: Only available starting with Hive 0.8.0+ |
create table employees(
name string,
salary float,
subordinates array<string>, --下屬
deductions map<string,float>, --扣薪紀錄
address struct<street:sting,city:sting,state:string,zip: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;
一般 \n 來分割記錄
^A(\001) 分割字段
^B(\002) 分割array或者struct
^C(\003) 分割map中的key和value
hiveQL與mysql區別
hive不支持行級插入操作、更新操作和刪除操作,hive不支持事務,增加了hadoop下的可以提供更高性能的擴展,以及一些個性化擴展,增加了一些外部程序。
Create/Drop/ Alter Database
CREATE (DATABASE|SCHEMA) [IF NOT EXISTS] database_name
[COMMENT database_comment] --描述信息
[LOCATION hdfs_path] --修改默認位置
[WITH DBPROPERTIES (property_name=property_value, ...)];
hive> show databases like 'h.*';
database_name
hdata
-------------------------------------------------------------------------
hive> desc database hdata;
db_name comment location owner_name owner_type parameters
hdata hdfs:--localhost:9000/user/hive/warehouse/hdata.db root USER
------------------------------------------------------------------------
hive> create database financials
> with dbproperties('creator' = 'Tomy','date'='2018-07-03');
hive> desc database financials;
db_name comment location owner_name owner_type parameters
financials hdfs:--localhost:9000/user/hive/warehouse/financials.db root USER
hive> desc database extended financials;
db_name comment location owner_name owner_type parameters
financials hdfs:--localhost:9000/user/hive/warehouse/financials.db root USER {date=2018-07-03, creator=Tomy}
hive> set hive.cli.print.current.db=true; --顯示當前的數據庫
hive (financials)>
hive> drop database if exist financials;
默認情況下hive不允許刪除一個有表的數據庫,應該先刪除表在刪數據庫,否則要用關鍵字cascade,hive自行刪除表再刪除database
hive> drop database if exist financials cascade;
修改數據庫屬性
hive (financials)> alter database financials set dbproperties('edited-by'='joe dba');
Time taken: 0.149 seconds
hive (financials)> desc database extended financials;
db_name comment location owner_name owner_type parameters
financials hdfs:--localhost:9000/user/hive/warehouse/financials.db root USER {date=2018-07-03, edited-by=joe dba, creator=Tomy}
Create Table
create table if not exists default.bf_log_20190714
(
ip string comment 'remote ip address', --字段名,類型,注釋
user string,
req_url string comment 'user request url'
)
comment 'web access log' --對表的注釋
row format delimited fields terminated by ' ' --列分隔
collection items terminated by '\n' --默認記錄回車分割,可以不寫
stored as textfile --默認可以不寫,存儲為文本文件
location '/user/hive/warehouse/'; --默認為hdfs用戶目錄下
load data local inpath '/opt/datas/bf_log.txt'into table default.bf_log_20190714;
---------------------------------------------------------------------------
create table if not exists default.bf_log_20190714_sa --根據一個查詢建表
as select ip,user from default.bf_log_20190714;
------------------------------------------------------------------------------
create table if not exists default.bf_log_20190715
like default.bf_log_20190714; --根據已有的表創建同樣結構
===========================================================
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.] table_name -- ()
[(col_name data_type [COMMENT col_comment], ... [constraint_specification])]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
[SKEWED BY (col_name, col_name,
ON ((col_value, col_value, ...), (col_value, col_value, ...), ...)
[STORED AS DIRECTORIES]
[
[ROW FORMAT row_format] –分隔
[STORED AS file_format] –默認文本
| STORED BY 'storage.handler.class.name' [WITH SERDEPROPERTIES (...)] --
]
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)] -- (Note: Available in Hive 0.6.0 and later) --表屬性例如'cretor'='Tomy'
[AS select_statement]; -- (Note: Available in Hive 0.5.0 and later; not supported for external tables)
CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name
LIKE existing_table_or_view_name
[LOCATION hdfs_path];
data_type
: primitive_type
| array_type
| map_type
| struct_type
| union_type -- (Note: Available in Hive 0.7.0 and later)
primitive_type
: TINYINT
| SMALLINT
| INT
| BIGINT
| BOOLEAN
| FLOAT
| DOUBLE
| DOUBLE PRECISION -- (Note: Available in Hive 2.2.0 and later)
| STRING
| BINARY -- (Note: Available in Hive 0.8.0 and later)
| TIMESTAMP -- (Note: Available in Hive 0.8.0 and later)
| DECIMAL -- (Note: Available in Hive 0.11.0 and later)
| DECIMAL(precision, scale) -- (Note: Available in Hive 0.13.0 and later)
| DATE -- (Note: Available in Hive 0.12.0 and later)
| VARCHAR -- (Note: Available in Hive 0.12.0 and later)
| CHAR -- (Note: Available in Hive 0.13.0 and later)
array_type
: ARRAY < data_type >
map_type
: MAP < primitive_type, data_type >
struct_type
: STRUCT < col_name : data_type [COMMENT col_comment], ...>
union_type
: UNIONTYPE < data_type, data_type, ... > -- (Note: Available in Hive 0.7.0 and later)
row_format
: DELIMITED [FIELDS TERMINATED BY char [ESCAPED BY char]] [COLLECTION ITEMS TERMINATED BY char]
[MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
[NULL DEFINED AS char] -- (Note: Available in Hive 0.13 and later)
| SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)]
file_format:
: SEQUENCEFILE
| TEXTFILE -- (默認文本, depending on hive.default.fileformat configuration)
| RCFILE -- (Note: Available in Hive 0.6.0 and later)
| ORC -- (Note: Available in Hive 0.11.0 and later)
| PARQUET -- (Note: Available in Hive 0.13.0 and later)
| AVRO -- (Note: Available in Hive 0.14.0 and later)
| JSONFILE -- (Note: Available in Hive 4.0.0 and later)
| INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname
constraint_specification:
: [, PRIMARY KEY (col_name, ...) DISABLE NOVALIDATE ]
[, CONSTRAINT constraint_name FOREIGN KEY (col_name, ...) REFERENCES table_name(col_name, ...) DISABLE NOVALIDATE
查詢另一個數據庫的表
hive (financials)> show tables in hdata;
tab_name
tmg
toss
hive (hdata)> show tables [like] 't.*';
tab_name
tmg
toss
hive (financials)> show tables like 't.*' in hdata; 錯誤
in和正則表達式不同時使用
hive (financials)> desc extended hdata.toss;
可以顯示parameters 屬性
使用formatted代替extended得到結果可讀性要更強
表自動有兩個屬性 last_modified_by 和 last_modified_time,並且不會顯示在表的詳細信息中
自定義表存儲格式
Hive 存儲格式是文本文件,也可以用 stored as textfile來顯示設定
create table employees(
name string,
salary float,
subordinates array<string>, --下屬
deductions map<string,float>, --扣薪紀錄
address struct<street:sting,city:sting,state:string,zip: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;
存儲記錄編碼是通過inputformat 對象來控制的,hive使用一個名為org.apache.hadoop.mapred.TextInputFormat的java類
將輸入流->記錄
記錄的解析是用Serde 序列化器/反序列化器來控制的,
記錄->列
Hive還有一個outputformat的對象來講查詢的輸出寫入文件中或者控制台記錄格式化->輸出流
刪除表
drop table if exists employees;
外部表,表的元數據信息會刪除,數據文件本身不會刪除
修改表
重命名
alter table log_mess rename to log_message;
增加、修改和刪除分區
alter table log_mess add [if not exists]
partition (year=2011,month=1,day=1) location '/logs/2011/01/01'
partition (year=2011,month=1,day=1) location '/logs/2011/01/02';
可以增加多個分區
移動位置修改分區
alter table log_mess partition(year=2012,month=01,day=02)
set location 's3n://ourbucket/logs/2012/01/02';
該命令不會移走外部表舊數據,也不會刪除舊數據
刪除分區
alter table log_mess drop if exists partion(year=2012,month=01,day=02);
外部表的數據文件依然不會刪除
修改列信息
重命名
alter table log_mess
change [column] hms hours_min_sec int
[comment 'the hours,minutes and seconds']
after severity; --將更改的字段移到severity字段之后,如果要放在第一個位置,用first代替after severity即可
即使字段名和類型只有一個改變,也要都重新指定
增加列
alter table log_mess
add columns(
app_name string comment 'sdfsd'
session_id long comment 'dfsdf'
);
刪除/替換列
alter table log_mess replace columns(
hours int
server string
)
Alter 只改變元信息
修改表屬性
alter table log_mess set tblproperties(
'note'='aaadfsd');
只能修改或者增加屬性,不能刪除屬性
修改存儲屬性
alter table log_mess
partition(year=2012, month=01,day=02)
set fileformat sequencefile;
其他修改語句
場景1:當表中存儲的文件在hive之外被修改了,就會觸發touch鈎子的執行
alter table log_mess
touch
partition(year=2012,month=01,day=02);
場景2:如果表或者分區不存在,那么上述語句不會創建表或者分區,那么下述語句會將這個分區內的文件打成hadoop壓縮包(HAR)文件
alter table log_mess
archive
partition(year=2012,month=01,day=02);
unchive可以反向操作
alter table log_mess
partition(year=2012,month=01,day=02) enable no_drop;
alter table log_mess
partition(year=2012,month=01,day=02) enable offline;
enable 替換disable可以反向操作
數據操作
向管理表裝載數據
load data local inpath '${env:HOME}/dis_employee_data'
overwrite into table employees
partition(contry='US',state='CA'); --兩個分區字段
overwrite:如果目錄不存在的話,這個命令會先創建分區目錄,然后在將數據拷貝到該目錄。
如果存在的話,之前的數據會被覆蓋。
load data 沒有local關鍵字,只能源文件和目標文件以及目錄在同一個文件系統,即不允許從一個集群hdfs轉載數據到另一個集群hdfs。
Hdfs 默認為/user/$USER
Hive還會驗證文件存儲格式是否一致。
通過查詢語句向表中插入數據
insert overwrite table employees
partition (country='US',state='OR')
select * from staged_employees se
where se.cnty='US'and se.st='OR';
但是如果staged_employees表非常大,有多個分區,那么就得掃描好多次,如下語句可以解決
from staged_employees se
insert overwrite table employees --或者insert into
partition(country='US',state='OR')
select * where se.cnty='US'and se.st='OR'
insert overwrite table employees
partition(country='US',state='CA')
select * where se.cnty='US'and se.st=' CA'
insert overwrite table employees
partition(country='US',state='IL')
select * where se.cnty='US'and se.st='IL';
動態分區插入
如果要創建非常多的分區,用戶就需要寫非常多的sql,而動態分區可以基於查詢的參數推斷出需要創建的分區名稱。
insert overwrite table employees
partition (country, state)
select …,se.cnty,se.st from staged_employees se ;
根據最后2列來確定分區字段country和state值。根據位置來匹配。
如果country和state值有100組的話,那么employees將會有100個分區。
用戶也可以混合靜態和動態分區
insert overwrite table employees
partition (country='US', state)
select …,se.cnty,se.st from staged_employees se
where se.cnty='US' ;
靜態分區鍵必須出現在動態分區鍵之前
動態分區功能默認未開啟,開始后默認是以'嚴格'模式執行的,在這種模式下要求至少有一列分區字段是靜態的。防止用戶使用時間戳等來作為分區。
hive .exec.dynamic.partition false 設置成true,表示開啟動態分區功能
hive.exec.dynamic.patition.mode strict 設置成nonstrict,允許所有分區都是動態的,否則要求至少有一列分區字段是靜態的
創建表存儲單個查詢語句結果
Create table ca_employee
as
select name,salary,address from employees
where se.state='CA';
導出數據
如果是需要的數據文件
hadoop –fs –cp source_path target_path
否則
insert overwrite local derectory '/tmp/ca_employees'
select name,salary,address from employees se
where se.state='CA';
一個或多個文件會被寫入這個文件目錄,具體個數由調用的reducer決定
指定目錄也可以是url全路徑 hdfs://master-server/tmp/ca_employees
導出多個
from employees se
insert overwrite local direction '/tmp/or_employees'
select name,salary,address where se.cty='US'and se.state='OR';
insert overwrite local direction '/tmp/ca_employees'
select name,salary,address where se.cty='US'and se.state='CA';
insert overwrite local direction '/tmp/il_employees'
select name,salary,address where se.cty='US'and se.state='IL';
查詢
**在SELECT子句中出現的字段或屬性,同時有聚合函數存在,如果不是在聚合函數中,那就必須要放到GROUP BY子句里面去,反過來,沒有出現在GROUP BY子句中的字段或屬性,只能在聚合函數中。
create table employees(
name string,
salary float,
subordinates array<string>, --下屬
deductions map<string,float>, --扣薪紀錄
address struct<street:sting,city:sting,state:string,zip:int>) --地址
partitioned by(country sting,state sting);
select name,subordinates, subordinates[0],deductions,address,deductions["State Taxes"],address.city from employees;
正則表達式來指定列
select symbol,'price.*' from stocks; 有問題
hive> desc tmg;
OK
id int
name string
age int
time string
hive> select id,'na.*' from tmg;
OK
1 na.*
2 na.*
3 na.*
使用列值進行計算
select upper(name),salary,deduction["Federal Taxes"],round(salary*(1- deduction["Federal Taxes"])) from employee;
int和 bigint 計算會提升為bigint
int和float計算會提升為float
注意數據溢出和下溢,參照java數據結構
函數
https://www.cnblogs.com/yejibigdata/p/6380744.html
round(1.3) floor(1.3) ceil/ceiling(1.3) rand() exp(1.1) ln(1.3) log10(1.3) log2(1.3) log(1.2,1.3) pow(1.2,1.3) /power sqrt(1.3) bin(1.3)得到二進制的string類型 hex(20)十六進制string類型 hex('str') hex(binary b) unhex(string i) conv(bigint i,int base,int to_base) 將i從base進制轉換為to_base
abs(1.3) pmod(int i,int j)i對j取模,double類型也可以
sin(1.3) 弧度 asin() cos() acos() tan() atan() degrees(1.3) 弧度變角度 radians(1.3)角度變弧度
positive(int i)返回值本身也可以double negative()相反數 sign(1.3) 返回正負號1.0/-1.0 e()自然常數 pi() 圓周率
數學函數見hive編程指南85頁
聚合函數注意distinct的使用
hive> set hive.map.aggr=true 提高聚合函數的性能,需要更多的內存
表生成函數
與聚合函數相反
select explode(subordinates) as sub from employees;
使用表生成函數時,必須使用列別名
-
parse_url函數使用案例
parse_url('http://facebook.com/path/p1.php?query=1', 'HOST')返回'facebook.com' ,
parse_url('http://facebook.com/path/p1.php?query=1', 'PATH')返回'/path/p1.php' ,
parse_url('http://facebook.com/path/p1.php?query=1', 'QUERY')返回'query=1',
或,可以指定key來返回特定參數,key的格式是QUERY:,
例如:QUERY:k1
parse_url('http://facebook.com/path/p1.php?query=1#Ref', 'REF')返回'Ref'
parse_url('http://facebook.com/path/p1.php?query=1#Ref', 'PROTOCOL')返回'http'
HIVE直接讀入json的函數有兩個:
(1)get_json_object(string json_string, string path)
返回值: string
說明:解析json的字符串json_string,返回path指定的內容。如果輸入的json字符串無效,那么返回NULL。
舉例:
hive> select get_json_object('{"store":{"fruit":\[{"weight":8,"type":"apple"},{"weight":9,"type":"pear"}], "bicycle":{"price":19.95,"color":"red"}}, "email":"amy@only_for_json_udf_test.net", "owner":"amy" } ','$.owner') from dual;
結果:amy
注:如果ower是一個數組 path還可以用$.owner[0] 這樣的坐標來獲取具體的數據
這個函數每次只能返回一個數據項。
(2)json_tuple(jsonStr, k1, k2, ...)
參數為一組鍵k1,k2……和JSON字符串,返回值的元組。該方法比 get_json_object 高效,因為可以在一次調用中輸入多個鍵
select a.timestamp, b.*
from log a lateral view json_tuple(a.appevent, 'eventid', 'eventname') b as f1, f2;
處理數據樣例:
{"GPS_LAT":39.8965125,"GPS_LONG":116.3493225,"GPS_SPEED":20.9993625,"GPS_STATE":"A","GPS_TIME":"2014-01-02 00:00:16","IMEI":"508597","after_oxygen_sensor":132,"air_condion_state":3,"bdoneNo_after_mileage":0,"bdoneNo_zero_mileage":8044,"db_speed":22,"direction_angle":358.2585,"front_oxygen_sensor":64,"instant_fuel":233,"speed":1210,"torque":33,"total_fuel":0}
處理HIVE語句:
create table 2014jrtest as select json_tuple(line,'GPS_LAT','GPS_LONG','GPS_SPEED','GPS_STATE','GPS_TIME','IMEI','after_oxygen_sensor','air_condion_state','bdoneNo_after_mileage','bdoneNo_zero_mileage','db_speed','direction_angle','front_oxygen_sensor','instant_fuel','speed','torque','total_fuel') from 2014test;
其他內置函數
ascii(strings) ->string 返回字符串首個ascii字符的整數值
base64(binary bin) ->string 將二進制bin轉換成給予64位的字符串
binary(string s) -> binary / binary(binary s) -> binary 將字符串轉換為二進制
case(<expr> as <type>) 將expr轉換為type cast('1',bigint)
concat(binary s1,binary s2,…) 或者string類型,拼接為字符串最終都為sting類型
concat_ws(string sep,binary s1,string s2,...)用在指定分隔符sep將后面的拼接為字符串
hive (hdata)> select concat_ws('+','hello','world');
hello+world
decode(binary bin,string charset) 將二進制解碼成字符串 'US-ASCII','IOS-8859-1','UTF-8','UTF-16BE', 'UTF-16LE', 'UTF-16'
encode(string src,string charset) 將字符串src編碼成二進制
find_in_set(string s,string commaSeparatedString) 返回在以逗號分隔的字符串中s出現的位置
hive (hdata)> select find_in_set('a','ba,c,a,da,f');
3
format_number(number x,int d)->string x保留d位小數
in
if語句
hive> select if(a=a,'bbbb',111) fromlxw_dual;
bbbb
hive> select if(1<2,100,200) fromlxw_dual;
200
case when then語句
hive>select name,salary,
> case
> when salary<5000.0 then 'low'
> when salary>=5000.0 and salary<7000.0 then 'middle'
> when salary>=7000.0 and salary<10000.0 then 'high'
> else 'very high'
> end as bracket from employees;
避免進行MapReduce
本地模式可以不觸發mapreduce
select * from employees
可以簡單的讀取對應存儲目錄下的文件,然后輸出格式化內容到控制台
對於where語句中過濾條件只是分區字段這種情況也無需MapReduce
select * from employees where country='US'and state='CA'limit 100;
set hive.exec.mode.local.auto=true;嘗試使用本地模式執行其他操作
where語句
hive (hdata)> select name, age agggge from tmg where agggge<20;
錯誤 where語句中不能有別名,改為嵌套查詢
hive (hdata)> select e.* from (select name,age agggge from tmg) e
where e.agggge<20;
baby 18
yifei 19
謂詞
A<=>B 如果A和B都為NULL,返回true,其他的和= 一致
a<>b, a!=b
a==b 錯誤語法 而是a=b來判斷
a [not ] between b and c 三者任一為NULL,結果為NULLL, a>=b and a<=c
a is NULL
a is not null
a [not] like b b如果為'x%'表示必須以x開頭,'%x'表示含有x即可
a rlike b / a regexp b b如果是a的正則表達式則返回true
浮點數注意
0.2轉換成float為0.2000001 轉換成double為0.200000000001
所以會出現where x>0.2 如果x為float的話,會選出0.2
解決方法1,存儲時用double
方法2 where x>cast(0.2 as float)
正則表達式
rlike '.*(Chicago|Ontario).*' .代表任一字符 *重復左邊字符0-無數次
like '%Chicago%'
group by
select year(ymd),avg(price_close) from stocks
where exchange='NASDAQ' and symbol='AAPL'
group by year(ymd);
having
允許用戶通過一個簡單的語法完成對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;
不用having的話,需要對選出的表再用where篩選一遍,嵌套
select s2.year,s2.avg from(
select year(ymd) year,avg(price_close) avg from stocks
where exchange='NASDAQ' and symbol='AAPL'
group by year(ymd)) s2
where s2.avg>50.0;
Join語句
inner join
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';
以下語句錯誤
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';
pig提供了交叉生產的功能,pig中可以實現
hive不支持on語句中使用or
大多數情況下hive會對每對join連接對象啟動一個MapReduce任務
select a.ymd,a.price_close, b.price_close, c.price_close
from strocs a join stocks b on a.ymd = b.ymd
join stocks c on a.ymd =c.ymd
where a.symbol='AAPL'and b.symbol='IBM'and c.symbol='GE';
join優化,因為3張和更多的表連接時,使用同一個連接鍵,例如本例子中的a.ymd,只會產生一個MapReduce。
Hive同時假定查詢中最后一個表是最大的,對每行記錄連接后,嘗試將其他表緩存起來,然后掃描最后的表進行計算。因此需要保證連續查詢中的表的大小從左往右一次增大。
可以標記顯式地告訴查詢優化器那個表是最大的
select /*streamtable(s)*/ 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';
還有一個類似的優化map-side join
left outer join
左邊中符合where的記錄都會保留,右邊沒有符合on后面的連接條件的記錄值會是null
select s.ymd,s.symbol,s.price_close,d.dividend
from stocks s left outer join dividends d on s.ymd =d.ymd and s.symbol=d.symbol
where s.symbol='AAPL';
outer join
where字句中增加分區過濾器可以加快查詢速度,對exchange字段增加謂詞限定
select s.ymd,s.symbol,s.price_close,d.dividend
from stocks s left outer join dividends d on s.ymd=d.ymd and s.symbol=d.symbol
where s.symbol='AAPL'
and s.exchange='NASDAQ'and d.exchange='NASDAQ';
但是這個結果和內連接一樣,實際是先執行join語句,然后where過濾,此時d.exchange字段大多數為NULL,因此過濾掉了這些。
解決方法是去掉d.exchange
select s.ymd,s.symbol,s.price_close,d.dividend
from stocks s left outer join dividends d on s.ymd=d.ymd and s.symbol=d.symbol
where s.symbol='AAPL' and s.exchange='NASDAQ';
如果將where中的條件放在on語句中,可以工作,但是外鏈接會忽略分區過濾條件。不過內連接可以的
幸運的是,有一種適合所有種類連接的解決方案,嵌套select
select s.ymd,s.symbol,s.price_close,d.dividend
from
(select * from stocks where symbol='AAPL' and exchange='NASDAQ') s
left outer join
(select * from dividend where symbol='AAPL' and exchange='NASDAQ') d
on s.ymd=d.ymd;
right outer join 類似
full outer join
完全外連接
任一表中沒有對應記錄則null
Left-semi-join
首先滿足on語句的連接條件,返回左邊表的記錄
不支持以下語句
select s.ymd,s.symbol,s.price_close from stocks s
where s.ymd,s.symbol in
(
select d.ymd,d.symboo from dividends d
);
可以用如下語句來達到同樣目的
select s.ymd,s.symbol,s.price_close from stocks s
left semi join dividends d on s.ymd=d.ymd and s.symbol=d.symbol;
注意:select和where語句不能引用到右邊表的字段。
不支持right-semi-join
半連接比內連接高效,對於左邊表一條指定的記錄,在右邊表一旦找到匹配的記錄,hive就會停止掃描。
笛卡爾乘積join
select * from stocks join dividends;
左邊5行數據右邊6行數據,結果30行數據
select * from stocks join dividends
where stock.symbol=dividends.symbol and stock.symbol='AAPL';
先進行笛卡爾乘積的運算,再進行where篩選,不過消耗很長時間。如果hive.mapred.mode設為true時,hive會阻止執行笛卡爾乘積。
map-side join
如果所有表只有一張是小表,那么可以在最大的表通過mapper時將小表完全放倒內存中。Hive可以在map端執行連接過程(稱為map-side join過程),因而hive可以和內存中的小表進行逐一匹配,從而省略了常規連接操作所需要的reduce過程。
dividends表很小
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';
如果不加mapjoin這個標記,用戶可以設置屬性hive.auto.convert.JOIN=true,來觸發優化
屬性可以設置在$HOME/.hiverc中
用戶也可以配置能夠使用的小表的大小 hive.mapjoin.smalltalbe.filesize=25000000
但是右外連接和圈外鏈接不支持這個優化
如果表中數據是分桶的,對於大表,特定情況下可以用這個優化。表中數據必須根據on語句中的鍵進行分桶,其中一張表的分桶個數必須為另一張表分桶個數的若干倍,因此hive可以再map階段按照分桶數據進行連接。這種情況下不需要先獲取表中所有內容才去和另一張表中每個分桶進行匹配連接。
這個優化默認沒有開啟, set hive.optimize.bucketmapJOIN=true;
如果涉及的分桶表都具有相同的分桶數,而且數據是按照連接鍵或桶的鍵進行排序的,hive可以執行一個更快的分類-合並sort-merge JOIN,如下設置
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
set hive.optimize.bucketmapjoin=true;
set hive.optimize.bucketmapjoin.sortedmerge =true;
order by 和 sort by
order by會對查詢結果集執行一個全局排序。也就是會有一個所有的數據都通過一個reducer進行處理的過程,對於大數據集這個過程可能會消耗太過漫長的時間來執行。
而sort by,只會在每個reducer中對數據進行排序,也就是執行一個局部排序過程。這個可以保證每個reducer的輸出數據都是有序的(但是並非全局有序),這樣可以提高后面的全局排序的效率。
select s.ymd, s.symbol, s.price_close
from stocks s
order by s.ymd asc, s.symbol desc;
select s.ymd, s.symbol, s.price_close
from stocks s
sort by s.ymd asc, s.symbol desc;
含有sort by的distribute by
distribute by控制map的輸出在reducer中是如何划分的,MapReduce job中傳輸的所有數據都是按照鍵值對的方式進行組織的,因此hive在將用戶的查詢語句轉換成MapReduce job時必須在內部使用這個功能。
默認情況下,MapReduce會根據map輸入的鍵計算相應的hash值,然后均勻分發到多個reducer。而這樣就會在sort by時,不同的reducer輸出的內容會有明顯的重疊。
比如股票,希望具有相同股票交易碼的數據在一起處理,我們可以使用distribute by來保證相同股票交易碼的數據會分發到同一個reducer中去。
select s.ymd,s.symbol,s.price_close from stocks s
distribute by s.symbol
sort by s.symbol asc ,s.ymd asc;
group by 和 distribute by在控制着reducer接收數據記錄方面類似,但是distribute by 要寫在group by之前。
Cluster by
在上面的例子中,s.symbol 用在了distribute語句中,也用在了sort by語句中,如果這兩個語句涉及到的列完全相同,並且采用的是升序過程(默認排序),那么cluster by就等價於這兩個子句,
select s.ymd,s.symbol,s.price_close from stocks s
cluster by s.symbol;
distribute by …sort by 或者cluster by會剝奪sort by的並行性,然而這樣可以實現輸出文件的數據是全局排序的。
類型轉換
Salary是string類型
select name,salary from employees
where cast(salary as float)<100000.0;
如果salary字段不合法,則返回NULL,但是浮點數轉換成整數推薦round()或者floor()
類型轉換binary值
Binary類型只支持轉換為string類型,如果不確定其是否為數值,可以嵌套使用
b字段是binary類型
select (2.0*cast(cast(b as string) as double)) from src;
抽樣查詢
對於非常大的數據集,有時用戶需要使用的是一個具有代表性的查詢結果而不是全部結果。Hive可以通過對表進行分桶抽樣來滿足這個需求。
假設numbers 表只有number字段,其值為1~10,我們可以使用rand()函數進行抽樣,這個函數會返回一個隨機值,前兩個查詢都返回了兩個不相等的值,而第三個查詢語句無返回結果:
hive (hdata)> select * from tmg tablesample(bucket 2 out of 3 on rand()) s;
第一遍有輸出
第二遍有輸出
第三遍無輸出
如果我們按照指定列而非rand()函數進行分桶的話,同一語句執行多次返回結果相同。
hive (hdata)> select * from tmg tablesample(bucket 2 out of 3 on age) s;
分桶語句中分母表示是數據將會被分散的桶個數,而分子表示將會選擇的桶個數。
Hive 桶
對於每一個表(table)或者分區, Hive可以進一步組織成桶,也就是說桶是更為細粒度的數據范圍划分。Hive也是 針對某一列進行桶的組織。Hive采用對列值哈希,然后除以桶的個數求余的方式決定該條記錄存放在哪個桶當中。
把表(或者分區)組織成桶(Bucket)有兩個理由:
(1)獲得更高的查詢處理效率。桶為表加上了額外的結構,Hive 在處理有些查詢時能利用這個結構。具體而言,連接兩個在(包含連接列的)相同列上划分了桶的表,可以使用 Map 端連接 (Map-side join)高效的實現。比如JOIN操作。對於JOIN操作兩個表有一個相同的列,如果對這兩個表都進行了桶操作。那么將保存相同列值的桶進行JOIN操作就可以,可以大大較少JOIN的數據量。
(2)使取樣(sampling)更高效。在處理大規模數據集時,在開發和修改查詢的階段,如果能在數據集的一小部分數據上試運行查詢,會帶來很多方便。
數據塊抽樣
hive> select * from tmg tablesample(50 percent) s;
3個數據選出了2個
分桶的輸入裁剪
select * from numbersflat where number % 2=0;
大多數表是這樣的,但是如果tablesample語句指定的列和clustered by 語句中指定的列相同,那么tablesample查詢就只會掃描涉及到的表的hash分區數據
create table number_bucketed(number int) clustered by(number) into 3 buckets;
set hive.enforce.bucketing=true;
insert overwrite table number_bucketed select number form numbers;
會有三個數據桶,下面語句查詢可以高效地僅僅對其中一個數據桶進行抽樣。
hive>select * from number_bucketed tablesample(bucket 2 out of 3 on number) s;
union all
可以將2個或多個表進行合並,每個union子查詢都必須有相同的列,而且對應的每個字段的類型必須一致。例如,如果第二個字段是float類型,難么其他子查詢的第二個字段必須是float類型。
select log.ymd,log.level,log.message
from(
select l1.ymd.l1.level,l1.message,'Log1' as source
from log1 l1
union all
select l2.ymd.l2.level,l2.message,'Log2' as source
from log2 l2
)log
sort by log.ymd asc;
union也可以對同一個源表的數據合並。便於將長的復雜where語句分割成2個或多個union子查詢,不過除非源表建立了索引,否則,這個查詢將會對同一份源數據進行多次的拷貝分發。
hive> select * from(
> select * from tmg where age<19
> union all
> select * from tmg where age>19) mg;
from(
from src select src.key,src.value where src.key<100
union all
from src select src.* where src.key>110
)unioninput
insert overwrite directory '/tmp/union.out' select unioninput.*;
視圖
使用視圖來降低查詢復雜度,類似編程語言中使用的函數或者軟件設計中的分層設計概念。
如下具有嵌套子查詢的查詢
from(
select * from people join cart
on(cart.people_id = people.id) where firstname='join'
)a select a.lastname where a.id=3;
因此可以創建一個視圖
create view shorter_join as
select * from people join cart
on(cart.people_id = people.id) where firstname='join';
select lastname from shorter_join where id=3;
動態分區視圖和map
create external table dynamictable(cols map<string,string>)
row format delimited
fields terminated by '\004'
collection items terminated by '\001'
map keys terminated by '\002'
stored as textfile;
視圖1
create view orders(state, city, part) as
select cols["state"], cols["city"], cols["part"]
from dynamictable
where cols["type"]="request";
視圖2
create view shipments(time, part) as
select cols["time"], cols["part"]
from dynamictable
where cols["type"]="request";
實際在優化方面,查詢語句和視圖語句可能會合並成一條單一的實際查詢語句,但是這個概念視圖仍然適用於視圖和使用這個視圖的查詢語言都包含一個order by 或者一個limit字句的情況。
例如視圖語句中有limit 100,用到視圖的查詢語句包含limit 200,則實際結果有100條記錄。
如果 視圖用到的列不存在,則失敗。
create view if not exist shipments(time, part)
comment 'sfasdfsadfasdf'
tabproperties('creator'='me')
as
select cols["time"], cols["part"]
from dynamictable
where cols["type"]="request";
create table shipments2 like shipments; --復制視圖
也可以加external 和location字句
刪除視圖 drop view if exists shipments;
查看視圖 show tables; 沒有show views
describe describe extended 來查看視圖信息, table type會顯示'virtual_view'
視圖只能修改元數據中的tblproperties屬性
alter view shipments set tblproperties('create_at'='some_timestamp');
模式設計
按天划分的表
應該分區,按天
partitioned by(day int);
alter table supply add partition(day=20110102);
但是在分區上,hdfs所能管理的文件總數有上限。但是MapR和Amazon S3文件系統沒有限制。
MapReduce會將一個任務(job)轉換為多個任務(task),默認情況下每個task都是一個新的jvm實例,都需要開啟和銷毀。對於小文件,每個文件都會對應於一個task。在一些情況jvm開啟和銷毀中銷毀可能會比實際處理數據的時間銷號要長。
所以,實際中應該是的每個目錄下的文件足夠大,應該是文件系統中塊大小的若干倍。
可以找合適的時間粒度或者二級分區比如 再按照州來分區
可以考慮分桶表數據存儲。
唯一鍵和標准化
Hive沒有主鍵或者給予序列自增鍵的概念。盡量避免非標准化的數據進行join操作。
非標准化的數據允許被掃描或者寫到大的、連續的磁盤存儲區域,從而優化磁盤驅動器的I/O性能,然而,非標准化數據可能導致數據重復,而且有更大的導致數據不一致的風險。
create table employees(
name string,
salary float,
subordinates array<string>, --下屬
deductions map<string,float>, --扣薪紀錄
address struct<street:sting,city:sting,state:string,zip:int>); --地址
這個例子數據模型從很多方面打破了傳統的設計原則。
首先,我們非正式的使用了name作為主鍵,但是name往往是不唯一的。一個關系模型中如果使用name作為主鍵,那么從一個員工記錄到經理記錄應該有唯一的一個外鍵關系。這里我們用另一種方式來表達這個關系,在subordinates數組中保存了該員工所有下屬的名字。
其次,每名員工來說,各項稅收扣除都是不同的,但是map的鍵都是一樣的,員工表和稅收扣除項之間是一對多的關系。
最后,有些雇員可能住在同一個地址,每個員工都有一個住址,而不是單獨一個住址表。
同一份數據多種處理
如下兩個操作
insert overwrite table sales
select * from history where action='purchased';
insert overwrite table credits
select * from history where action='returned';
如下改造可以掃描一次history表
from history
insert overwrite sales select * from history where action='purchased'
insert overwrite table credits select * where action='returned';
對於每個表的分區
中間表可以防止出錯重跑
hive –hiveconf dt=2011-01-01
insert overwrite table distinct_ip_in_logs
select distinct(ip) as ip from weblogs
where hit_date='${hiveconf:dt}';
create table state_city_for_day (state string,city string);
insert overwrite state_city_for_day
select distinct(state,city) from distinct_ip_in_logs
join geodata on (distinct_ip_in_logs.ip=geodata.ip);
這種方法是有效的,不過當計算某一天的數據時會導致前一天的數據被insert overwrite覆蓋掉。而且如果同時運行這兩個實例,用於處理不同日期的數據會相互影響到對方的數據。
一個更具魯棒性的方法是在整個過程中使用分區。這樣就不會存在同步問題,同時還能帶來一個好處,就是可以允許用戶對中間數據按日期進行比較。
hive –hiveconf dt=2011-01-01
insert overwrite table distinct_ip_in_logs
partition(hit_date=${dt})
select distinct(ip) as ip from weblogs
where hit_date='${hiveconf:dt}';
create table state_city_for_day (state string, city string)
partitioned by(hit_date string);
insert overwrite state_city_for_day partition(${hiveconf:dt})
select distinct(state, city) from distinct_ip_in_logs
join geodata on (distinct_ip_in_logs.ip=geodata.ip)
where (hit_date='${hiveconf:dt}');
這種做法有一個缺點,用戶需要管理中間表並刪除舊分區,不過也很容易實現自動化。
分桶表數據存儲
分區提供了一個格力數據和優化查詢的便利的方式。但是,並非所有的數據集都可以形成合理的分區,況且還有要划分合適大小的問題存在。
分桶是將數據集分解成更容易管理的若干部分的另一個技術。
例如,假設有個表的一級分區是dt,代表日期,二級分區是user_id,那么這種方式會形成太多的小分區。如果用戶使用動態分區來創建這些分區的話,那么默認情況下,hive會限制動態分區可以創建的最大分區數,用來避免創建太多的分區導致超過了分布式文件系統的處理能力。所以有user_id來分區語句可能失敗。
不過我們對weblog進行分桶,並使用user_id字段作為分桶字段,則字段值會根據用戶指定的值進行哈希分發到桶中,同一個user_id下的記錄會存儲到同一個桶內。假設用戶數比桶數多得多,那么每個桶內就會有多個用戶記錄。
create table weblog(user_id int,url string,source_ip string)
partitioned by(dt string)
clustered by (user_id) into 96 buckets;
set hive.enforce.bucketing=true; 強制hive為目標表的分桶初始化過程設置一個正確的reducer數量
from raw_logs
insert overwrite table weblog
patition(dt='2009-02-21')
select user_id,url,souce_ip where dt=' 2009-02-21';
如果我們沒有設置hive.enforce.bucketing屬性,就需要自己設置與分桶個數相適應的reducer個數,例如set mapred.reduce.tasks=96,然后在insert 語句中需要在select后增加cluster by語句。
分桶同時有利於高效的map-side join。
為表增加列
create table weblogs(version long, url string)
partitioned by(hit_date int)
row format delimited
fields terminated by '\t';
load data local inpath 'log1.txt' into weblogs partition(20110101);
select * from weblogs;
1 /toys 20110101
alter table weblogs add culumns(user id string);
load data local inpath 'log2.txt' into weblogs partition(20110102);
1 /mystuff 20110101 NULL
1 /toys 20110101 NULL
1 /cars 20110101 bob
1 /stuff 20110101 terry
這種方式無法在已有的字段的開始或者中間增加新字段
使用列存儲表
Hive通常使用行式存儲,不過也提供了一個列式SerDe來混合列式存儲信息。
重復數據
假設有足夠多的行,像state字段和age字段這樣的列將會有很多重復的數據。這樣的數據如果使用列式存儲會非常好。
多列
如果一個表有非常多的字段。查詢通常會使用到一個字段或者很少的一組字段,列式存儲會使分析表數據執行更快。
調優
使用explain
hive (hdata)> select sum(age) from tmg;
hive (hdata)> explain select sum(age) from tmg;
Explain
STAGE DEPENDENCIES:
Stage-1 is a root stage --stage-1包含了這個job的大部分處理過程,而且會觸發一個MapReducejob
Stage-0 depends on stages: Stage-1
TablesScan以這個表為輸入,然后會產生一個只有字段number的輸出。
Group By Operator會應用到sum(number),然后會產生一個輸出字段_col0(臨時結果按照規則起的字段名)。這些都是發生在job的map過程。
STAGE PLANS:
Stage: Stage-1
Map Reduce
Map Operator Tree:
TableScan
alias: tmg
Statistics: Num rows: 8 Data size: 35 Basic stats: COMPLETE Column stats: NONE
Select Operator
expressions: age (type: int)
outputColumnNames: age
Statistics: Num rows: 8 Data size: 35 Basic stats: COMPLETE Column stats: NONE
Group By Operator
aggregations: sum(age)
mode: hash
outputColumnNames: _col0
Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONE
Reduce Output Operator
sort order:
Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONE
value expressions: _col0 (type: bigint)
Reduce Operator Tree:
Group By Operator
aggregations: sum(VALUE._col0)
mode: mergepartial
outputColumnNames: _col0
Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONE
File Output Operator
compressed: false
Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONE
table:
input format: org.apache.hadoop.mapred.SequenceFileInputFormat
output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
Stage: Stage-0
Fetch Operator
limit: -1 --這個job沒有limit語句
Processor Tree:
ListSink
使用explain extended
會多出一些文件路徑
限制調整
Limit語句是需要執行整個查詢語句,然后返回結果的,比較浪費,hive有一個屬性可以開啟,當使用limit時可以對源數據進行抽樣。
Hive.limit.optimize.enable的值為true,那么還會有兩個參數可以控制這個操作,hive.limit.row.max.size 和hive.limit.optimize.limit.file 可以設數值
但是這個有個問題是,可能輸入的有用的數據永遠不可能被處理到。重要的是理解。
Join優化
map-side join 優化
一個表足夠小,完全載入內存,hive可以執行一個map-side join, 減少reduce過程,有時可以減少某些map task任務。
本地模式
有時hive的輸入數據量很小,大多數情況下,hive可以通過本地模式在單台計算機上處理所有任務。
set oldjobtracker=${hiveconf:mapred.job.tracker};
set mapred.job.tracker=local;
set mapred.tmp.dir=/home/edward/tmp;
select * from people where firstname=bob;
...
Set mapred.job.tracker=${ oldjobtracker };
用戶可以設置hive.exec.mode.local.auto=true 來讓hive在適當的時候自動啟動這個優化。用戶也可以永久寫在$HOME/.hiverc中
見P141
並行執行
Hive會將一個查詢轉化成一個或多個階段,可以使MapReduce階段、抽樣階段、合並階段、limit階段或者其他階段。默認情況下,hive一次只執行一個階段,但是有些階段可能並非完全相互依賴,可以並行。
嚴格模式
hive.mapred.mode=strict 可以禁止3中類型的查詢
-
分區表,除非where有分區字段過濾條件,否則不允許執行
-
對於使用了order by語句的限制,必須使用limit語句。排序過程將所有數據的結果發到同一個reducer中進行處理,強制limit可以防止reducer額外執行很長時間。
-
限制笛卡爾積的查詢。必須有on。
調整mapper和reducer的個數
確定最佳的mapper和reducer個數,並行性。
Hive是按照輸入的數據量大小來確定reducer個數的。我們可以通過dfs –count來計算輸入量大小,類似Linux的du –s命令,可以計算指定目錄下所有數據的總大小。
$hadoop dfs –count /user/media6/fracture/ins/* | tail -4
Hive.exec.reducers.bytes.per.reducer 默認值為1GB,如果調整為750MB,reducer數目就會增多為4個。
Hive默認reducer個數為3,通過設置屬性 mapred.reduce.tasks 不同來確定reducer數量對時間的影響。
當在共享集群中處理大任務時,控制資源利用情況,hive.exec.reducers.max 非常重要,一個hadoop集群可以提供的map和reducer資源個數稱為插槽是固定的。通過hive.exec.reducers.max屬性設置可以阻止某個查詢消耗過多的reducer資源,可以配置到$HIVE_HOME/conf/hive-site.xml
(集群總Reduce插槽個數*1.5)/(執行中的查詢平均個數)
