1. 程式人生 > >004-hive基本操作

004-hive基本操作

文章目錄

hive 基本操作

1、資料庫的基本操作

1)預設的資料庫是 default
2)建立資料庫:create database hivedb comment 'I am hive database';
	完整格式:
		create database|schema
		[if not exists] database_name
		[comment database_comment]
		[location hdfs_path]
		[with dbproperties (property_name=property_value, ...)]; 設定一些屬性
		
		建立資料庫使用 database 或 schema 都可以;
		if not exists:判斷資料庫是否存在;
		comment:資料庫註釋;
		location hdfs_path:指定資料庫在 hdfs 上的目錄,預設/user/hive/warehouse/database_name;
		with dbproperties (property_name=property_value, ...):設定一些屬性
	例:create database hivetestdb;
		# 建立資料庫,Hive會在/user/hive/warehouse/下建立一個以database_name.db命名的目錄(如:/user/hive/warehouse/hivetestdb.db)
3)檢視所有資料庫:show databases;
4)檢視指定資料庫:desc database database_name;
5)檢視指定資料庫詳細資訊:desc database extended database_name;
6)檢視當前資料庫:select current_database();
7)切換資料庫:use database_name;
8)刪除空資料庫:drop database database_name;
   級聯刪除資料庫(包括表):drop database database_name cascade;
   刪除資料庫完善格式:drop database if exists database_name cascade;

2、表的操作

操作 hive 表時,最好在前面加上資料庫名
1)建立表:create database auser(id int comment 'I am id',name varchar(30));
   建立表時指定分隔符:create database auser(id int comment 'I am id',name varchar(30)) [row format delimited fields terminated by '\t'];
   建立帶分割槽的表:CREATE TABLE tab01 (id int,name string) PARTITIONED BY (ds string);
	不指定 database 時,預設建立在 default 資料庫中;
	說明:在 hivetestdb 中建立表 auth_user,hive 會在 /user/hive/warehouse/hivetestdb.db 下建立 auth_user 目錄。
2)查看錶資料:select * from table_name;
3)檢視當前庫所有表:show tables;
4)檢視建表語句:show create table table_name;
5)檢視一個表的分割槽:show partition table_name;
	如果這個表不存在分割槽則會報錯
6)查看錶結構(包括註釋):describe table_name 或 desc table_name 或 desc formatted table_name;
	例:
	describe extended utab2;

	輸出:
	Table(
		tableName : utab2,
		dbName : default,
		owner : root,
		createTime : 1537504392,
		lastAccessTime : 0,
		retention : 0,
		sd : StorageDescriptor(
			cols : [
				FieldSchema(name : id,type : int,comment : null),
				FieldSchema(name : uname,type : string,comment : null),
				FieldSchema(name : age,type : int,comment : null)
			],
			location : hdfs://localhost:9000/user/hive/warehouse/utab2,
			inputFormat : org.apache.hadoop.mapred.TextInputFormat,
			outputFormat : org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat,
			compressed : false,
			numBuckets : -1,
			serdeInfo : SerDeInfo(name : null,
			serializationLib : org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe,
			parameters : {serialization.format=1}),
			bucketCols : [],
			sortCols : [],
			parameters : {},
			skewedInfo : SkewedInfo(skewedColNames : [],
			skewedColValues : [],
			skewedColValueLocationMaps : {}),
			storedAsSubDirectories : false
		),
		partitionKeys : [],
		parameters : 
			{
				totalSize=8,
				numRows=1,
				rawDataSize=7,
				COLUMN_STATS_ACCURATE={\"BASIC_STATS\" : \"true\",\"COLUMN_STATS\" : {\"age\" : \"true\",\"id\" : \"true\",\"uname\" : \"true\"}},
				numFiles=1,
				transient_lastDdlTime=1537505000,
				bucketing_version=2
			},
		viewOriginalText : null,
		viewExpandedText : null,
		tableType : MANAGED_TABLE,
		rewriteEnabled : false,
		catName : hive,
		ownerType : USER
	)
7)查看錶詳細資訊:describe extended table_name;
8)修改表
	a. 修改表名:alter table table_name rename to new_table_name;
	b. 修改 location:alter table table_name set location 'hdfs://nameservice1/data/test';
	c. 修改表屬性(如編碼):alter table table_name set serdeproperties('serialization.encoding'='GBK');
	d. 新增列:alter table table_name add columns (age int comment 'this is age');
	e. 使用新欄位覆蓋表原所有欄位:alter table table_name replace columns (age string comment 'only keep the column');
