Hive學習筆記總結java
Ps:hive的元數據並不存放在hdfs上,而是存儲在數據庫中(metastore),目前只支持 mysql、derby。Hive 中的元數據包括表的名字,表的列和分區及其屬性,表的屬性(是否爲外部表等),表的數據所在目錄等。python
元數據就是描述數據的數據,而Hive的數據存儲在Hadoop HDFS
數據仍是原來的文本數據,可是如今有了個目錄規劃。mysql
Hive利用HDFS存儲數據,利用MapReduce查詢數據。linux
Hive只是一個工具,不須要集羣配置。算法
export HIVE_HOME=/usr/local/hive-2.0.1
export PATH=\(PATH:\)HIVE_HOME/bin
配置MySql,若是不進行配置,默認使用derby數據庫,可是很差用,在哪一個地方執行./hive命令,哪兒就會建立一個metastore_db
MySQL安裝到其中某一個節點上便可。sql
能夠安裝在某一個節點,併發布成標準服務,在其餘節點使用beeline方法。數據庫
啓動方式,(假如是在master上):
啓動爲前臺服務:bin/hiveserver2
啓動爲後臺:nohup bin/hiveserver2 1>/var/log/hiveserver.log 2>/var/log/hiveserver.err &json
鏈接方法:
hive/bin/beeline 回車,進入beeline的命令界面
輸入命令鏈接hiveserver2
beeline> !connect jdbc:hive2://master:10000
beeline> !connect jdbc:hive2://localhost:10000
(master是hiveserver2所啓動的那臺主機名,端口默認是10000)服務器
hive > create database tabletest;架構
語法:
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name [(col_name data_type [COMMENT col_comment], ...)] [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] [ROW FORMAT row_format] [STORED AS file_format] [LOCATION hdfs_path]
示例:
create table t_order(id int,name string,rongliang string,price double) row format delimited fields terminated by '\t';
建立了一個t_order表,對應在Mysql的元數據中TBLS表會增長表的信息,和列的信息,以下:
同時,會在HDFS的中的tabletest.db文件夾中增長一個t_order文件夾。全部的 Table 數據(不包括 External Table)都保存在這個目錄中。
能夠直接使用HDFS上傳文件到t_order文件夾中,或者使用Hive的load命令。
load data local inpath '/home/hadoop/ip.txt' [OVERWRITE] into table tab_ext;
做用和上傳本地linux文件到HDFS系統同樣;但須要注意,若是inpath 後面路徑是HDFS路徑,則將是將其刪除後,剪切到目標文件夾,很差!
EXTERNAL關鍵字可讓用戶建立一個外部表,在建表的同時指定一個指向實際數據的路徑(LOCATION),Hive 建立內部表時,會將數據移動到數據倉庫指向的路徑;若建立外部表,僅記錄數據所在的路徑,不對數據的位置作任何改變。
爲了不源文件丟失的問題,能夠創建external表,數據源能夠在任意位置。
CREATE EXTERNAL TABLE tab_ip_ext(id int, name string, ip STRING, country STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' STORED AS TEXTFILE LOCATION '/external/hive';
在建立表的時候,就指定了HDFS文件路徑,所以,源文件上傳到/external/hive/文件夾便可。
外部表刪除時,只刪除元數據信息,存儲在HDFS中的數據沒有被刪除。
做用:若是文件很大,用分區表能夠快過濾出按分區字段劃分的數據。
t_order中有兩個分區part1和part2.
實際就是在HDFS中的t_order文件夾下面再創建兩個文件夾,每一個文件名就是part1和part2。
create table t_order(id int,name string,rongliang string,price double) partitioned by (part_flag string) row format delimited fields terminated by '\t';
插入數據:
load data local inpath '/home/hadoop/ip.txt' overwrite into table t_order partition(part_flag='part1');
就會把ip.txt文件上傳到/t_order/part_flag='part1'/文件夾中。
查看分區表中的數據:
select * from t_order where part_flag='part1';
查詢時,分區字段也會顯示,可是實際表中是沒有這個字段的,是僞字段。
hive中的分區 就是再多建一個目錄, 優勢:便於統計,效率更高,縮小數據集。
相關命令:
Hive裏的分桶=MapReduce中的分區,而Hive中的分區只是將數據分到了不一樣的文件夾。
create table stu_buck(Sno int,Sname string,Sex string,Sage int,Sdept string) clustered by(Sno) sorted by(Sno DESC) into 4 buckets row format delimited fields terminated by ',';
含義:根據Sno字段分桶,每一個桶按照Sno字段局部有序,4個桶。建桶的時候不會的數據作處理,只是要求插入的數據是被分好桶的。
通常不適用load數據進入分桶表,由於load進入的數據不會自動按照分桶規則分爲四個小文件。因此,通常使用select查詢向分桶表插入文件。
設置變量,設置分桶爲true, 設置reduce數量是分桶的數量個數
set hive.enforce.bucketing = true; set mapreduce.job.reduces=4; insert overwrite table student_buck select * from student cluster by(Sno); insert overwrite table stu_buck select * from student distribute by(Sno) sort by(Sno asc);
其中,能夠用distribute by(sno) sort by(sno asc)替代cluster by(Sno),這是等價的。cluster by(Sno) = 分桶+排序
先分發,再局部排序。區別是distribute更加靈活,能夠根據一個字段分區,另外字段排序。
第二個子查詢的輸出了4個文件做爲主查詢的輸入。
原理:
Hive是針對某一列進行桶的組織。Hive採用對列值哈希,而後除以桶的個數求餘的方式決定該條記錄存放在哪一個桶當中。(原理和MapReduce的getPartition方法相同)
做用:
(1) 最大的做用是用來提升join操做的效率;
前提是兩個都是分桶表且分桶數量相同或者倍數關係?
思考這個問題:
select a.id,a.name,b.addr from a join b on a.id = b.id;
若是a表和b表已是分桶表,並且分桶的字段是id字段
作這個join操做時,還須要全表作笛卡爾積嗎?
對於JOIN操做兩個表有一個相同的列,若是對這兩個表都進行了桶操做。那麼將保存相同列值的桶進行JOIN操做就能夠,能夠大大較少JOIN的數據量。
(2)取樣(sampling)更高效。在處理大規模數據集時,在開發和修改查詢的階段,若是能在數據集的一小部分數據上試運行查詢,會帶來不少方便。
Hive一條一條的insert太慢。
可是能夠批量的insert.實際就是想文件夾中追加文件。
create table tab_ip_like like tab_ip; insert overwrite table tab_ip_like select * from tab_ip;
向tab_ip_like中追加文件
一、將查詢結果保存到一張新的hive表中
create table t_tmp
as
select * from t_p;
二、將查詢結果保存到一張已經存在的hive表中
insert into table t_tmp
select * from t_p;
三、將查詢結果保存到指定的文件目錄(能夠是本地,也能夠是HDFS)
insert overwrite local directory '/home/hadoop/test'
select * from t_p;
插入HDFS
insert overwrite directory '/aaa/test'
select * from t_p;
語法:
SELECT [ALL | DISTINCT] select_expr, select_expr, ... FROM table_reference [WHERE where_condition] [GROUP BY col_list [HAVING condition]] [CLUSTER BY col_list | [DISTRIBUTE BY col_list] [SORT BY| ORDER BY col_list] ] [LIMIT number]
注:
所以,若是分桶和sort字段是同一個時,此時,cluster by = distribute by + sort by
select * from inner_table select count(*) from inner_table
刪除表時,元數據與數據都會被刪除
drop table inner_table
LEFT JOIN,RIGHT JOIN, FULL OUTER JOIN ,inner join, left semi join
準備數據
1,a
2,b
3,c
4,d
7,y
8,u
2,bb
3,cc
7,yy
9,pp
建表:
create table a(id int,name string) row format delimited fields terminated by ','; create table b(id int,name string) row format delimited fields terminated by ',';
導入數據:
load data local inpath '/home/hadoop/a.txt' into table a; load data local inpath '/home/hadoop/b.txt' into table b;
select * from a inner join b on a.id=b.id;
+-------+---------+-------+---------+--+
| a.id | a.name | b.id | b.name |
+-------+---------+-------+---------+--+
| 2 | b | 2 | bb |
| 3 | c | 3 | cc |
| 7 | y | 7 | yy |
+-------+---------+-------+---------+--+
就是求交集。
select * from a left join b on a.id=b.id;
+-------+---------+-------+---------+--+
| a.id | a.name | b.id | b.name |
+-------+---------+-------+---------+--+
| 1 | a | NULL | NULL |
| 2 | b | 2 | bb |
| 3 | c | 3 | cc |
| 4 | d | NULL | NULL |
| 7 | y | 7 | yy |
| 8 | u | NULL | NULL |
+-------+---------+-------+---------+--+
左邊沒有找到鏈接的置空。
select * from a right join b on a.id=b.id;
select * from a full outer join b on a.id=b.id;
+-------+---------+-------+---------+--+
| a.id | a.name | b.id | b.name |
+-------+---------+-------+---------+--+
| 1 | a | NULL | NULL |
| 2 | b | 2 | bb |
| 3 | c | 3 | cc |
| 4 | d | NULL | NULL |
| 7 | y | 7 | yy |
| 8 | u | NULL | NULL |
| NULL | NULL | 9 | pp |
+-------+---------+-------+---------+--+
兩邊數據都顯示。
select * from a left semi join b on a.id = b.id;
+-------+---------+--+
| a.id | a.name |
+-------+---------+--+
| 2 | b |
| 3 | c |
| 7 | y |
+-------+---------+--+
只返回左邊一半,即a的東西,效率高一點。
能夠存儲中間結果。
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;
當Hive提供的內置函數沒法知足你的業務處理須要時,此時就能夠考慮使用用戶自定義函數(UDF:user-defined function)。
UDF 做用於單個數據行,產生一個數據行做爲輸出。(數學函數,字符串函數)
UDAF(用戶定義彙集函數):接收多個輸入數據行,併產生一個輸出數據行。(count,max)
一、先開發一個java類,繼承UDF,並重載evaluate方法
public class ToLowerCase extends UDF { // 必須是public public String evaluate(String field) { String result = field.toLowerCase(); return result; } }
二、打成jar包上傳到服務器
三、將jar包添加到hive的classpath
hive>add JAR /home/hadoop/udf.jar;
四、建立臨時函數與開發好的java class關聯
Hive>create temporary function tolowercase as 'cn.itcast.bigdata.udf.ToProvince';
五、便可在hql中使用自定義的函數strip
select id,tolowercase(name) from t_p;
Hive的 TRANSFORM 關鍵字提供了在SQL中調用自寫腳本的功能
適合實現Hive中沒有的功能又不想寫UDF的狀況。
一、先加載rating.json文件到hive的一個原始表 rat_json
//{"movie":"1721","rate":"3","timeStamp":"965440048","uid":"5114"} create table rat_json(line string) row format delimited; load data local inpath '/opt/rating.json' into table rat_json
二、須要解析json數據成四個字段,插入一張新的表 t_rating(用於存放處理的數據,須要有四個字段)
create table t_rating(movieid string,rate int,timestring string,uid string) row format delimited fields terminated by '\t'; insert overwrite table t_rating select get_json_object(line,'$.movie') as moive,get_json_object(line,'$.rate') as rate from rat_json; //get_json_object是內置jason函數,也能夠自定義UDF函數實現
三、使用transform+python的方式去轉換unixtime爲weekday
(1)先編輯一個python腳本文件
python代碼:
vi weekday_mapper.py #!/bin/python import sys import datetime for line in sys.stdin: line = line.strip() movieid, rating, unixtime,userid = line.split('\t') weekday = datetime.datetime.fromtimestamp(float(unixtime)).isoweekday() print '\t'.join([movieid, rating, str(weekday),userid])
(2)將文件加入hive的classpath:
hive>add FILE /home/hadoop/weekday_mapper.py; hive>create TABLE u_data_new as SELECT TRANSFORM (movieid, rate, timestring,uid) USING 'python weekday_mapper.py' AS (movieid, rate, weekday,uid) FROM t_rating; select distinct(weekday) from u_data_new limit 10;
將查詢處理過的新數據插入u_data_new文件中。
初接觸,記下學習筆記,還有不少問題,望指導,謝謝。