9)刪除和清空表
	a. 刪除表:drop table [if exists] table_name;
	b. 清空表:truncate table table_name;
		注意:
			》truncate table student; 只能對管理表使用,不能對外部表使用
			》truncate 命令操作時表名前不能加上database_name
			》外部表 drop 之後,資料表在hdfs上目錄的資料檔案依然存在,實際是隻刪除了儲存在關係型資料庫中的元資料
			》管理表 truncate 之後,資料表location 所在目錄的資料檔案刪除,目錄依然存在。
			  管理表 drop 之後,資料表location 所在目錄刪除。刪除了元資料和資料檔案,資料目錄。
10)插入資料
	a. 單表插入
		insert overwrite table tab09 select a.* from tab03 a;
		insert overwrite table tab09 select 7,'cat';
		insert into table auth_user values (4,'kitty');
		說明:
			overwrite 是覆蓋,into 是追加。
	b. 多表插入(Multi Table/File Inserts)
		FROM src
		  INSERT OVERWRITE TABLE dest1 SELECT src.* WHERE src.key < 100
		  INSERT OVERWRITE TABLE dest2 SELECT src.key, src.value WHERE src.key >= 100 and src.key < 200
		  INSERT OVERWRITE TABLE dest3 PARTITION(ds='2008-04-08', hr='12') SELECT src.key WHERE src.key >= 200 and src.key < 300
		  INSERT OVERWRITE LOCAL DIRECTORY '/tmp/dest4.out' SELECT src.value WHERE src.key >= 300;
			
		FROM pv_users
			INSERT OVERWRITE TABLE pv_gender_sum SELECT pv_users.gender, count_distinct(pv_users.userid) GROUP BY pv_users.gender
			INSERT OVERWRITE DIRECTORY '/user/data/tmp/pv_age_sum' SELECT pv_users.age, count_distinct(pv_users.userid) GROUP BY pv_users.age;	
			
		【Dynamic-Partition Insert -- version 0.6.0 後增加的新特徵】
		FROM page_view_stg pvs
		INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='US')
			   SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'US'
		INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='CA')
			   SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'CA'
		INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='UK')
			   SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'UK';
		上面這個語句,是一個非常不好的示例,因為我們預先需要知道所有的 country,並且 dt 如果變了,那麼我們需要重新增加新的 insert 語句。例如,當還有另外一個 country='DC' 或者 dt = '2008-09-10'
		Dynamic-partition insert 是為了解決上述問題而被設計的。所以 Dynamic-partition insert 如下即可
		FROM page_view_stg pvs
		INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country)
			   SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip, pvs.country

		說明:
			上述示例語句中,dt 是一個靜態分割槽列(因為它的值一直都是2008-06-08,沒有任何變化),country 是動態分割槽列。
			動態分割槽列的值來自輸入列。
			目前,只允許動態分割槽列作為分割槽子句中的最後一列(s),因為分割槽列順序表示它的層次順序,所以不能用(dt, country='US')來指定分割槽子句。
			select 語句中額外增加的 pvs.country 列,是動態分割槽列對應的輸入列。請注意,您不需要為靜態分割槽列新增一個輸入列,因為它的值已經在隔斷子句中知道了。
			注意,動態分割槽值是通過排序、而不是名稱來選擇的,並作為select子句的最後一列來選擇。(即動態分割槽列的值是來自 select 子句的最後一列,而不通過名字匹配的)
			
		動態分割槽插入語句的語義:
			當動態分割槽列已經存在非空分割槽時(例如,在某些ds根分割槽之下存在著country='CA'),如果動態分割槽插入在輸入資料中看到相同的值(比如'CA'),就會被覆蓋。
			因為 Hive 分割槽對應於HDFS中的一個目錄,所以分割槽值必須符合HDFS路徑格式。任何在URI中具有特殊含義的字元(例如,'%', ':', '/', '#')都將以'%'的形式轉義,後跟2位元組的ASCII值。
			如果輸入列是非字串的型別,那麼它的值將首先被轉換成字串,用於構造HDFS路徑。
			如果輸入列值為NULL或空字串,這一行將被放入一個特殊的分割槽中,該分割槽的名稱由hive引數hive.exec.default.default.name控制。預設值是HIVE_DEFAULT_PARTITION{}。基本上這個分割槽將包含所有的“壞”行,它們的值不是有效的分割槽名稱。這種方法的警告是,如果您選擇Hive,那麼它將丟失並被HIVE_DEFAULT_PARTITION{}所取代。JIRA hia-1309是一個解決方案,讓使用者指定“壞檔案”來保留輸入分割槽列值。
			動態分割槽插入可能是一個資源佔用者,因為它可以在短時間內生成大量的分割槽。為了讓自己分桶,我們定義了三個引數:
				hive.exec.max.dynamic.partitions.pernode:(預設值是1000)是每個mapper或reducer可以建立的最大動態分割槽數。如果一個mapper或reducer建立的比這個閾值更多,那麼將會從map/reducer(通過計數器)中產生一個致命的錯誤,整個job將被殺死。
				hive.exec.max.dynamic.partitions:(預設值是100)能夠被一個DML建立的動態分割槽的總數。如果每一個mapper/reducer都沒有超過限制,但是動態分割槽的總數是超過了,那麼在將中間資料移動到最終目的地之前,將會丟擲一個異常結束 job。
				hive.exec.max.created.files:(預設值是100000)是所有的mapper和reducer建立的最大的檔案總數。每一個mapper/reducer 建立一個新檔案時將執行 Hadoop counter 更新。如果總數超過了hive.exec.max.created.files,將丟擲一個致命的錯誤,job 將被殺死。
			我們想要保護不利於動態分割槽插入的另一種情況是,使用者可能意外地指定所有分割槽為動態分割槽,而不指定一個靜態分割槽,雖然最初的目的是想覆蓋一個根分割槽的子分割槽。我們可以定義另外一個引數 hive.exec.dynamic.partition.mode=strict 來保護這種全動態分割槽情況。在嚴格模式下,您必須指定至少一個靜態分割槽。預設模式是嚴格的。另外,我們可以用一個引數 hive.exec.dynamic.partition=true/false 來控制是否允許動態分割槽。在Hive 0.9.0之前預設值是false,在Hive 0.9.0和之後預設值是 true。 
			在Hive 0.6中,hive.merge.mapfiles=true or hive.merge.mapredfiles=true時動態分割槽插入不工作。所以它內部關閉了merge 引數。在Hive 0.7中 merging file 是支援動態分割槽插入的(詳見JIRA hi1307)。

3、表的其他操作

1)group by
	CREATE TABLE tab10 (name string) row format delimited fields terminated by '\t';
	a. select 語句為常規 sql
		INSERT OVERWRITE TABLE tab10 SELECT a.name FROM tab09 a GROUP BY a.name;
	b. from 寫到了 select 的前面
		FROM tab09 a INSERT OVERWRITE TABLE tab10 SELECT a.name GROUP BY a.name;

2)Aggregations
	INSERT OVERWRITE TABLE pv_gender_sum SELECT pv_users.gender, count(DISTINCT pv_users.userid) FROM pv_users GROUP BY pv_users.gender;
	INSERT OVERWRITE TABLE pv_gender_agg SELECT pv_users.gender, count(DISTINCT pv_users.userid), count(*), sum(DISTINCT pv_users.userid) FROM pv_users GROUP BY pv_users.gender;

3)joins
	a. join
		FROM tab001 t1 JOIN tab002 t2 ON (t1.bar = t2.bar) INSERT OVERWRITE TABLE tab003 SELECT t1.bar, t1.foo, t2.foo;
		INSERT OVERWRITE TABLE pv_users SELECT pv.*, u.gender, u.age FROM user u JOIN page_view pv ON (pv.userid = u.id) WHERE pv.date = '2008-03-03';
	b. LEFT OUTER, RIGHT OUTER or FULL OUTER,外部連線
		INSERT OVERWRITE TABLE pv_users SELECT pv.*, u.gender, u.age FROM user u FULL OUTER JOIN page_view pv ON (pv.userid = u.id) WHERE pv.date = '2008-03-03';
	c. LEFT SEMI JOIN,為了檢查另一張表中的鍵的存在,使用者可以使用左半連線,如下面的例子所示
		INSERT OVERWRITE TABLE pv_users SELECT u.* FROM user u LEFT SEMI JOIN page_view pv ON (pv.userid = u.id) WHERE pv.date = '2008-03-03';
	d. 多表連線
		INSERT OVERWRITE TABLE pv_friends SELECT pv.*, u.gender, u.age, f.friends FROM page_view pv JOIN user u ON (pv.userid = u.id) JOIN friend_list f ON (u.id = f.uid) WHERE pv.date = '2008-03-03';

4)Sampling -- 抽樣
	從pv_gender_sum的32個桶中選擇第三個桶
	INSERT OVERWRITE TABLE pv_gender_sum_sample SELECT pv_gender_sum.* FROM pv_gender_sum TABLESAMPLE(BUCKET 3 OUT OF 32);

5)Union All
	INSERT OVERWRITE TABLE actions_users
	SELECT u.id, actions.date
	FROM (
		SELECT av.uid AS uid
		FROM action_video av
		WHERE av.date = '2008-06-03'
	 
		UNION ALL
	 
		SELECT ac.uid AS uid
		FROM action_comment ac
		WHERE ac.date = '2008-06-03'
		) actions JOIN users u ON(u.id = actions.uid);

6)Custom Map/Reduce Scripts -- 自定義 Map/Reduce 指令碼
	https://cwiki.apache.org/confluence/display/Hive/Tutorial#Tutorial-BuiltInOperatorsandFunctions
	FROM (
		 FROM pv_users
		 MAP pv_users.userid, pv_users.date
		 USING 'map_script'
		 AS dt, uid
		 CLUSTER BY dt) map_output
	 
	 INSERT OVERWRITE TABLE pv_users_reduced
		 REDUCE map_output.dt, map_output.uid
		 USING 'reduce_script'
		 AS date, count;

7)streaming
	FROM invites a INSERT OVERWRITE TABLE events SELECT TRANSFORM(a.foo, a.bar) AS (oof, rab) USING '/bin/cat' WHERE a.ds > '2008-08-09';

4、hive匯入資料

1)table --> table
	a. 匯入其他表資料
		insert overwrite|into table table_name select * from table_name2;
	b. 建立表時匯入其他表資料
		create table table_name as select * from table_name2;
	c. 建立表時指定 location,並匯入其他表資料
		注意:建立表指定 location 匯入資料時必須是不存在的目錄,不然建立表會失敗。可以先建立表,再刪除相應的目錄,再將資料上傳到對應的目錄。表就可以直接加載出資料。

2)file --> table 將檔案內容匯入到表中(表所有目錄)
	load data [local] inpath '/tmp/students.txt' [overwrite] into table table_name [partition(part1='value1',part2='value2',...)]; 
		示例1:
			load data local inpath '/tmp/students.txt' overwrite into table tab03;
		說明:
			local 表示載入本地資料;不使用 local 時,表示載入 HDFS 上的資料。
			加上 overwrite 表示覆蓋,不加 overwrite 表示追加。
			inpath 是載入的資料的目錄,一般寫全路徑。可以指定到檔案,也可以直接指定目錄,指定目錄會載入目錄下所有檔案的資料。
			partition:向分割槽表中匯入資料。
		示例2:
			# local 用於指定本地檔案,如果缺省了,則會在 HDFS 中查詢檔案;OVERWRITE 表示覆蓋,如果預設則表示新增
			load data local inpath '/tmp/students.txt' overwrite into table tab03;
			
			# students.txt 內容為
				id	name
				1	'zhangsan'
				2	'lisi'
				3	wangwu
				
			# select * from tab03;
				NULL	name
				1	'zhangsan'
				2	'lisi'
				3	wangwu
			上面為 NULL 是因為第一列型別為 int

		示例3:
			CREATE TABLE tab07 (id int,name string) PARTITIONED BY (ds string) row format delimited fields terminated by '\t';
			load data local inpath '/tmp/students.txt' overwrite into table tab07 PARTITION (ds='2008-08-15');
			# students.txt
			1	'zhangsan'
			2	'lisi'
			3	wangwu
			4	tom
			5	cat
			6	kitty

			select * from tab07;
			1	'zhangsan'	2008-08-15
			2	'lisi'	2008-08-15
			3	wangwu	2008-08-15
			4	tom	2008-08-15
			5	cat	2008-08-15
			6	kitty	2008-08-15

5、hive 匯出資料

1)table --> file
	insert overwrite|into [local] directory '/temp/students.txt' [row format delimited fields terminated by '\t'] select * from table_name	
		示例:
			# 往 HDFS 裡寫資料
			insert overwrite directory '/tmp/students.txt' select * from tab07 t where t.ds = '2008-08-15';
			# 往本地檔案裡寫資料
			insert overwrite local directory '/tmp/students5' select a.* from tab03 a;
			insert overwrite local directory '/tmp/students6' select * from tab07 t where t.ds = '2008-08-15';

參考地址:
https://cwiki.apache.org/confluence/display/Hive/Tutorial
https://www.cnblogs.com/johnny-YJL/p/7940594.html