hive基礎命令和配置

第1章 Hive基本概念

1.1 什麼是Hive
Hive:由Facebook開源用於解決海量結構化日誌的數據統計。
Hive是基於Hadoop的一個數據倉庫工具,可以將結構化的數據文件映射爲一張表,並提供類SQL查詢功能。
本質是:將HQL轉化成MapReduce程序

1)Hive處理的數據存儲在HDFS
2)Hive分析數據底層的實現是MapReduce
3)執行程序運行在Yarn上

1.2 Hive的優缺點
1.2.1 優點

1)操作接口採用類SQL語法,提供快速開發的能力(簡單、容易上手)。
2)避免了去寫MapReduce,減少開發人員的學習成本。
3)Hive的執行延遲比較高,因此Hive常用於數據分析,對實時性要求不高的場合。
4)Hive優勢在於處理大數據,對於處理小數據沒有優勢,因爲Hive的執行延遲比較高。
5)Hive支持用戶自定義函數,用戶可以根據自己的需求來實現自己的函數。

1.2.2 缺點

1.Hive的HQL表達能力有限
(1)迭代式算法無法表達
(2)數據挖掘方面不擅長,由於MapReduce數據處理流程的限制,效率更高的算法卻無法實現。

2.Hive的效率比較低
(1)Hive自動生成的MapReduce作業,通常情況下不夠智能化
(2)Hive調優比較困難,粒度較粗

1.3 Hive架構原理
在這裏插入圖片描述

		圖6-1 Hive架構原理

1.用戶接口:Client
CLI(command-line interface)、JDBC/ODBC(jdbc訪問hive)、WEBUI(瀏覽器訪問hive)
2.元數據:Metastore
元數據包括:表名、表所屬的數據庫(默認是default)、表的擁有者、列/分區字段、表的類型(是否是外部表)、表的數據所在目錄等;
默認存儲在自帶的derby數據庫中,推薦使用MySQL存儲Metastore
3.Hadoop
使用HDFS進行存儲,使用MapReduce進行計算。
4.驅動器:Driver
(1)解析器(SQL Parser):將SQL字符串轉換成抽象語法樹AST,這一步一般都用第三方工具庫完成,比如antlr;對AST進行語法分析,比如表是否存在、字段是否存在、SQL語義是否有誤。
(2)編譯器(Physical Plan):將AST編譯生成邏輯執行計劃。
(3)優化器(Query Optimizer):對邏輯執行計劃進行優化。
(4)執行器(Execution):把邏輯執行計劃轉換成可以運行的物理計劃。對於Hive來說,就是MR/Spark。
在這裏插入圖片描述
Hive通過給用戶提供的一系列交互接口,接收到用戶的指令(SQL),使用自己的Driver,結合元數據(MetaStore),將這些指令翻譯成MapReduce,提交到Hadoop中執行,最後,將執行返回的結果輸出到用戶交互接口。

1.4 Hive和數據庫比較
由於 Hive 採用了類似SQL 的查詢語言 HQL(Hive Query Language),因此很容易將 Hive 理解爲數據庫。其實從結構上來看,Hive 和數據庫除了擁有類似的查詢語言,再無類似之處。本文將從多個方面來闡述 Hive 和數據庫的差異。數據庫可以用在 Online 的應用中,但是Hive 是爲數據倉庫而設計的,清楚這一點,有助於從應用角度理解 Hive 的特性。

1.4.1 查詢語言
由於SQL被廣泛的應用在數據倉庫中,因此,專門針對Hive的特性設計了類SQL的查詢語言HQL。熟悉SQL開發的開發者可以很方便的使用Hive進行開發。

1.4.2 數據存儲位置
Hive 是建立在 Hadoop 之上的,所有 Hive 的數據都是存儲在 HDFS 中的。而數據庫則可以將數據保存在塊設備或者本地文件系統中。

1.4.3 數據更新
由於Hive是針對數據倉庫應用設計的,而數據倉庫的內容是讀多寫少的。因此,Hive中不建議對數據的改寫,所有的數據都是在加載的時候確定好的。而數據庫中的數據通常是需要經常進行修改的,因此可以使用 INSERT INTO … VALUES 添加數據,使用 UPDATE … SET修改數據。

1.4.4 執行
Hive中大多數查詢的執行是通過 Hadoop 提供的 MapReduce 來實現的。而數據庫通常有自己的執行引擎。

1.4.5 執行延遲
Hive 在查詢數據的時候,由於沒有索引,需要掃描整個表,因此延遲較高。另外一個導致 Hive 執行延遲高的因素是 MapReduce框架。由於MapReduce 本身具有較高的延遲,因此在利用MapReduce 執行Hive查詢時,也會有較高的延遲。相對的,數據庫的執行延遲較低。當然,這個低是有條件的,即數據規模較小,當數據規模大到超過數據庫的處理能力的時候,Hive的並行計算顯然能體現出優勢。

1.4.6 可擴展性
由於Hive是建立在Hadoop之上的,因此Hive的可擴展性是和Hadoop的可擴展性是一致的(世界上最大的Hadoop 集羣在 Yahoo!,2009年的規模在4000 臺節點左右)。而數據庫由於 ACID 語義的嚴格限制,擴展行非常有限。目前最先進的並行數據庫 Oracle 在理論上的擴展能力也只有100臺左右。

1.4.7 數據規模
由於Hive建立在集羣上並可以利用MapReduce進行並行計算,因此可以支持很大規模的數據;對應的,數據庫可以支持的數據規模較小。

第2章 Hive安裝

2.1 Hive安裝地址

1.Hive官網地址
http://hive.apache.org/

2.文檔查看地址
https://cwiki.apache.org/confluence/display/Hive/GettingStarted

3.下載地址
http://archive.apache.org/dist/hive/

4.github地址
https://github.com/apache/hive

2.2 Hive安裝部署

1.Hive安裝及配置
(1)把apache-hive-1.2.1-bin.tar.gz上傳到linux的/opt/software目錄下
(2)解壓apache-hive-1.2.1-bin.tar.gz到/opt/module/目錄下面
[jinghang@hadoop102 software]$ tar -zxvf apache-hive-1.2.1-bin.tar.gz -C /opt/module/
(3)修改apache-hive-1.2.1-bin.tar.gz的名稱爲hive
[jinghang@hadoop102 module]$ mv apache-hive-1.2.1-bin/ hive
(4)修改/opt/module/hive/conf目錄下的hive-env.sh.template名稱爲hive-env.sh
[jinghang@hadoop102 conf]$ mv hive-env.sh.template hive-env.sh
(5)配置hive-env.sh文件
(a)配置HADOOP_HOME路徑
export HADOOP_HOME=/opt/module/hadoop-2.7.2
(b)配置HIVE_CONF_DIR路徑
export HIVE_CONF_DIR=/opt/module/hive/conf

2.Hadoop集羣配置
(1)必須啓動hdfs和yarn

[jinghang@hadoop102 hadoop-2.7.2]$ sbin/start-dfs.sh
[jinghang@hadoop103 hadoop-2.7.2]$ sbin/start-yarn.sh

(2)在HDFS上創建/tmp和/user/hive/warehouse兩個目錄並修改他們的同組權限可寫

[jinghang@hadoop102 hadoop-2.7.2]$ bin/hadoop fs -mkdir /tmp
[jinghang@hadoop102 hadoop-2.7.2]$ bin/hadoop fs -mkdir -p /user/hive/warehouse

[jinghang@hadoop102 hadoop-2.7.2]$ bin/hadoop fs -chmod g+w /tmp
[jinghang@hadoop102 hadoop-2.7.2]$ bin/hadoop fs -chmod g+w /user/hive/warehouse

3.Hive基本操作
(1)啓動hive

[jinghang@hadoop102 hive]$ bin/hive

(2)查看數據庫

hive> show databases;

(3)打開默認數據庫

hive> use default;

(4)顯示default數據庫中的表

hive> show tables;

(5)創建一張表

hive> create table student(id int, name string);

(6)顯示數據庫中有幾張表

hive> show tables;

(7)查看錶的結構

hive> desc student;

(8)向表中插入數據

hive> insert into student values(1000,"ss");

(9)查詢表中數據

hive> select * from student;

(10)退出hive

hive> quit;

說明:(查看hive在hdfs中的結構)
數據庫:在hdfs中表現爲${hive.metastore.warehouse.dir}目錄下一個文件夾
表:在hdfs中表現所屬db目錄下一個文件夾,文件夾中存放該表中的具體數據

2.3 將本地文件導入Hive案例
需求
將本地/opt/module/datas/student.txt這個目錄下的數據導入到hive的student(id int, name string)表中。

1.數據準備
在/opt/module/datas這個目錄下準備數據
(1)在/opt/module/目錄下創建datas

[jinghang@hadoop102 module]$ mkdir datas

(2)在/opt/module/datas/目錄下創建student.txt文件並添加數據

[jinghang@hadoop102 datas]$ touch student.txt
[jinghang@hadoop102 datas]$ vi student.txt
1001	zhangshan
1002	lishi
1003	zhaoliu
注意以

tab鍵間隔。

2.Hive實際操作
(1)啓動hive

[jinghang@hadoop102 hive]$ bin/hive

(2)顯示數據庫

hive> show databases;

(3)使用default數據庫

hive> use default;

(4)顯示default數據庫中的表

hive> show tables;

(5)刪除已創建的student表

hive> drop table student;

(6)創建student表, 並聲明文件分隔符’\t’

hive> create table student(id int, name string) ROW FORMAT DELIMITED FIELDS TERMINATED
 BY '\t';

(7)加載/opt/module/datas/student.txt 文件到student數據庫表中。

hive> load data local inpath '/opt/module/datas/student.txt' into table student;

(8)Hive查詢結果

hive> select * from student;
OK
1001	zhangshan
1002	lishi
1003	zhaoliu
Time taken: 0.266 seconds, Fetched: 3 row(s)

3.遇到的問題
再打開一個客戶端窗口啓動hive,會產生java.sql.SQLException異常。

Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException:
 Unable to instantiate
 org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient
        at org.apache.hadoop.hive.ql.session.SessionState.start(SessionState.java:522)
        at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java:677)
        at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java:621)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.apache.hadoop.util.RunJar.run(RunJar.java:221)
        at org.apache.hadoop.util.RunJar.main(RunJar.java:136)
Caused by: java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient
        at org.apache.hadoop.hive.metastore.MetaStoreUtils.newInstance(MetaStoreUtils.java:1523)
        at org.apache.hadoop.hive.metastore.RetryingMetaStoreClient.<init>(RetryingMetaStoreClient.java:86)
        at org.apache.hadoop.hive.metastore.RetryingMetaStoreClient.getProxy(RetryingMetaStoreClient.java:132)
        at org.apache.hadoop.hive.metastore.RetryingMetaStoreClient.getProxy(RetryingMetaStoreClient.java:104)
        at org.apache.hadoop.hive.ql.metadata.Hive.createMetaStoreClient(Hive.java:3005)
        at org.apache.hadoop.hive.ql.metadata.Hive.getMSC(Hive.java:3024)
        at org.apache.hadoop.hive.ql.session.SessionState.start(SessionState.java:503)
... 8 more

原因是,Metastore默認存儲在自帶的derby數據庫中,推薦使用MySQL存儲Metastore;

2.4 MySql安裝

2.4.1 安裝包準備

1.查看mysql是否安裝,如果安裝了,卸載mysql
(1)查看

[root@hadoop102 桌面]# rpm -qa|grep mysql
mysql-libs-5.1.73-7.el6.x86_64

(2)卸載

[root@hadoop102 桌面]# rpm -e --nodeps mysql-libs-5.1.73-7.el6.x86_64

2.解壓mysql-libs.zip文件到當前目錄

[root@hadoop102 software]# unzip mysql-libs.zip
[root@hadoop102 software]# ls
mysql-libs.zip
mysql-libs

3.進入到mysql-libs文件夾下

[root@hadoop102 mysql-libs]# ll
總用量 76048
-rw-r--r--. 1 root root 18509960 3月  26 2015 MySQL-client-5.6.24-1.el6.x86_64.rpm
-rw-r--r--. 1 root root  3575135 12月  1 2013 mysql-connector-java-5.1.27.tar.gz
-rw-r--r--. 1 root root 55782196 3月  26 2015 MySQL-server-5.6.24-1.el6.x86_64.rpm

2.4.2 安裝MySql服務器

1.安裝mysql服務端

[root@hadoop102 mysql-libs]# rpm -ivh MySQL-server-5.6.24-1.el6.x86_64.rpm

2.查看產生的隨機密碼

[root@hadoop102 mysql-libs]# cat /root/.mysql_secret
OEXaQuS8IWkG19Xs

3.查看mysql狀態

[root@hadoop102 mysql-libs]# service mysql status

4.啓動mysql

[root@hadoop102 mysql-libs]# service mysql start

2.4.3 安裝MySql客戶端

1.安裝mysql客戶端

[root@hadoop102 mysql-libs]# rpm -ivh MySQL-client-5.6.24-1.el6.x86_64.rpm

2.鏈接mysql

[root@hadoop102 mysql-libs]# mysql -uroot -pOEXaQuS8IWkG19Xs

3.修改密碼

mysql>SET PASSWORD=PASSWORD('000000');

4.退出mysql

mysql>exit

2.4.4 MySql中user表中主機配置
配置只要是root用戶+密碼,在任何主機上都能登錄MySQL數據庫。
1.進入mysql

[root@hadoop102 mysql-libs]# mysql -uroot -p000000

2.顯示數據庫

mysql>show databases;

3.使用mysql數據庫

mysql>use mysql;

4.展示mysql數據庫中的所有表

mysql>show tables;

5.展示user表的結構

mysql>desc user;

6.查詢user表

mysql>select User, Host, Password from user;

7.修改user表,把Host表內容修改爲%

mysql>update user set host='%' where host='localhost';

8.刪除root用戶的其他host

mysql>delete from user where Host='hadoop102';
mysql>delete from user where Host='127.0.0.1';
mysql>delete from user where Host='::1'

9.刷新

mysql>flush privileges;

10.退出

mysql>quit;

2.5 Hive元數據配置到MySql
2.5.1 驅動拷貝
1.在/opt/software/mysql-libs目錄下解壓mysql-connector-java-5.1.27.tar.gz驅動包

[root@hadoop102 mysql-libs]# tar -zxvf mysql-connector-java-5.1.27.tar.gz

2.拷貝/opt/software/mysql-libs/mysql-connector-java-5.1.27目錄下的mysql-

connector-java-5.1.27-bin.jar到/opt/module/hive/lib/
[root@hadoop102 mysql-connector-java-5.1.27]# cp mysql-connector-java-5.1.27-bin.jar
 /opt/module/hive/lib/

2.5.2 配置Metastore到MySql
1.在/opt/module/hive/conf目錄下創建一個hive-site.xml

[jinghang@hadoop102 conf]$ touch hive-site.xml
[jinghang@hadoop102 conf]$ vi hive-site.xml

2.根據官方文檔配置參數,拷貝數據到hive-site.xml文件中

https://cwiki.apache.org/confluence/display/Hive/AdminManual+MetastoreAdmin
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
	<property>
	  <name>javax.jdo.option.ConnectionURL</name>
	  <value>jdbc:mysql://hadoop102:3306/metastore?createDatabaseIfNotExist=true</value>
	  <description>JDBC connect string for a JDBC metastore</description>
	</property>

	<property>
	  <name>javax.jdo.option.ConnectionDriverName</name>
	  <value>com.mysql.jdbc.Driver</value>
	  <description>Driver class name for a JDBC metastore</description>
	</property>

	<property>
	  <name>javax.jdo.option.ConnectionUserName</name>
	  <value>root</value>
	  <description>username to use against metastore database</description>
	</property>

	<property>
	  <name>javax.jdo.option.ConnectionPassword</name>
	  <value>000000</value>
	  <description>password to use against metastore database</description>
	</property>
</configuration>

3.配置完畢後,如果啓動hive異常,可以重新啓動虛
擬機。(重啓後,別忘了啓動hadoop集羣)

2.5.3 多窗口啓動Hive測試
1.先啓動MySQL

[jinghang@hadoop102 mysql-libs]$ mysql -uroot -p000000

查看有幾個數據庫

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql             |
| performance_schema |
| test               |
+--------------------+

2.再次打開多個窗口,分別啓動hive

[jinghang@hadoop102 hive]$ bin/hive

3.啓動hive後,回到MySQL窗口查看數據庫,顯示增加了metastore數據庫

	mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| metastore          |
| mysql             |
| performance_schema |
| test               |
+--------------------+

2.6 HiveJDBC訪問

2.6.1 啓動hiveserver2服務

[jinghang@hadoop102 hive]$ bin/hiveserver2

2.6.2 啓動beeline

[jinghang@hadoop102 hive]$ bin/beeline
Beeline version 1.2.1 by Apache Hive
beeline>

2.6.3 連接hiveserver2

beeline> !connect jdbc:hive2://hadoop102:10000(回車)
Connecting to jdbc:hive2://hadoop102:10000
Enter username for jdbc:hive2://hadoop102:10000: jinghang(回車)
Enter password for jdbc:hive2://hadoop102:10000: (直接回車)
Connected to: Apache Hive (version 1.2.1)
Driver: Hive JDBC (version 1.2.1)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://hadoop102:10000> show databases;
+----------------+--+
| database_name  |
+----------------+--+
| default        |
| hive_db2       |
+----------------+--+

2.7 Hive常用交互命令

[jinghang@hadoop102 hive]$ bin/hive -help
usage: hive
 -d,--define <key=value>          Variable subsitution to apply to hive
                                  commands. e.g. -d A=B or --define A=B
    --database <databasename>     Specify the database to use
 -e <quoted-query-string>         SQL from command line
 -f <filename>                    SQL from files
 -H,--help                        Print help information
    --hiveconf <property=value>   Use value for given property
    --hivevar <key=value>         Variable subsitution to apply to hive
                                  commands. e.g. --hivevar A=B
 -i <filename>                    Initialization SQL file
 -S,--silent                      Silent mode in interactive shell
 -v,--verbose                     Verbose mode (echo executed SQL to the console)

1.“-e”不進入hive的交互窗口執行sql語句

[jinghang@hadoop102 hive]$ bin/hive -e "select id from student;"

2.“-f”執行腳本中sql語句
(1)在/opt/module/datas目錄下創建hivef.sql文件

[jinghang@hadoop102 datas]$ touch hivef.sql

		文件中寫入正確的sql語句
		
		select *from student;

(2)執行文件中的sql語句

[jinghang@hadoop102 hive]$ bin/hive -f /opt/module/datas/hivef.sql

(3)執行文件中的sql語句並將結果寫入文件中

[jinghang@hadoop102 hive]$ bin/hive -f /opt/module/datas/hivef.sql  > /opt/module/datas/hive_result.txt

2.8 Hive其他命令操作
1.退出hive窗口:

hive(default)>exit;
hive(default)>quit;
在新版的hive中沒區別了,在以前的版本是有的:
exit:先隱性提交數據,再退出;
quit:不提交數據,退出;

2.在hive cli命令窗口中如何查看hdfs文件系統

hive(default)>dfs -ls /;

3.在hive cli命令窗口中如何查看本地文件系統

hive(default)>! ls /opt/module/datas;

4.查看在hive中輸入的所有歷史命令
(1)進入到當前用戶的根目錄/root或/home/jinghang
(2)查看. hivehistory文件

[jinghang@hadoop102 ~]$ cat .hivehistory

2.9 Hive常見屬性配置
2.9.1 Hive數據倉庫位置配置
1)Default數據倉庫的最原始位置是在hdfs上的:/user/hive/warehouse路徑下。
2)在倉庫目錄下,沒有對默認的數據庫default創建文件夾。如果某張表屬於default數據庫,直接在數據倉庫目錄下創建一個文件夾。
3)修改default數據倉庫原始位置(將hive-default.xml.template如下配置信息拷貝到hive-site.xml文件中)。

<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value>
<description>location of default database for the warehouse</description>
</property>

配置同組用戶有執行權限

bin/hdfs dfs -chmod g+w /user/hive/warehouse

2.9.2 查詢後信息顯示配置
1)在hive-site.xml文件中添加如下配置信息,就可以實現顯示當前數據庫,以及查詢表的頭信息配置。

<property>
	<name>hive.cli.print.header</name>
	<value>true</value>
</property>

<property>
	<name>hive.cli.print.current.db</name>
	<value>true</value>
</property>

2)重新啓動hive,對比配置前後差異。
(1)配置前,如圖6-2所示
在這裏插入圖片描述

		圖6-2 配置前

(2)配置後,如圖6-3所示
在這裏插入圖片描述

	       圖6-3 配置後

2.9.3 Hive運行日誌信息配置
1.Hive的log默認存放在/tmp/jinghang/hive.log目錄下(當前用戶名下)
2.修改hive的log存放日誌到/opt/module/hive/logs
(1)修改/opt/module/hive/conf/hive-log4j.properties.template文件名稱爲

hive-log4j.properties
[jinghang@hadoop102 conf]$ pwd
/opt/module/hive/conf
[jinghang@hadoop102 conf]$ mv hive-log4j.properties.template hive-log4j.properties

(2)在hive-log4j.properties文件中修改log存放位置

hive.log.dir=/opt/module/hive/logs

2.9.4 參數配置方式
1.查看當前所有的配置信息

hive>set;

2.參數的配置三種方式
(1)配置文件方式
默認配置文件:hive-default.xml
用戶自定義配置文件:hive-site.xml
注意:用戶自定義配置會覆蓋默認配置。另外,Hive也會讀入Hadoop的配置,因爲Hive是作爲Hadoop的客戶端啓動的,Hive的配置會覆蓋Hadoop的配置。配置文件的設定對本機啓動的所有Hive進程都有效。
(2)命令行參數方式
啓動Hive時,可以在命令行添加-hiveconf param=value來設定參數。
例如:

[jinghang@hadoop103 hive]$ bin/hive -hiveconf mapred.reduce.tasks=10;

注意:僅對本次hive啓動有效
查看參數設置:

hive (default)> set mapred.reduce.tasks;

(3)參數聲明方式
可以在HQL中使用SET關鍵字設定參數
例如:

hive (default)> set mapred.reduce.tasks=100;

注意:僅對本次hive啓動有效
查看參數設置

hive (default)> set mapred.reduce.tasks;

上述三種設定方式的優先級依次遞增。即配置文件<命令行參數<參數聲明。注意某些系統級的參數,例如log4j相關的設定,必須用前兩種方式設定,因爲那些參數的讀取在會話建立以前已經完成了。

第3章 Hive數據類型

3.1 基本數據類型

						表6-1
						
Hive數據類型  	 Java數據類型	    長度	                例子
TINYINT	            byte	   1byte有符號整數	        20
SMALINT	            short	   2byte有符號整數	        20
INT	                 int	   4byte有符號整數  	        20
BIGINT	             long	   8byte有符號整數	        20
BOOLEAN	            boolean	   布爾類型,true或者false	TRUE  FALSE
FLOAT             	float	   單精度浮點數	            3.14159
DOUBLE	            double	   雙精度浮點數	            3.14159
STRING	            string	   字符系列。可以指定字符集。可以使用單引號或者雙引號。	‘now is the time’ “for all good men”
TIMESTAMP		    時間類型	
BINARY		        字節數組	

對於Hive的String類型相當於數據庫的varchar類型,該類型是一個可變的字符串,不過它不能聲明其中最多能存儲多少個字符,理論上它可以存儲2GB的字符數。

3.2 集合數據類型

表6-2
數據類型						描述															語法示例
STRUCT			和c語言中的struct類似,都可以通過“點”符號訪問元素							struct()		
				內容。例如,如果某個列的數據類型是STRUCT{first STRING,  					例如struct<street:string, city:string>
				last STRING},那麼第1個元素可以通過字段.first來引用。	

MAP				MAP是一組鍵-值對元組集合,使用數組表示法可以訪問數據。						 map()
				例如,如果某個列的數據類型是MAP,其中鍵->值對					 			 例如map<string, int>
				是’first’->’John’和’last’->’Doe’,那麼可以通過
				字段名[‘last’]獲取最後一個元素	

ARRAY			數組是一組具有相同類型和名稱的變量的集合。這些變量 					  	 Array()
				稱爲數組的元素,每個數組元素都有一個編號,編號從零 						 例如array<string>
				開始。例如,數組值爲[‘John’, ‘Doe’],那麼第2個
				元素可以通過數組名[1]進行引用。

Hive有三種複雜數據類型ARRAY、MAP 和 STRUCT。ARRAY和MAP與Java中的Array和Map類似,而STRUCT與C語言中的Struct類似,它封裝了一個命名字段集合,複雜數據類型允許任意層次的嵌套。

案例實操
1)假設某表有如下一行,我們用JSON格式來表示其數據結構。在Hive下訪問的格式爲

{
    "name": "songsong",
    "friends": ["bingbing" , "lili"] ,       //列表Array, 
    "children": {                      //鍵值Map,
        "xiao song": 18 ,
        "xiaoxiao song": 19
    }
    "address": {                      //結構Struct,
        "street": "hui long guan" ,
        "city": "beijing" 
    }
}

2)基於上述數據結構,我們在Hive裏創建對應的表,並導入數據。
創建本地測試文件test.txt

songsong,bingbing_lili,xiao song:18_xiaoxiao song:19,hui long guan_beijing
yangyang,caicai_susu,xiao yang:18_xiaoxiao yang:19,chao yang_beijing

注意 :MAP,STRUCT和ARRAY裏的元素間關係都可以用同一個字符表示,這裏用“_”。

3)Hive上創建測試表test

create table test(
name string,
friends array<string>,
children map<string, int>,
address struct<street:string, city:string>
)
row format delimited fields terminated by ','
collection items terminated by '_'
map keys terminated by ':'
lines terminated by '\n';

字段解釋:

row format delimited fields terminated by ',' -- 列分隔符 collection items terminated by '_' --MAP STRUCT 和 ARRAY 的分隔符

(數據分割符號)
map keys terminated by ':' -- MAP中的key與value的分隔符 lines terminated by '\n'; -- 行分隔符

4)導入文本數據到測試表

hive (default)> load data local inpath ‘/opt/module/datas/test.txt’into table test

5)訪問三種集合列裏的數據,以下分別是ARRAY,MAP,STRUCT的訪問方式

hive (default)> select friends[1],children['xiao song'],address.city from test
where name="songsong";
OK
_c0     _c1     city
lili    18      beijing
Time taken: 0.076 seconds, Fetched: 1 row(s)

3.3 類型轉化
Hive的原子數據類型是可以進行隱式轉換的,類似於Java的類型轉換,例如某表達式使用INT類型,TINYINT會自動轉換爲INT類型,但是Hive不會進行反向轉化,例如,某表達式使用TINYINT類型,INT不會自動轉換爲TINYINT類型,它會返回錯誤,除非使用CAST操作。

1.隱式類型轉換規則如下
(1)任何整數類型都可以隱式地轉換爲一個範圍更廣的類型,如TINYINT可以轉換成INT,INT可以轉換成BIGINT。
(2)所有整數類型、FLOAT和STRING類型都可以隱式地轉換成DOUBLE。
(3)TINYINT、SMALLINT、INT都可以轉換爲FLOAT。
(4)BOOLEAN類型不可以轉換爲任何其它的類型。

2.可以使用CAST操作顯示進行數據類型轉換
例如CAST(‘1’ AS INT)將把字符串’1’ 轉換成整數1;如果強制類型轉換失敗,如執行CAST(‘X’ AS INT),表達式返回空值 NULL。

0: jdbc:hive2://hadoop102:10000> select '1'+2, cast('1'as int) + 2;
+------+------+--+
| _c0  | _c1  |
+------+------+--+
| 3.0  | 3    |
+------+------+--+
-+。

第4章 DDL數據定義

4.1 創建數據庫

CREATE DATABASE [IF NOT EXISTS] database_name
[COMMENT database_comment]
[LOCATION hdfs_path]
[WITH DBPROPERTIES (property_name=property_value, …)];

1)創建一個數據庫,數據庫在HDFS上的默認存儲路徑是/user/hive/warehouse/*.db。

hive (default)> create database db_hive;

2)避免要創建的數據庫已經存在錯誤,增加if not exists判斷。(標準寫法)

hive (default)> create database db_hive;
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. Database db_hive already exists
hive (default)> create database if not exists db_hive;

3)創建一個數據庫,指定數據庫在HDFS上存放的位置

hive (default)> create database db_hive2 location '/db_hive2.db';

圖6-4 數據庫存放位置

4.2 查詢數據庫
4.2.1 顯示數據庫

1.顯示數據庫

hive> show databases;

2.過濾顯示查詢的數據庫

hive> show databases like 'db_hive*';
OK
db_hive
db_hive_1

4.2.2 查看數據庫詳情
1.顯示數據庫信息

hive> desc database db_hive;
OK
db_hive		hdfs://hadoop102:9000/user/hive/warehouse/db_hive.db	jinghangUSER

2.顯示數據庫詳細信息,extended

hive> desc database extended db_hive;
OK
db_hive		hdfs://hadoop102:9000/user/hive/warehouse/db_hive.db	jinghangUSER	

4.2.3 切換當前數據庫

hive (default)> use db_hive;

4.3 修改數據庫
用戶可以使用ALTER DATABASE命令爲某個數據庫的DBPROPERTIES設置鍵-值對屬性值,來描述這個數據庫的屬性信息。數據庫的其他元數據信息都是不可更改的,包括數據庫名和數據庫所在的目錄位置。

hive (default)> alter database db_hive set dbproperties('createtime'='20170830');

在hive中查看修改結果

hive> desc database extended db_hive;
db_name comment location        owner_name      owner_type      parameters
db_hive         hdfs://hadoop102:8020/user/hive/warehouse/db_hive.db    jinghang USER    {createtime=20170830}

4.4 刪除數據庫
1.刪除空數據庫

hive>drop database db_hive2;

2.如果刪除的數據庫不存在,最好採用 if exists判斷數據庫是否存在

hive> drop database db_hive;
FAILED: SemanticException [Error 10072]: Database does not exist: db_hive
hive> drop database if exists db_hive2;

3.如果數據庫不爲空,可以採用cascade命令,強制刪除

hive> drop database db_hive;
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. InvalidOperationException(message:Database db_hive is not empty. One or more tables exist.)
hive> drop database db_hive cascade;

4.5 創建表
1.建表語法

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]
[TBLPROPERTIES (property_name=property_value, …)]
[AS select_statement]

2.字段解釋說明
(1)CREATE TABLE 創建一個指定名字的表。如果相同名字的表已經存在,則拋出異常;用戶可以用 IF NOT EXISTS 選項來忽略這個異常。
(2)EXTERNAL關鍵字可以讓用戶創建一個外部表,在建表的同時可以指定一個指向實際數據的路徑(LOCATION),在刪除表的時候,內部表的元數據和數據會被一起刪除,而外部表只刪除元數據,不刪除數據。
(3)COMMENT:爲表和列添加註釋。
(4)PARTITIONED BY創建分區表
(5)CLUSTERED BY創建分桶表
(6)SORTED BY不常用,對桶中的一個或多個列另外排序
(7)ROW FORMAT
DELIMITED [FIELDS TERMINATED 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, …)]
用戶在建表的時候可以自定義SerDe或者使用自帶的SerDe。如果沒有指定ROW FORMAT 或者ROW FORMAT DELIMITED,將會使用自帶的SerDe。在建表的時候,用戶還需要爲表指定列,用戶在指定表的列的同時也會指定自定義的SerDe,Hive通過SerDe確定表的具體的列的數據。
SerDe是Serialize/Deserilize的簡稱, hive使用Serde進行行對象的序列與反序列化。
(8)STORED AS指定存儲文件類型
常用的存儲文件類型:SEQUENCEFILE(二進制序列文件)、TEXTFILE(文本)、RCFILE(列式存儲格式文件)
如果文件數據是純文本,可以使用STORED AS TEXTFILE。如果數據需要壓縮,使用 STORED AS SEQUENCEFILE。
(9)LOCATION :指定表在HDFS上的存儲位置。
(10)AS:後跟查詢語句
,根據查詢結果創建表。
(11)LIKE允許用戶複製現有的表結構,但是不復制數據。

4.5.1 管理表

1.理論
默認創建的表都是所謂的管理表,有時也被稱爲內部表。因爲這種表,Hive會(或多或少地)控制着數據的生命週期。Hive默認情況下會將這些表的數據存儲在由配置項hive.metastore.warehouse.dir(例如,/user/hive/warehouse)所定義的目錄的子目錄下。 當我們刪除一個管理表時,Hive也會刪除這個表中數據。管理表不適合和其他工具共享數據。
2.案例實操
(1)普通創建表

create table if not exists student2(
id int, name string
)
row format delimited fields terminated by '\t'
stored as textfile
location '/user/hive/warehouse/student2';

(2)根據查詢結果創建表(查詢的結果會添加到新創建的表中)

create table if not exists student3 as select id, name from student;

(3)根據已經存在的表結構創建表

create table if not exists student4 like student;

(4)查詢表的類型

hive (default)> desc formatted student2;
Table Type:             MANAGED_TABLE  

4.5.2 外部表

1.理論
因爲表是外部表,所以Hive並非認爲其完全擁有這份數據。刪除該表並不會刪除掉這份數據,不過描述表的元數據信息會被刪除掉。

2.管理表和外部表的使用場景
每天將收集到的網站日誌定期流入HDFS文本文件。在外部表(原始日誌表)的基礎上做大量的統計分析,用到的中間表、結果表使用內部表存儲,數據通過SELECT+INSERT進入內部表。

3.案例實操
分別創建部門和員工外部表,並向表中導入數據。
(1)上傳數據到HDFS

hive (default)> dfs -mkdir /student;
hive (default)> dfs -put /opt/module/datas/student.txt /student;

(2)建表語句
創建外部表

hive (default)> create external table stu_external(
id int, 
name string) 
row format delimited fields terminated by '\t' 
location '/student';

(3)查看創建的表

hive (default)> select * from stu_external;
OK
stu_external.id stu_external.name
1001    lisi
1002    wangwu
1003    zhaoliu

(4)查看錶格式化數據

hive (default)> desc formatted dept;
Table Type:             EXTERNAL_TABLE

(5)刪除外部表

hive (default)> drop table stu_external;

外部表刪除後,hdfs中的數據還在,但是metadata中stu_external的元數據已被刪除

4.5.3 管理表與外部表的互相轉換
(1)查詢表的類型

hive (default)> desc formatted student2;
Table Type:             MANAGED_TABLE

(2)修改內部表student2爲外部表

alter table student2 set tblproperties('EXTERNAL'='TRUE');

(3)查詢表的類型

hive (default)> desc formatted student2;
Table Type:             EXTERNAL_TABLE

(4)修改外部表student2爲內部表

alter table student2 set tblproperties('EXTERNAL'='FALSE');

(5)查詢表的類型

hive (default)> desc formatted student2;
Table Type:             MANAGED_TABLE

注意:('EXTERNAL'='TRUE')和('EXTERNAL'='FALSE')爲固定寫法,區分大小寫!

4.6 分區表
分區表實際上就是對應一個HDFS文件系統上的獨立的文件夾,該文件夾下是該分區所有的數據文件。Hive中的分區就是分目錄,把一個大的數據集根據業務需要分割成小的數據集。在查詢時通過WHERE子句中的表達式選擇查詢所需要的指定的分區,這樣的查詢效率會提高很多。
4.6.1 分區表基本操作
1.引入分區表(需要根據日期對日誌進行管理)

/user/hive/warehouse/log_partition/20170702/20170702.log
/user/hive/warehouse/log_partition/20170703/20170703.log
/user/hive/warehouse/log_partition/20170704/20170704.log

2.創建分區表語法

hive (default)> create table dept_partition(
deptno int, dname string, loc string
)
partitioned by (month string)
row format delimited fields terminated by '\t';

注意:分區字段不能是表中已經存在的數據,可以將分區字段看作表的僞列。

3.加載數據到分區表中

hive (default)> load data local inpath '/opt/module/datas/dept.txt' into table default.dept_partition partition(month='201709');
hive (default)> load data local inpath '/opt/module/datas/dept.txt' into table default.dept_partition partition(month='201708');
hive (default)> load data local inpath '/opt/module/datas/dept.txt' into table default.dept_partition partition(month='201707’);

注意:分區表加載數據時,必須指定分區

4.查詢分區表中數據
單分區查詢

hive (default)> select * from dept_partition where month='201709';

多分區聯合查詢

hive (default)> select * from dept_partition where month='201709'
              union
              select * from dept_partition where month='201708'
              union
              select * from dept_partition where month='201707';


_u3.deptno      _u3.dname       _u3.loc _u3.month
10      ACCOUNTING      NEW YORK        201707
10      ACCOUNTING      NEW YORK        201708
10      ACCOUNTING      NEW YORK        201709
20      RESEARCH        DALLAS  201707
20      RESEARCH        DALLAS  201708
20      RESEARCH        DALLAS  201709
30      SALES   CHICAGO 201707
30      SALES   CHICAGO 201708
30      SALES   CHICAGO 201709
40      OPERATIONS      BOSTON  201707
40      OPERATIONS      BOSTON  201708
40      OPERATIONS      BOSTON  201709

5.增加分區
創建單個分區

hive (default)> alter table dept_partition add partition(month='201706') ;
同時創建多個分區
hive (default)> alter table dept_partition add partition(month='201705') partition(month='201704');

6.刪除分區
刪除單個分區

hive (default)> alter table dept_partition drop partition (month='201704');

同時刪除多個分區

hive (default)> alter table dept_partition drop partition (month='201705'), partition (month='201706');

7.查看分區表有多少分區

hive> show partitions dept_partition;

8.查看分區表結構

hive> desc formatted dept_partition;


# Partition Information          
# col_name              data_type               comment             
month                   string    

4.6.2 分區表注意事項
1.創建二級分區表

hive (default)> create table dept_partition2(
               deptno int, dname string, loc string
               )
               partitioned by (month string, day string)
               row format delimited fields terminated by '\t';

2.正常的加載數據
(1)加載數據到二級分區表中

hive (default)> load data local inpath '/opt/module/datas/dept.txt' into table
 default.dept_partition2 partition(month='201709', day='13');

(2)查詢分區數據

hive (default)> select * from dept_partition2 where month='201709' and day='13';

3.把數據直接上傳到分區目錄上,讓分區表和數據產生關聯的三種方式
(1)方式一:上傳數據後修復
上傳數據

hive (default)> dfs -mkdir -p
 /user/hive/warehouse/dept_partition2/month=201709/day=12;
hive (default)> dfs -put /opt/module/datas/dept.txt  /user/hive/warehouse/dept_partition2/month=201709/day=12;
查詢數據(查詢不到剛上傳的數據)
hive (default)> select * from dept_partition2 where month='201709' and day='12';

執行修復命令

hive> msck repair table dept_partition2;

再次查詢數據

hive (default)> select * from dept_partition2 where month='201709' and day='12';

(2)方式二:上傳數據後添加分區
上傳數據

hive (default)> dfs -mkdir -p
 /user/hive/warehouse/dept_partition2/month=201709/day=11;
hive (default)> dfs -put /opt/module/datas/dept.txt  /user/hive/warehouse/dept_partition2/month=201709/day=11;
執行添加分區
hive (default)> alter table dept_partition2 add partition(month='201709',
 day='11');
查詢數據
hive (default)> select * from dept_partition2 where month='201709' and day='11';

(3)方式三:創建文件夾後load數據到分區
創建目錄

hive (default)> dfs -mkdir -p
 /user/hive/warehouse/dept_partition2/month=201709/day=10;

上傳數據

hive (default)> load data local inpath '/opt/module/datas/dept.txt' into table
 dept_partition2 partition(month='201709',day='10');

查詢數據

hive (default)> select * from dept_partition2 where month='201709' and day='10';

4.7 修改表
4.7.1 重命名錶
1.語法
ALTER TABLE table_name RENAME TO new_table_name
2.實操案例

hive (default)> alter table dept_partition2 rename to dept_partition3;

4.7.2 增加、修改和刪除表分區

詳見4.6.1分區表基本操作。

4.7.3 增加/修改/替換列信息
1.語法
更新列
ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_name column_type [COMMENT col_comment] [FIRST|AFTER column_name]

增加和替換列
ALTER TABLE table_name ADD|REPLACE COLUMNS (col_name data_type [COMMENT col_comment], …)
注:ADD是代表新增一字段,字段位置在所有列後面(partition列前),REPLACE則是表示替換表中所有字段。

2.實操案例
(1)查詢表結構

hive> desc dept_partition;

(2)添加列

hive (default)> alter table dept_partition add columns(deptdesc string);

(3)查詢表結構

hive> desc dept_partition;

(4)更新列

hive (default)> alter table dept_partition change column deptdesc desc int;

(5)查詢表結構

hive> desc dept_partition;

(6)替換列

hive (default)> alter table dept_partition replace columns(deptno string, dname
 string, loc string);

(7)查詢表結構

hive> desc dept_partition;

4.8 刪除表

hive (default)> drop table dept_partition;

第5章 DML數據操作

5.1 數據導入
5.1.1 向表中裝載數據(Load)

1.語法
hive> load data [local] inpath ‘/opt/module/datas/student.txt’ [overwrite] into table student [partition (partcol1=val1,…)];
(1)load data:表示加載數據
(2)local:表示從本地加載數據到hive表;否則從HDFS加載數據到hive表
(3)inpath:表示加載數據的路徑
(4)overwrite:表示覆蓋表中已有數據,否則表示追加
(5)into table:表示加載到哪張表
(6)student:表示具體的表
(7)partition:表示上傳到指定分區

2.實操案例
(0)創建一張表

hive (default)> create table student(id string, name string) row format delimited fields terminated by '\t';

(1)加載本地文件到hive

hive (default)> load data local inpath '/opt/module/datas/student.txt' into table default.student;

(2)加載HDFS文件到hive中
上傳文件到HDFS

hive (default)> dfs -put /opt/module/datas/student.txt /user/jinghang/hive;

加載HDFS上數據

hive (default)> load data inpath '/user/jinghang/hive/student.txt' into table default.student;

(3)加載數據覆蓋表中已有的數據
上傳文件到HDFS

hive (default)> dfs -put /opt/module/datas/student.txt /user/jinghang/hive;

加載數據覆蓋表中已有的數據

hive (default)> load data inpath '/user/jinghang/hive/student.txt' overwrite into table default.student;

5.1.2 通過查詢語句向表中插入數據(Insert)
1.創建一張分區表

hive (default)> create table student(id int, name string) partitioned by (month string) row format delimited fields terminated by '\t';

2.基本插入數據

hive (default)> insert into table  student partition(month='201709') values(1,'wangwu'),(2,’zhaoliu’);

3.基本模式插入(根據單張表查詢結果)

hive (default)> insert overwrite table student partition(month='201708')
             select id, name from student where month='201709';

insert into:以追加數據的方式插入到表或分區,原有數據不會刪除
insert overwrite:會覆蓋表或分區中已存在的數據

注意:insert不支持插入部分字段

4.多表(多分區)插入模式(根據多張表查詢結果)

hive (default)> from student
              insert overwrite table student partition(month='201707')
              select id, name where month='201709'
              insert overwrite table student partition(month='201706')
              select id, name where month='201709';

5.1.3 查詢語句中創建表並加載數據(As Select)

詳見4.5.1章創建表。
根據查詢結果創建表(查詢的結果會添加到新創建的表中)

create table if not exists student3
as select id, name from student;

5.1.4 創建表時通過Location指定加載數據路徑
1.上傳數據到hdfs上

hive (default)> dfs -mkdir /student;
hive (default)> dfs -put /opt/module/datas/student.txt /student;
  1. 創建表,並指定在hdfs上的位置
hive (default)> create external table if not exists student5(
              id int, name string
              )
              row format delimited fields terminated by '\t'
              location '/student;

3.查詢數據

hive (default)> select * from student5;

5.1.5 Import數據到指定Hive表中
注意:先用export導出後,再將數據導入。

hive (default)> import table student2 partition(month='201709') from
 '/user/hive/warehouse/export/student';

5.2 數據導出
5.2.1 Insert導出
1.將查詢的結果導出到本地

hive (default)> insert overwrite local directory '/opt/module/datas/export/student'
            select * from student;

2.將查詢的結果格式化導出到本地

hive(default)>insert overwrite local directory '/opt/module/datas/export/student1'
           ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'             select * from student;

3.將查詢的結果導出到HDFS上(沒有local)

hive (default)> insert overwrite directory '/user/jinghang/student2'
             ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' 
             select * from student;

5.2.2 Hadoop命令導出到本地

hive (default)> dfs -get /user/hive/warehouse/student/month=201709/000000_0
/opt/module/datas/export/student3.txt;

5.2.3 Hive Shell 命令導出
基本語法:(hive -f/-e 執行語句或者腳本 > file)

[jinghang@hadoop102 hive]$ bin/hive -e 'select * from default.student;' >
 /opt/module/datas/export/student4.txt;

5.2.4 Export導出到HDFS上

(defahiveult)> export table default.student to
 '/user/hive/warehouse/export/student';

export和import主要用於兩個Hadoop平臺集羣之間Hive表遷移。

5.2.5 Sqoop導出
後續課程專門講。

5.3 清除表中數據(Truncate)

注意:Truncate只能刪除管理表,不能刪除外部表中數據

hive (default)> truncate table student;

第6章 查詢

https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Select
查詢語句語法:
[WITH CommonTableExpression (, CommonTableExpression)*] (Note: Only available
starting with Hive 0.13.0)
SELECT [ALL | DISTINCT] select_expr, select_expr, …
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list]
[ORDER BY col_list]
[CLUSTER BY col_list
| [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT number]

6.1 基本查詢(Select…From)

6.1.1 全表和特定列查詢

創建部門表

create table if not exists dept(
deptno int,
dname string,
loc int
)
row format delimited fields terminated by '\t';

創建員工表

create table if not exists emp(
empno int,
ename string,
job string,
mgr int,
hiredate string, 
sal double, 
comm double,
deptno int)
row format delimited fields terminated by '\t';

導入數據

hive (default)> load data local inpath '/opt/module/datas/dept.txt' into table
dept;
hive (default)> load data local inpath '/opt/module/datas/emp.txt' into table emp;

1.全表查詢

hive (default)> select * from emp;

2.選擇特定列查詢

hive (default)> select empno, ename from emp;

注意:
(1)SQL 語言大小寫不敏感。
(2)SQL 可以寫在一行或者多行
(3)關鍵字不能被縮寫也不能分行
(4)各子句一般要分行寫。
(5)使用縮進提高語句的可讀性。

6.1.2 列別名
1.重命名一個列
2.便於計算
3.緊跟列名,也可以在列名和別名之間加入關鍵字‘AS’
4.案例實操
查詢名稱和部門

hive (default)> select ename AS name, deptno dn from emp;

6.1.3 算術運算符

					表6-3
運算符 描述
A+B A和B 相加
A-B A減去B
A*B A和B 相乘
A/B A除以B
A%B A對B取餘
A&B A和B按位取與
A 豎槓B A和B按位取或
A^B A和B按位取異或
~A A按位取反

案例實操
查詢出所有員工的薪水後加1顯示。

hive (default)> select sal +1 from emp;

6.1.4 常用函數
1.求總行數(count)

hive (default)> select count(*) cnt from emp;

2.求工資的最大值(max)

hive (default)> select max(sal) max_sal from emp;

3.求工資的最小值(min)

hive (default)> select min(sal) min_sal from emp;

4.求工資的總和(sum)

hive (default)> select sum(sal) sum_sal from emp; 

5.求工資的平均值(avg)

hive (default)> select avg(sal) avg_sal from emp;

6.1.5 Limit語句
典型的查詢會返回多行數據。LIMIT子句用於限制返回的行數,沒有從哪開始,只能從0開始

hive (default)> select * from emp limit 5;

6.2 Where語句
1.使用WHERE子句,將不滿足條件的行過濾掉
2.WHERE子句緊隨FROM子句
3.案例實操
查詢出薪水大於1000的所有員工

hive (default)> select * from emp where sal >1000;

注意:where子句中不能使用字段別名。

6.2.1 比較運算符(Between/In/ Is Null)
1)下面表中描述了謂詞操作符,這些操作符同樣可以用於JOIN…ON和HAVING語句中。

						表6-4
						
操作符						支持的數據類型							描述
A=B							基本數據類型						如果A等於B則返回TRUE,反之返回FALSE
A<=>B						基本數據類型						如果A和B都爲NULL,則返回TRUE,其他的和等號(=)操作符的結果一致,如果任一爲NULL則結果爲NULL
A<>B, A!=B					基本數據類型						A或者B爲NULL則返回NULL;如果A不等於B,則返回TRUE,反之返回FALSE
A<B							基本數據類型						A或者B爲NULL,則返回NULL;如果A小於B,則返回TRUE,反之返回FALSE
A<=B						基本數據類型						A或者B爲NULL,則返回NULL;如果A小於等於B,則返回TRUE,反之返回FALSE
A>B							基本數據類型						A或者B爲NULL,則返回NULL;如果A大於B,則返回TRUE,反之返回FALSE
A>=B						基本數據類型						A或者B爲NULL,則返回NULL;如果A大於等於B,則返回TRUE,反之返回FALSE
A [NOT] BETWEEN B AND C		基本數據類型						如果A,B或者C任一爲NULL,則結果爲NULL。如果A的值大於等於B而且小於或等於C,則結果爲TRUE,反之爲FALSE。如果使用NOT關鍵字則可達到相反的效果。
A IS NULL					所有數據類型						如果A等於NULL,則返回TRUE,反之返回FALSE
A IS NOT NULL				所有數據類型						如果A不等於NULL,則返回TRUE,反之返回FALSE
IN(數值1, 數值2)				所有數據類型						使用 IN運算顯示列表中的值
A [NOT] LIKE B				STRING 類型						B是一個SQL下的簡單正則表達式,也叫通配符模式,如果A與其匹配的話,則返回TRUE;反之返回FALSE。B的表達式說明如下:‘x%’表示A必須以字母‘x’開頭,‘%x’表示A必須以字母’x’結尾,而‘%x%’表示A包含有字母’x’,可以位於開頭,結尾或者字符串中間。如果使用NOT關鍵字則可達到相反的效果。
A RLIKE B, A REGEXP B		STRING 類型						B是基於java的正則表達式,如果A與其匹配,則返回TRUE;反之返回FALSE。匹配使用的是JDK中的正則表達式接口實現的,因爲正則也依據其中的規則。例如,正則表達式必須和整個字符串A相匹配,而不是隻需與其字符串匹配。

2)案例實操
(1)查詢出薪水等於5000的所有員工

hive (default)> select * from emp where sal =5000;

(2)查詢工資在500到1000的員工信息

hive (default)> select * from emp where sal between 500 and 1000;

(3)查詢comm爲空的所有員工信息

hive (default)> select * from emp where comm is null;

(4)查詢工資是1500或5000的員工信息

hive (default)> select * from emp where sal IN (1500, 5000);

6.2.2 Like和RLike
1)使用LIKE運算選擇類似的值
2)選擇條件可以包含字符或數字:

% 代表零個或多個字符(任意個字符)。
_ 代表一個字符。

3)RLIKE子句是Hive中這個功能的一個擴展,其可以通過Java的正則表達式這個更強大的語言來指定匹配條件。
4)案例實操
(1)查找以2開頭薪水的員工信息

hive (default)> select * from emp where sal LIKE '2%';

(2)查找第二個數值爲2的薪水的員工信息

hive (default)> select * from emp where sal LIKE '_2%';

(3)查找薪水中含有2的員工信息

hive (default)> select * from emp where sal RLIKE '[2]';

6.2.3 邏輯運算符(And/Or/Not)

					表6-5
操作符 含義
AND 邏輯並
OR 邏輯或
NOT 邏輯否

案例實操
(1)查詢薪水大於1000,部門是30

hive (default)> select * from emp where sal>1000 and deptno=30;
(2)查詢薪水大於1000,或者部門是30
hive (default)> select * from emp where sal>1000 or deptno=30;
(3)查詢除了20部門和30部門以外的員工信息
hive (default)> select * from emp where deptno not IN(30, 20);

6.3 分組
6.3.1 Group By語句
GROUP BY語句通常會和聚合函數一起使用,按照一個或者多個列隊結果進行分組,然後對每個組執行聚合操作。
案例實操:
(1)計算emp表每個部門的平均工資

hive (default)> select t.deptno, avg(t.sal) avg_sal from emp t group by t.deptno;

(2)計算emp每個部門中每個崗位的最高薪水
h

ive (default)> select t.deptno, t.job, max(t.sal) max_sal from emp t group by
 t.deptno, t.job;

6.3.2 Having語句
1.having與where不同點
(1)where後面不能寫分組函數,而having後面可以使用分組函數。
(2)having只用於group by分組統計語句。
2.案例實操
(1)求每個部門的平均薪水大於2000的部門
求每個部門的平均工資

hive (default)> select deptno, avg(sal) from emp group by deptno;

求每個部門的平均薪水大於2000的部門

hive (default)> select deptno, avg(sal) avg_sal from emp group by deptno having
 avg_sal > 2000;

6.4 Join語句
6.4.1 等值Join
Hive支持通常的SQL JOIN語句,但是隻支持等值連接,不支持非等值連接。
案例實操
(1)根據員工表和部門表中的部門編號相等,查詢員工編號、員工名稱和部門名稱;

hive (default)> select e.empno, e.ename, d.deptno, d.dname from emp e join dept d on e.deptno = d.deptno;

6.4.2 表的別名
1.好處
(1)使用別名可以簡化查詢。
(2)使用表名前綴可以提高執行效率。
2.案例實操
合併員工表和部門表

hive (default)> select e.empno, e.ename, d.deptno from emp e join dept d on e.deptno
 = d.deptno;

6.4.3 內連接
內連接:只有進行連接的兩個表中都存在與連接條件相匹配的數據纔會被保留下來。

hive (default)> select e.empno, e.ename, d.deptno from emp e join dept d on e.deptno
 = d.deptno;

6.4.4 左外連接
左外連接:JOIN操作符左邊表中符合WHERE子句的所有記錄將會被返回。

hive (default)> select e.empno, e.ename, d.deptno from emp e left join dept d on e.deptno = d.deptno;

6.4.5 右外連接
右外連接:JOIN操作符右邊表中符合WHERE子句的所有記錄將會被返回。

hive (default)> select e.empno, e.ename, d.deptno from emp e right join dept d on e.deptno = d.deptno;

6.4.6 滿外連接
滿外連接:將會返回所有表中符合WHERE語句條件的所有記錄。如果任一表的指定字段沒有符合條件的值的話,那麼就使用NULL值替代。

hive (default)> select e.empno, e.ename, d.deptno from emp e full join dept d on e.deptno
 = d.deptno;

6.4.7 多表連接
注意:連接 n個表,至少需要n-1個連接條件。例如:連接三個表,至少需要兩個連接條件。
數據準備

1.創建位置表

create table if not exists location(
loc int,
loc_name string
)
row format delimited fields terminated by '\t';

2.導入數據

hive (default)> load data local inpath '/opt/module/datas/location.txt' into table location;

3.多表連接查詢

hive (default)>SELECT e.ename, d.dname, l.loc_name
FROM   emp e 
JOIN   dept d
ON     d.deptno = e.deptno 
JOIN   location l
ON     d.loc = l.loc;

大多數情況下,Hive會對每對JOIN連接對象啓動一個MapReduce任務。本例中會首先啓動一個MapReduce job對錶e和表d進行連接操作,然後會再啓動一個MapReduce job將第一個MapReduce job的輸出和表l;進行連接操作。
注意:爲什麼不是表d和表l先進行連接操作呢?這是因爲Hive總是按照從左到右的順序執行的。
優化:當對3個或者更多表進行join連接時,如果每個on子句都使用相同的連接鍵的話,那麼只會產生一個MapReduce job。

6.4.8 笛卡爾積
1.笛卡爾集會在下面條件下產生
(1)省略連接條件
(2)連接條件無效
(3)所有表中的所有行互相連接
2.案例實操

hive (default)> select empno, dname from emp, dept;

6.4.9 連接謂詞中不支持or
hive join目前不支持在on子句中使用謂詞or

hive (default)> select e.empno, e.ename, d.deptno from emp e join dept d on e.deptno
= d.deptno or e.ename=d.ename;   錯誤的

6.5 排序
6.5.1 全局排序(Order By)

Order By:全局排序,只有一個Reducer

1.使用 ORDER BY 子句排序
ASC(ascend): 升序(默認)
DESC(descend): 降序
2.ORDER BY 子句在SELECT語句的結尾
3.案例實操
(1)查詢員工信息按工資升序排列

hive (default)> select * from emp order by sal;
(2)查詢員工信息按工資降序排列
hive (default)> select * from emp order by sal desc;

6.5.2 按照別名排序
按照員工薪水的2倍排序

hive (default)> select ename, sal*2 twosal from emp order by twosal;

6.5.3 多個列排序
按照部門和工資升序排序

hive (default)> select ename, deptno, sal from emp order by deptno, sal ;

6.5.4 每個MapReduce內部排序(Sort By)
Sort By:對於大規模的數據集order by的效率非常低。在很多情況下,並不需要全局排序,此時可以使用sort by。
Sort by爲每個reducer產生一個排序文件。每個Reducer內部進行排序,對全局結果集來說不是排序。
1.設置reduce個數

hive (default)> set mapreduce.job.reduces=3;

2.查看設置reduce個數

hive (default)> set mapreduce.job.reduces;

3.根據部門編號降序查看員工信息

hive (default)> select * from emp sort by deptno desc;
4.將查詢結果導入到文件中(按照部門編號降序排序)
hive (default)> insert overwrite local directory '/opt/module/datas/sortby-result'
 select * from emp sort by deptno desc;

6.5.5 分區排序(Distribute By)
Distribute By: 在有些情況下,我們需要控制某個特定行應該到哪個reducer,通常是爲了進行後續的聚集操作。distribute by 子句可以做這件事。distribute by類似MR中partition(自定義分區),進行分區,結合sort by使用。
對於distribute by進行測試,一定要分配多reduce進行處理,否則無法看到distribute by的效果。
案例實操:
(1)先按照部門編號分區,再按照員工編號降序排序。

hive (default)> set mapreduce.job.reduces=3;
hive (default)> insert overwrite local directory '/opt/module/datas/distribute-result' select * from emp distribute by deptno sort by empno desc;

注意:
1.distribute by的分區規則是根據分區字段的hash碼與reduce的個數進行模除後,餘數相同的分到一個區。
2.Hive要求DISTRIBUTE BY語句要寫在SORT BY語句之前。

6.5.6 Cluster By
當distribute by和sorts by字段相同時,可以使用cluster by方式。
cluster by除了具有distribute by的功能外還兼具sort by的功能。但是排序只能是升序排序,不能指定排序規則爲ASC或者DESC。
1)以下兩種寫法等價

hive (default)> select * from emp cluster by deptno;
hive (default)> select * from emp distribute by deptno sort by deptno;

注意:按照部門編號分區,不一定就是固定死的數值,可以是20號和30號部門分到一個分區裏面去。

6.6 分桶及抽樣查詢
6.6.1 分桶表數據存儲

分區提供一個隔離數據和優化查詢的便利方式。不過,並非所有的數據集都可形成合理的分區。對於一張表或者分區,Hive 可以進一步組織成桶,也就是更爲細粒度的數據範圍劃分。
分桶是將數據集分解成更容易管理的若干部分的另一個技術。
分區針對的是數據的存儲路徑;分桶針對的是數據文件。
1.先創建分桶表,通過直接導入數據文件的方式
(1)數據準備
在這裏插入圖片描述
(2)創建分桶表

create table stu_buck(id int, name string)
clustered by(id) 
into 4 buckets
row format delimited fields terminated by '\t';

(3)查看錶結構

hive (default)> desc formatted stu_buck;
Num Buckets:            4     

(4)導入數據到分桶表中

hive (default)> load data local inpath '/opt/module/datas/student.txt' into table
 stu_buck;

(5)查看創建的分桶表中是否分成4個桶,如圖6-7所示

發現並沒有分成4個桶。是什麼原因呢?

2.創建分桶表時,數據通過子查詢的方式導入
(1)先建一個普通的stu表

create table stu(id int, name string)
row format delimited fields terminated by '\t';

(2)向普通的stu表中導入數據

load data local inpath '/opt/module/datas/student.txt' into table stu;

(3)清空stu_buck表中數據

truncate table stu_buck;
select * from stu_buck;

(4)導入數據到分桶表,通過子查詢的方式

insert into table stu_buck
select id, name from stu;

(5)發現還是隻有一個分桶,如圖6-8所示

					圖6-8 未分桶

(6)需要設置一個屬性

hive (default)> set hive.enforce.bucketing=true;
hive (default)> set mapreduce.job.reduces=-1;
hive (default)> insert into table stu_buck
select id, name from stu;
				圖6-9 分桶

(7)查詢分桶的數據

hive (default)> select * from stu_buck;
OK
stu_buck.id     stu_buck.name
1004    ss4
1008    ss8
1012    ss12
1016    ss16
1001    ss1
1005    ss5
1009    ss9
1013    ss13
1002    ss2
1006    ss6
1010    ss10
1014    ss14
1003    ss3
1007    ss7
1011    ss11
1015    ss15

分桶規則:
根據結果可知:Hive的分桶採用對分桶字段的值進行哈希,然後除以桶的個數求餘的方式決定該條記錄存放在哪個桶當中,第一個桶餘數爲0,第二個桶餘數爲1,
第三個桶餘數爲2,第四個桶餘數爲3

6.6.2 分桶抽樣查詢
注:抽樣調查,跟之前的桶數無關,按id與y’的取餘之後的哈希值進行比較
對於非常大的數據集,有時用戶需要使用的是一個具有代表性的查詢結果而不是全部結果。Hive可以通過對錶進行抽樣來滿足這個需求。
查詢表stu_buck中的數據。
hive (default)> select * from stu_buck tablesample(bucket 1 out of 4 on id);
注:tablesample是抽樣語句,語法:TABLESAMPLE(BUCKET x OUT OF y) 。
y必須是table總bucket數的倍數或者因子。hive根據y的大小,決定抽樣的比例。例如,table總共分了4份,當y=2時,抽取(4/2=)2個bucket的數據,當y=8時,抽取(4/8=)1/2個bucket的數據,4是桶數。
x表示從哪個bucket開始抽取,如果需要取多個分區,以後的分區號爲當前分區號加上y。例如,table總bucket數爲4,tablesample(bucket 1 out of 2),表示總共抽取(4/2=)2個bucket的數據,抽取第1(x)個和第3(x+y)個bucket的數據。
注意:x的值必須小於等於y的值,否則
FAILED: SemanticException [Error 10061]: Numerator should not be bigger than denominator in sample clause for table stu_buck

6.7 其他常用查詢函數
6.7.1 空字段賦值

1.函數說明
NVL:給值爲NULL的數據賦值,它的格式是NVL( value,default_value)。它的功能是如果value爲NULL,則NVL函數返回default_value的值,否則返回value的值,如果兩個參數都爲NULL ,則返回NULL。
2.數據準備:採用員工表
3.查詢:如果員工的comm爲NULL,則用-1代替

hive (default)> select comm,nvl(comm, -1) from emp;
OK
comm    _c1
NULL    -1.0
300.0   300.0
500.0   500.0
NULL    -1.0
1400.0  1400.0
NULL    -1.0
NULL    -1.0
NULL    -1.0
NULL    -1.0
0.0     0.0
NULL    -1.0
NULL    -1.0
NULL    -1.0
NULL    -1.0

4.查詢:如果員工的comm爲NULL,則用領導id代替

hive (default)> select comm, nvl(comm,mgr) from emp;
OK
comm    _c1
NULL    7902.0
300.0   300.0
500.0   500.0
NULL    7839.0
1400.0  1400.0
NULL    7839.0
NULL    7839.0
NULL    7566.0
NULL    NULL
0.0     0.0
NULL    7788.0
NULL    7698.0
NULL    7566.0
NULL    7782.0

6.7.2 CASE WHEN

  1. 數據準備
    在這裏插入圖片描述
    2.需求
    求出不同部門男女各多少人。結果如下:
A     2       1
B     1       2

3.創建本地emp_sex.txt,導入數據

[jinghang@hadoop102 datas]$ vi emp_sex.txt
悟空	A	男
大海	A	男
宋宋	B	男
鳳姐	A	女
婷姐	B	女
婷婷	B	女

4.創建hive表並導入數據

create table emp_sex(
name string, 
dept_id string, 
sex string) 
row format delimited fields terminated by "\t";
load data local inpath '/opt/module/datas/emp_sex.txt' into table emp_sex;

5.按需求查詢數據

select 
  dept_id,
  sum(case sex when '男' then 1 else 0 end) male_count,
  sum(case sex when '女' then 1 else 0 end) female_count
from 
  emp_sex
group by
  dept_id;

6.7.2 行轉列
1.相關函數說明
CONCAT(string A/col, string B/col…):返回輸入字符串連接後的結果,支持任意個輸入字符串;
CONCAT_WS(separator, str1, str2,…):它是一個特殊形式的 CONCAT()。第一個參數剩餘參數間的分隔符。分隔符可以是與剩餘參數一樣的字符串。如果分隔符是 NULL,返回值也將爲 NULL。這個函數會跳過分隔符參數後的任何 NULL 和空字符串。分隔符將被加到被連接的字符串之間;
COLLECT_SET(col):函數只接受基本數據類型,它的主要作用是將某字段的值進行去重彙總,產生array類型字段。
2.數據準備
在這裏插入圖片描述
3.需求
把星座和血型一樣的人歸類到一起。結果如下:

射手座,A            大海|鳳姐
白羊座,A            孫悟空|豬八戒
白羊座,B            宋宋

4.創建本地constellation.txt,導入數據

[jinghang@hadoop102 datas]$ vi constellation.txt
孫悟空	白羊座	A
大海	     射手座	A
宋宋	     白羊座	B
豬八戒    白羊座	A
鳳姐	     射手座	A

5.創建hive表並導入數據

create table person_info(
name string, 
constellation string, 
blood_type string) 
row format delimited fields terminated by "\t";
load data local inpath "/opt/module/datas/constellation.txt" into table person_info;

6.按需求查詢數據
使用函數:concat_ws(’,’,collect_set(column))
說明:collect_list 不去重,collect_set 去重。 column的數據類型要求是
string

select
    t1.base,
    concat_ws('|', collect_set(t1.name)) name
from
    (select
        name,
        concat(constellation, ",", blood_type) base
    from
        person_info) t1
group by
    t1.base;

6.7.3 列轉行
1.函數說明
EXPLODE(col):將hive一列中複雜的array或者map結構拆分成多行。
LATERAL VIEW
用法:LATERAL VIEW udtf(expression) tableAlias AS columnAlias
解釋:用於和split, explode等UDTF一起使用,它能夠將一列數據拆成多行數據,在此基礎上可以對拆分後的數據進行聚合。
2.數據準備
在這裏插入圖片描述
3.需求
將電影分類中的數組數據展開。結果如下:

《疑犯追蹤》      懸疑
《疑犯追蹤》      動作
《疑犯追蹤》      科幻
《疑犯追蹤》      劇情
《Lie to me》   懸疑
《Lie to me》   警匪
《Lie to me》   動作
《Lie to me》   心理
《Lie to me》   劇情
《戰狼2》        戰爭
《戰狼2》        動作
《戰狼2》        災難

4.創建本地movie.txt,導入數據

[jinghang@hadoop102 datas]$ vi movie.txt
《疑犯追蹤》	懸疑,動作,科幻,劇情
《Lie to me》	懸疑,警匪,動作,心理,劇情
《戰狼2》	戰爭,動作,災難

5.創建hive表並導入數據

create table movie_info(
    movie string, 
    category array<string>) 
row format delimited fields terminated by "\t"
collection items terminated by ",";
load data local inpath "/opt/module/datas/movie.txt" into table movie_info;

6.按需求查詢數據

select
    movie,
    category_name
from 
movie_info lateral view explode(category) table_tmp as category_name;
 lateral view explode(category) table_tmp as category_name此爲固定格式,不可更改
table_tmp,相當於這個數組拆分過後的每一個元素,as category_name爲起別名

6.7.4 窗口函數(開窗函數)
1.相關函數說明
OVER():指定分析函數工作的數據窗口大小,這個數據窗口大小可能會隨着行的變而變化。
CURRENT ROW:當前行
n PRECEDING:往前n行數據
n FOLLOWING:往後n行數據
UNBOUNDED:起點,UNBOUNDED PRECEDING 表示從前面的起點, UNBOUNDED FOLLOWING表示到後面的終點
LAG(col,n,default_val):往前第n行數據
LEAD(col,n, default_val):往後第n行數據
NTILE(n):把有序分區中的行分發到指定數據的組中,各個組有編號,編號從1開始,對於每一行,NTILE返回此行所屬的組的編號。注意:n必須爲int類型。
2.數據準備:name,orderdate,cost

jack,2017-01-01,10
tony,2017-01-02,15
jack,2017-02-03,23
tony,2017-01-04,29
jack,2017-01-05,46
jack,2017-04-06,42
tony,2017-01-07,50
jack,2017-01-08,55
mart,2017-04-08,62
mart,2017-04-09,68
neil,2017-05-10,12
mart,2017-04-11,75
neil,2017-06-12,80
mart,2017-04-13,94

3.需求
(1)查詢在2017年4月份購買過的顧客及總人數
(2)查詢顧客的購買明細及月購買總額
(3)上述的場景, 將每個顧客的cost按照日期進行累加
(4)查詢每個顧客上次的購買時間
(5)查詢前20%時間的訂單信息
4.創建本地business.txt,導入數據

[jinghang@hadoop102 datas]$ vi business.txt

5.創建hive表並導入數據

create table business(
name string, 
orderdate string,
cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
load data local inpath "/opt/module/datas/business.txt" into table business;

6.按需求查詢數據
(1)查詢在2017年4月份購買過的顧客及總人數

select name,count(*) over () 
from business 
where substring(orderdate,1,7) = '2017-04' 
group by name;

(2)查詢顧客的購買明細及月購買總額
不加 partition by 的話則把整個數據集當作一個分區,不加 order by的話會對某些函數統計結果產生影響,如sum()

select name,orderdate,cost,sum(cost) over(partition by month(orderdate)) from
 business;

(3)上述的場景, 將每個顧客的cost按照日期進行累加
select name,orderdate,cost,
sum(cost) over() as sample1,–所有行相加
sum(cost) over(partition by name) as sample2,–按name分組,組內數據相加
sum(cost) over(partition by name order by orderdate) as sample3,–按name分組,組內數據累加
sum(cost) over(partition by name order by orderdate rows between UNBOUNDED PRECEDING and current row ) as sample4 ,–和sample3一樣,由起點到當前行的聚合
sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING and current row) as sample5, --當前行和前面一行做聚合
sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING AND 1 FOLLOWING ) as sample6,–當前行和前邊一行及後面一行
sum(cost) over(partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING ) as sample7 --當前行及後面所有行
from business;
rows必須跟在Order by 子句之後,對排序的結果進行限制,使用固定的行數來限制分區中的數據行數量

(4)查看顧客上次的購買時間

select name,orderdate,cost, 
lag(orderdate,1,'1900-01-01') over(partition by name order by orderdate ) as time1, lag(orderdate,2) over (partition by name order by orderdate) as time2 
from business;

(5)查詢前20%時間的訂單信息

select * from (
    select name,orderdate,cost, ntile(5) over(order by orderdate) sorted
    from business
) t
where sorted = 1;

6.7.5 Rank
1.函數說明
RANK() 排序相同時會重複,總數不會變
DENSE_RANK() 排序相同時會重複,總數會減少
ROW_NUMBER() 會根據順序計算
2.數據準備
在這裏插入圖片描述
3.需求
計算每門學科成績排名。
4.創建本地score.txt,導入數據

[jinghang@hadoop102 datas]$ vi score.txt

5.創建hive表並導入數據

create table score(
name string,
subject string, 
score int) 
row format delimited fields terminated by "\t";
load data local inpath '/opt/module/datas/score.txt' into table score;

6.按需求查詢數據

select name,
subject,
score,
rank() over(partition by subject order by score desc) rp,
dense_rank() over(partition by subject order by score desc) drp,
row_number() over(partition by subject order by score desc) rmp
from score;


name    subject score   rp      drp     rmp
孫悟空  數學    95      1       1       1
宋宋    數學    86      2       2       2
婷婷    數學    85      3       3       3
大海    數學    56      4       4       4
宋宋    英語    84      1       1       1
大海    英語    84      1       1       2
婷婷    英語    78      3       2       3
孫悟空  英語    68      4       3       4
大海    語文    94      1       1       1
孫悟空  語文    87      2       2       2
婷婷    語文    65      3       3       3
宋宋    語文    64      4       4       4

擴展:求出每門學科前三名的學生?

第7章 函數

7.1 系統內置函數
1.查看系統自帶的函數

hive> show functions;

2.顯示自帶的函數的用法

hive> desc function upper;

3.詳細顯示自帶的函數的用法

hive> desc function extended upper;

7.2 自定義函數
1)Hive 自帶了一些函數,比如:max/min等,但是數量有限,自己可以通過自定義UDF來方便的擴展。
2)當Hive提供的內置函數無法滿足你的業務處理需要時,此時就可以考慮使用用戶自定義函數(UDF:user-defined function)。
3)根據用戶自定義函數類別分爲以下三種:
(1)UDF(User-Defined-Function)
一進一出

(2)UDAF(User-Defined Aggregation Function)
聚集函數,多進一出

類似於:count/max/min

**(3)UDTF(User-Defined Table-Generating Functions)
	一進多出**
	`
	如lateral view explore()
	`

4)官方文檔地址
https://cwiki.apache.org/confluence/display/Hive/HivePlugins

5)編程步驟:
(1)繼承org.apache.hadoop.hive.ql.exec.UDF
(2)需要實現evaluate函數;evaluate函數支持重載;
(3)在hive的命令行窗口創建函數
a)添加jar

add jar linux_jar_path

b)創建function

create [temporary] function [dbname.]function_name AS class_name;

(4)在hive的命令行窗口刪除函數

Drop [temporary] function [if exists] [dbname.]function_name;

6)注意事項
(1)UDF必須要有返回類型,可以返回null,但是返回類型不能爲void;

7.3 自定義UDF函數
1.創建一個Maven工程Hive
2.導入依賴

<dependencies>
		<!-- https://mvnrepository.com/artifact/org.apache.hive/hive-exec -->
		<dependency>
			<groupId>org.apache.hive</groupId>
			<artifactId>hive-exec</artifactId>
			<version>1.2.1</version>
		</dependency>
</dependencies>

3.創建一個類

package com.jinghang.hive;
import org.apache.hadoop.hive.ql.exec.UDF;

public class Lower extends UDF {

	public String evaluate (final String s) {
		
		if (s == null) {
			return null;
		}
		
		return s.toLowerCase();
	}
}

4.打成jar包上傳到服務器/opt/module/jars/udf.jar
5.將jar包添加到hive的classpath

hive (default)> add jar /opt/module/datas/udf.jar;

6.創建臨時函數與開發好的java class關聯

hive (default)> create temporary function mylower as "com.jinghang.hive.Lower";

7.即可在hql中使用自定義的函數strip

hive (default)> select ename, mylower(ename) lowername from emp;

第8章 壓縮和存儲

8.1 Hadoop源碼編譯支持Snappy壓縮

8.1.1 資源準備
1.CentOS聯網
配置CentOS能連接外網。Linux虛擬機ping www.baidu.com 是暢通的
注意:採用root角色編譯,減少文件夾權限出現問題

2.jar包準備(hadoop源碼、JDK8 、maven、protobuf)
(1)hadoop-2.7.2-src.tar.gz
(2)jdk-8u144-linux-x64.tar.gz
(3)snappy-1.1.3.tar.gz
(4)apache-maven-3.0.5-bin.tar.gz
(5)protobuf-2.5.0.tar.gz

8.1.2 jar包安裝
注意:所有操作必須在root用戶下完成
1.JDK解壓、配置環境變量JAVA_HOME和PATH,驗證java-version(如下都需要驗證是否配置成功)

[root@hadoop101 software] # tar -zxf jdk-8u144-linux-x64.tar.gz -C /opt/module/
[root@hadoop101 software]# vi /etc/profile
#JAVA_HOME
export JAVA_HOME=/opt/module/jdk1.8.0_144
export PATH=$PATH:$JAVA_HOME/bin
[root@hadoop101 software]#source /etc/profile

驗證命令:java -version
2.Maven解壓、配置 MAVEN_HOME和PATH

[root@hadoop101 software]# tar -zxvf apache-maven-3.0.5-bin.tar.gz -C /opt/module/
[root@hadoop101 apache-maven-3.0.5]# vi /etc/profile
#MAVEN_HOME
export MAVEN_HOME=/opt/module/apache-maven-3.0.5
export PATH=$PATH:$MAVEN_HOME/bin
[root@hadoop101 software]#source /etc/profile

驗證命令:mvn -version
8.1.3 編譯源碼
1.準備編譯環境

[root@hadoop101 software]# yum install svn
[root@hadoop101 software]# yum install autoconf automake libtool cmake
[root@hadoop101 software]# yum install ncurses-devel
[root@hadoop101 software]# yum install openssl-devel
[root@hadoop101 software]# yum install gcc*

2.編譯安裝snappy

[root@hadoop101 software]# tar -zxvf snappy-1.1.3.tar.gz -C /opt/module/
[root@hadoop101 module]# cd snappy-1.1.3/
[root@hadoop101 snappy-1.1.3]# ./configure
[root@hadoop101 snappy-1.1.3]# make
[root@hadoop101 snappy-1.1.3]# make install


# 查看snappy庫文件
[root@hadoop101 snappy-1.1.3]# ls -lh /usr/local/lib |grep snappy

3.編譯安裝protobuf

[root@hadoop101 software]# tar -zxvf protobuf-2.5.0.tar.gz -C /opt/module/
[root@hadoop101 module]# cd protobuf-2.5.0/
[root@hadoop101 protobuf-2.5.0]# ./configure 
[root@hadoop101 protobuf-2.5.0]#  make 
[root@hadoop101 protobuf-2.5.0]#  make install
# 查看protobuf版本以測試是否安裝成功
[root@hadoop101 protobuf-2.5.0]# protoc --version

4.編譯hadoop native

[root@hadoop101 software]# tar -zxvf hadoop-2.7.2-src.tar.gz
[root@hadoop101 software]# cd hadoop-2.7.2-src/
[root@hadoop101 software]# mvn clean package -DskipTests -Pdist,native -Dtar -Dsnappy.lib=/usr/local/lib -Dbundle.snappy
執行成功後,/opt/software/hadoop-2.7.2-src/hadoop-dist/target/hadoop-2.7.2.tar.gz即爲新生成的支持snappy壓縮的二進制安裝包。

8.2 Hadoop壓縮配置
8.2.1 MR支持的壓縮編碼
在這裏插入圖片描述
爲了支持多種壓縮/解壓縮算法,Hadoop引入了編碼/解碼器,如下表所示:
在這裏插入圖片描述
壓縮性能的比較:
在這裏插入圖片描述

http://google.github.io/snappy/
On a single core of a Core i7 processor in 64-bit mode, Snappy compresses at about 250 MB/sec or more and decompresses at about 500 MB/sec or more.

8.2.2 壓縮參數配置
要在Hadoop中啓用壓縮,可以配置如下參數(mapred-site.xml文件中):
在這裏插入圖片描述
在這裏插入圖片描述
8.3 開啓Map輸出階段壓縮
開啓map輸出階段壓縮可以減少job中map和Reduce task間數據傳輸量。具體配置如下:
案例實操:
1.開啓hive中間傳輸數據壓縮功能

hive (default)>set hive.exec.compress.intermediate=true;

2.開啓mapreduce中map輸出壓縮功能

hive (default)>set mapreduce.map.output.compress=true;

3.設置mapreduce中map輸出數據的壓縮方式

hive (default)>set mapreduce.map.output.compress.codec=
 org.apache.hadoop.io.compress.SnappyCodec;

4.執行查詢語句

hive (default)> select count(ename) name from emp;

8.4 開啓Reduce輸出階段壓縮
當Hive將輸出寫入到表中時,輸出內容同樣可以進行壓縮。屬性hive.exec.compress.output控制着這個功能。用戶可能需要保持默認設置文件中的默認值false,這樣默認的輸出就是非壓縮的純文本文件了。用戶可以通過在查詢語句或執行腳本中設置這個值爲true,來開啓輸出結果壓縮功能。
案例實操:
1.開啓hive最終輸出數據壓縮功能

hive (default)>set hive.exec.compress.output=true;

2.開啓mapreduce最終輸出數據壓縮

hive (default)>set mapreduce.output.fileoutputformat.compress=true;

3.設置mapreduce最終數據輸出壓縮方式

hive (default)> set mapreduce.output.fileoutputformat.compress.codec =
 org.apache.hadoop.io.compress.SnappyCodec;

4.設置mapreduce最終數據輸出壓縮爲塊壓縮

hive (default)> set mapreduce.output.fileoutputformat.compress.type=BLOCK;

5.測試一下輸出結果是否是壓縮文件

hive (default)> insert overwrite local directory
 '/opt/module/datas/distribute-result' select * from emp distribute by deptno sort by empno desc;

8.5 文件存儲格式
Hive支持的存儲數據的格式主要有:TEXTFILE 、SEQUENCEFILE、ORC、PARQUET。
8.5.1 列式存儲和行式存儲
在這裏插入圖片描述

		 		圖6-10 列式存儲和行式存儲

如圖6-10所示左邊爲邏輯表,右邊第一個爲行式存儲,第二個爲列式存儲。
1.行存儲的特點
查詢滿足條件的一整行數據的時候,列存儲則需要去每個聚集的字段找到對應的每個列的值,行存儲只需要找到其中一個值,其餘的值都在相鄰地方,所以此時行存儲查詢的速度更快。
2.列存儲的特點
因爲每個字段的數據聚集存儲,在查詢只需要少數幾個字段的時候,能大大減少讀取的數據量;每個字段的數據類型一定是相同的,列式存儲可以針對性的設計更好的設計壓縮算法。

TEXTFILE和SEQUENCEFILE的存儲格式都是基於行存儲的;
ORC和PARQUET是基於列式存儲的。

8.5.2 TextFile格式
默認格式,數據不做壓縮,磁盤開銷大,數據解析開銷大。可結合Gzip、Bzip2使用,但使用Gzip這種方式,hive不會對數據進行切分,從而無法對數據進行並行操作。

8.5.3 Orc格式
Orc (Optimized Row Columnar)是Hive 0.11版裏引入的新的存儲格式。
如圖6-11所示可以看到每個Orc文件由1個或多個stripe組成,每個stripe一般爲HDFS的塊大小,每一個stripe包含多條記錄,這些記錄按照列進行獨立存儲,對應到Parquet中的row group的概念。每個Stripe裏有三部分組成,分別是Index Data,Row Data,Stripe Footer:
在這裏插入圖片描述

					圖6-11 Orc格式

1)Index Data:一個輕量級的index,默認是每隔1W行做一個索引。這裏做的索引應該只是記錄某行的各字段在Row Data中的offset。
2)Row Data:存的是具體的數據,先取部分行,然後對這些行按列進行存儲。對每個列進行了編碼,分成多個Stream來存儲
3)Stripe Footer:存的是各個Stream的類型,長度等信息。
每個文件有一個File Footer,這裏面存的是每個Stripe的行數,每個Column的數據類型信息等;每個文件的尾部是一個PostScript,這裏面記錄了整個文件的壓縮類型以及FileFooter的長度信息等。在讀取文件時,會seek到文件尾部讀PostScript,從裏面解析到File Footer長度,再讀FileFooter,從裏面解析到各個Stripe信息,再讀各個Stripe,即從後往前讀。

8.5.4 Parquet格式
Parquet文件是以二進制方式存儲的,所以是不可以直接讀取的,文件中包括該文件的數據和元數據,因此Parquet格式文件是自解析的
1)行組(Row Group):每一個行組包含一定的行數,在一個HDFS文件中至少存儲一個行組,類似於orc的stripe的概念。
2)列塊(Column Chunk):在一個行組中每一列保存在一個列塊中,行組中的所有列連續的存儲在這個行組文件中。一個列塊中的值都是相同類型的,不同的列塊可能使用不同的算法進行壓縮。
3)頁(Page):每一個列塊劃分爲多個頁,一個頁是最小的編碼的單位,在同一個列塊的不同頁可能使用不同的編碼方式。
通常情況下,在存儲Parquet數據的時候會按照Block大小設置行組的大小,由於一般情況下每一個Mapper任務處理數據的最小單位是一個Block,這樣可以把每一個行組由一個Mapper任務處理,增大任務執行並行度。Parquet文件的格式如圖6-12所示。
在這裏插入圖片描述

				圖6-12  Parquet格式

上圖展示了一個Parquet文件的內容,一個文件中可以存儲多個行組,文件的首位都是該文件的Magic Code,用於校驗它是否是一個Parquet文件,Footer length記錄了文件元數據的大小,通過該值和文件長度可以計算出元數據的偏移量,文件的元數據中包括每一個行組的元數據信息和該文件存儲數據的Schema信息。除了文件中每一個行組的元數據,每一頁的開始都會存儲該頁的元數據,在Parquet中,有三種類型的頁:數據頁、字典頁和索引頁。數據頁用於存儲當前行組中該列的值,字典頁存儲該列值的編碼字典,每一個列塊中最多包含一個字典頁,索引頁用來存儲當前行組下該列的索引,目前Parquet中還不支持索引頁。

8.5.5 主流文件存儲格式對比實驗
從存儲文件的壓縮比和查詢速度兩個角度對比。
存儲文件的壓縮比測試:
1.測試數據
在這裏插入圖片描述
2.TextFile
(1)創建表,存儲數據格式爲TEXTFILE

create table log_text (
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by '\t'
stored as textfile ;

(2)向表中加載數據

hive (default)> load data local inpath '/opt/module/datas/log.data' into table log_text ;

(3)查看錶中數據大小

hive (default)> dfs -du -h /user/hive/warehouse/log_text;
18.1 M  /user/hive/warehouse/log_text/log.data

3.ORC
(1)創建表,存儲數據格式爲ORC

create table log_orc(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by '\t'
stored as orc ;

(2)向表中加載數據

hive (default)> insert into table log_orc select * from log_text ;

(3)查看錶中數據大小

hive (default)> dfs -du -h /user/hive/warehouse/log_orc/ ;
2.8 M  /user/hive/warehouse/log_orc/000000_0

4.Parquet
(1)創建表,存儲數據格式爲parquet

create table log_parquet(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by '\t'
stored as parquet ;	

(2)向表中加載數據

hive (default)> insert into table log_parquet select * from log_text ;

(3)查看錶中數據大小

hive (default)> dfs -du -h /user/hive/warehouse/log_parquet/ ;
13.1 M  /user/hive/warehouse/log_parquet/000000_0

存儲文件的壓縮比總結:
ORC > Parquet > textFile
存儲文件的查詢速度測試:
1.TextFile

hive (default)> select count(*) from log_text;
_c0
100000
Time taken: 21.54 seconds, Fetched: 1 row(s)
Time taken: 21.08 seconds, Fetched: 1 row(s)
Time taken: 19.298 seconds, Fetched: 1 row(s)

2.ORC

hive (default)> select count(*) from log_orc;
_c0
100000
Time taken: 20.867 seconds, Fetched: 1 row(s)
Time taken: 22.667 seconds, Fetched: 1 row(s)
Time taken: 18.36 seconds, Fetched: 1 row(s)

3.Parquet

hive (default)> select count(*) from log_parquet;
_c0
100000
Time taken: 22.922 seconds, Fetched: 1 row(s)
Time taken: 21.074 seconds, Fetched: 1 row(s)
Time taken: 18.384 seconds, Fetched: 1 row(s)

存儲文件的查詢速度總結:查詢速度相近。

8.6 存儲和壓縮結合
8.6.1 修改Hadoop集羣具有Snappy壓縮方式
1.查看hadoop checknative命令使用

[jinghang@hadoop104 hadoop-2.7.2]$ hadoop
  		checknative [-a|-h]  check native hadoop and compression libraries availability

2.查看hadoop支持的壓縮方式

[jinghang@hadoop104 hadoop-2.7.2]$ hadoop checknative
17/12/24 20:32:52 WARN bzip2.Bzip2Factory: Failed to load/initialize native-bzip2 library system-native, will use pure-Java version
17/12/24 20:32:52 INFO zlib.ZlibFactory: Successfully loaded & initialized native-zlib library
Native library checking:
hadoop:  true /opt/module/hadoop-2.7.2/lib/native/libhadoop.so
zlib:    true /lib64/libz.so.1
snappy:  false 
lz4:     true revision:99
bzip2:   false

3.將編譯好的支持Snappy壓縮的hadoop-2.7.2.tar.gz包導入到hadoop102的/opt/software中
4.解壓hadoop-2.7.2.tar.gz到當前路徑

[jinghang@hadoop102 software]$ tar -zxvf hadoop-2.7.2.tar.gz

5.進入到/opt/software/hadoop-2.7.2/lib/native路徑可以看到支持Snappy壓縮的動態鏈接庫

[jinghang@hadoop102 native]$ pwd
/opt/software/hadoop-2.7.2/lib/native
[jinghang@hadoop102 native]$ ll
-rw-r--r--. 1 jinghang jinghang  472950 9月   1 10:19 libsnappy.a
-rwxr-xr-x. 1 jinghang jinghang     955 9月   1 10:19 libsnappy.la
lrwxrwxrwx. 1 jinghang jinghang      18 12月 24 20:39 libsnappy.so -> libsnappy.so.1.3.0
lrwxrwxrwx. 1 jinghang jinghang      18 12月 24 20:39 libsnappy.so.1 -> libsnappy.so.1.3.0
-rwxr-xr-x. 1 jinghang jinghang  228177 9月   1 10:19 libsnappy.so.1.3.0

6.拷貝/opt/software/hadoop-2.7.2/lib/native裏面的所有內容到開發集羣的/opt/module/hadoop-2.7.2/lib/native路徑上

[jinghang@hadoop102 native]$ cp ../native/* /opt/module/hadoop-2.7.2/lib/native/

7.分發集羣

[jinghang@hadoop102 lib]$ xsync native/

8.再次查看hadoop支持的壓縮類型

[jinghang@hadoop102 hadoop-2.7.2]$ hadoop checknative
17/12/24 20:45:02 WARN bzip2.Bzip2Factory: Failed to load/initialize native-bzip2 library system-native, will use pure-Java version
17/12/24 20:45:02 INFO zlib.ZlibFactory: Successfully loaded & initialized native-zlib library
Native library checking:
hadoop:  true /opt/module/hadoop-2.7.2/lib/native/libhadoop.so
zlib:    true /lib64/libz.so.1
snappy:  true /opt/module/hadoop-2.7.2/lib/native/libsnappy.so.1
lz4:     true revision:99
bzip2:   false

9.重新啓動hadoop集羣和hive

8.6.2 測試存儲和壓縮
官網:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+ORC

ORC存儲方式的壓縮:

1.創建一個非壓縮的的ORC存儲方式
(1)建表語句

create table log_orc_none(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by '\t'
stored as orc tblproperties ("orc.compress"="NONE");

(2)插入數據

hive (default)> insert into table log_orc_none select * from log_text ;

(3)查看插入後數據

hive (default)> dfs -du -h /user/hive/warehouse/log_orc_none/ ;

7.7 M /user/hive/warehouse/log_orc_none/000000_0

2.創建一個SNAPPY壓縮的ORC存儲方式
(1)建表語句

create table log_orc_snappy(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by '\t'
stored as orc tblproperties ("orc.compress"="SNAPPY");
(2)插入數據
hive (default)> insert into table log_orc_snappy select * from log_text ;
	

(3)查看插入後數據

hive (default)> dfs -du -h /user/hive/warehouse/log_orc_snappy/ ;
3.8 M  /user/hive/warehouse/log_orc_snappy/000000_0

3.上一節中默認創建的ORC存儲方式,導入數據後的大小爲
2.8 M /user/hive/warehouse/log_orc/000000_0
比Snappy壓縮的還小。原因是orc存儲文件默認採用ZLIB壓縮,ZLIB採用的是deflate壓縮算法。比snappy壓縮的小。

4.存儲方式和壓縮總結
在實際的項目開發當中,hive表的數據存儲格式一般選擇:orc或parquet。壓縮方式一般選擇snappy,lzo。

第9章 企業級調優

9.1 Fetch抓取
Fetch抓取是指,Hive中對某些情況的查詢可以不必使用MapReduce計算。例如:SELECT * FROM employees;在這種情況下,Hive可以簡單地讀取employee對應的存儲目錄下的文件,然後輸出查詢結果到控制檯。
在hive-default.xml.template文件中hive.fetch.task.conversion默認是more,老版本hive默認是minimal,該屬性修改爲more以後,在全局查找、字段查找、limit查找等都不走mapreduce。

<property>
    <name>hive.fetch.task.conversion</name>
    <value>more</value>
    <description>
      Expects one of [none, minimal, more].
      Some select queries can be converted to single FETCH task minimizing latency.
      Currently the query should be single sourced not having any subquery and should not have any aggregations or distincts (which incurs RS), lateral views and joins.
      0. none : disable hive.fetch.task.conversion
      1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only
      2. more  : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)
    </description>
  </property>

案例實操:
1)把hive.fetch.task.conversion設置成none,然後執行查詢語句,都會執行mapreduce程序。

hive (default)> set hive.fetch.task.conversion=none;
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;

2)把hive.fetch.task.conversion設置成more,然後執行查詢語句,如下查詢方式都不會執行mapreduce程序。

hive (default)> set hive.fetch.task.conversion=more;
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;

9.2 本地模式
大多數的Hadoop Job是需要Hadoop提供的完整的可擴展性來處理大數據集的。不過,有時Hive的輸入數據量是非常小的。在這種情況下,爲查詢觸發執行任務消耗的時間可能會比實際job的執行時間要多的多。對於大多數這種情況,Hive可以通過本地模式在單臺機器上處理所有的任務。對於小數據集,執行時間可以明顯被縮短。
用戶可以通過設置hive.exec.mode.local.auto的值爲true,來讓Hive在適當的時候自動啓動這個優化,默認是false。

set hive.exec.mode.local.auto=true;  //開啓本地mr

//設置local mr的最大輸入數據量,當輸入數據量小於這個值時採用local mr的方式,默認爲134217728,即128M

set hive.exec.mode.local.auto.inputbytes.max=50000000;

//設置local mr的最大輸入文件個數,當輸入文件個數小於這個值時採用local mr的方式,默認爲4

set hive.exec.mode.local.auto.input.files.max=10;

案例實操:
1)開啓本地模式,並執行查詢語句

hive (default)> set hive.exec.mode.local.auto=true; 
hive (default)> select * from emp cluster by deptno;
Time taken: 1.328 seconds, Fetched: 14 row(s)

2)關閉本地模式,並執行查詢語句

hive (default)> set hive.exec.mode.local.auto=false; 
hive (default)> select * from emp cluster by deptno;
Time taken: 20.09 seconds, Fetched: 14 row(s)

9.3 表的優化
9.3.1 小表、大表Join
將key相對分散,並且數據量小的表放在join的左邊,這樣可以有效減少內存溢出錯誤發生的機率;再進一步,可以使用map join讓小的維度表(1000條以下的記錄條數)先進內存。在map端完成reduce。
實際測試發現:新版的hive已經對小表JOIN大表和大表JOIN小表進行了優化。小表放在左邊和右邊已經沒有明顯區別。
案例實操
1.需求
測試大表JOIN小表和小表JOIN大表的效率
2.建大表、小表和JOIN後表的語句

// 創建大表
create table bigtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
// 創建小表
create table smalltable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
// 創建join後表的語句
create table jointable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';

3.分別向大表和小表中導入數據

hive (default)> load data local inpath '/opt/module/datas/bigtable' into table bigtable;
hive (default)>load data local inpath '/opt/module/datas/smalltable' into table smalltable;

4.關閉mapjoin功能(默認是打開的)

set hive.auto.convert.join = false;

5.執行小表JOIN大表語句

insert overwrite table jointable
select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from smalltable s
left join bigtable  b
on b.id = s.id;
Time taken: 35.921 seconds
No rows affected (44.456 seconds)

6.執行大表JOIN小表語句

insert overwrite table jointable
select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable  b
left join smalltable  s
on s.id = b.id;
Time taken: 34.196 seconds
No rows affected (26.287 seconds)

9.3.2 大表Join大表
1.空KEY過濾
有時join超時是因爲某些key對應的數據太多,而相同key對應的數據都會發送到相同的reducer上,從而導致內存不夠。此時我們應該仔細分析這些異常的key,很多情況下,這些key對應的數據是異常數據,我們需要在SQL語句中進行過濾。例如key對應的字段爲空,操作如下:
案例實操
(1)配置歷史服務器
配置mapred-site.xml

<property>
<name>mapreduce.jobhistory.address</name>
<value>hadoop102:10020</value>
</property>
<property>
    <name>mapreduce.jobhistory.webapp.address</name>
    <value>hadoop102:19888</value>
</property>

啓動歷史服務器

sbin/mr-jobhistory-daemon.sh start historyserver

查看jobhistory
http://hadoop102:19888/jobhistory

(2)創建原始數據表、空id表、合併後數據表

// 創建原始表
create table ori(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
// 創建空id表
create table nullidtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
// 創建join後表的語句
create table jointable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';

(3)分別加載原始數據和空id數據到對應表中

hive (default)> load data local inpath '/opt/module/datas/ori' into table ori;
hive (default)> load data local inpath '/opt/module/datas/nullid' into table nullidtable;

(4)測試不過濾空id

hive (default)> insert overwrite table jointable select n.* from nullidtable n
left join ori o on n.id = o.id;
Time taken: 42.038 seconds
Time taken: 37.284 seconds

(5)測試過濾空id

hive (default)> insert overwrite table jointable select n.* from (select * from nullidtable where id is not null ) n  left join ori o on n.id = o.id;
Time taken: 31.725 seconds
Time taken: 28.876 seconds

2.空key轉換
有時雖然某個key爲空對應的數據很多,但是相應的數據不是異常數據,必須要包含在join的結果中,此時我們可以表a中key爲空的字段賦一個隨機的值,使得數據隨機均勻地分不到不同的reducer上。例如:
案例實操:
不隨機分佈空null值:
(1)設置5個reduce個數

set mapreduce.job.reduces = 5;

(2)JOIN兩張表

insert overwrite table jointable
select n.* from nullidtable n left join ori b on n.id = b.id;

結果:如圖6-13所示,可以看出來,出現了數據傾斜,某些reducer的資源消耗遠大於其他reducer。
在這裏插入圖片描述

						圖6-13 空key轉換

隨機分佈空null值
(1)設置5個reduce個數

set mapreduce.job.reduces = 5;

(2)JOIN兩張表

insert overwrite table jointable
select n.* from nullidtable n full join ori o on 
case when n.id is null then concat('hive', rand()) else n.id end = o.id;

結果:如圖6-14所示,可以看出來,消除了數據傾斜,負載均衡reducer的資源消耗
在這裏插入圖片描述

					圖6-14 隨機分佈空值

9.3.3 MapJoin(小表join大表)
如果不指定MapJoin或者不符合MapJoin的條件,那麼Hive解析器會將Join操作轉換成Common Join,即:在Reduce階段完成join。容易發生數據傾斜。可以用MapJoin把小表全部加載到內存在map端進行join,避免reducer處理。
1.開啓MapJoin參數設置
(1)設置自動選擇Mapjoin

set hive.auto.convert.join = true; 默認爲true

(2)大表小表的閾值設置(默認25M一下認爲是小表):

set hive.mapjoin.smalltable.filesize=25000000;

2.MapJoin工作機制,如圖6-15所示在這裏插入圖片描述

				圖6-15  MapJoin工作機制

案例實操:
(1)開啓Mapjoin功能

set hive.auto.convert.join = true; 默認爲true

(2)執行小表JOIN大表語句

insert overwrite table jointable
select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from smalltable s
join bigtable  b
on s.id = b.id;
Time taken: 24.594 seconds

(3)執行大表JOIN小表語句

insert overwrite table jointable
select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable  b
join smalltable  s
on s.id = b.id;
Time taken: 24.315 seconds

9.3.4 Group By

默認情況下,Map階段同一Key數據分發給一個reduce,當一個key數據過大時就傾斜了。
在這裏插入圖片描述
並不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端進行部分聚合,最後在Reduce端得出最終結果。
1.開啓Map端聚合參數設置
(1)是否在Map端進行聚合,默認爲True

set hive.map.aggr = true

(2)在Map端進行聚合操作的條目數目

set hive.groupby.mapaggr.checkinterval = 100000

(3)有數據傾斜的時候進行負載均衡(默認是false)

set hive.groupby.skewindata = true

當選項設定爲 true,生成的查詢計劃會有兩個MR Job。第一個MR Job中,Map的輸出結果會隨機分佈到Reduce中,每個Reduce做部分聚合操作,並輸出結果,這樣處理的結果是相同的Group By Key有可能被分發到不同的Reduce中,從而達到負載均衡的目的;第二個MR Job再根據預處理的數據結果按照Group By Key分佈到Reduce中(這個過程可以保證相同的Group By Key被分佈到同一個Reduce中),最後完成最終的聚合操作。

hive (default)> select deptno from emp group by deptno;
Stage-Stage-1: Map: 1  Reduce: 5   Cumulative CPU: 23.68 sec   HDFS Read: 19987 HDFS Write: 9 SUCCESS
Total MapReduce CPU Time Spent: 23 seconds 680 msec
OK
deptno
10
20
30

優化以後

hive (default)> set hive.groupby.skewindata = true;
hive (default)> select deptno from emp group by deptno;
Stage-Stage-1: Map: 1  Reduce: 5   Cumulative CPU: 28.53 sec   HDFS Read: 18209 HDFS Write: 534 SUCCESS
Stage-Stage-2: Map: 1  Reduce: 5   Cumulative CPU: 38.32 sec   HDFS Read: 15014 HDFS Write: 9 SUCCESS
Total MapReduce CPU Time Spent: 1 minutes 6 seconds 850 msec
OK
deptno
10
20
30

9.3.5 Count(Distinct) 去重統計
數據量小的時候無所謂,數據量大的情況下,由於COUNT DISTINCT的全聚合操作,即使設定了reduce task個數,set mapred.reduce.tasks=100;hive也只會啓動一個reducer。,這就造成一個Reduce處理的數據量太大,導致整個Job很難完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替換:
案例實操
1.創建一張大表

hive (default)> create table bigtable(id bigint, time bigint, uid string, keyword
string, url_rank int, click_num int, click_url string) row format delimited
fields terminated by '\t';

2.加載數據

hive (default)> load data local inpath '/opt/module/datas/bigtable' into table
 bigtable;

3.設置5個reduce個數

set mapreduce.job.reduces = 5;

4.執行去重id查詢

hive (default)> select count(distinct id) from bigtable;
Stage-Stage-1: Map: 1  Reduce: 1   Cumulative CPU: 7.12 sec   HDFS Read: 120741990 HDFS Write: 7 SUCCESS
Total MapReduce CPU Time Spent: 7 seconds 120 msec
OK
c0
100001
Time taken: 23.607 seconds, Fetched: 1 row(s)

5.採用GROUP by去重id

hive (default)> select count(id) from (select id from bigtable group by id) a;
Stage-Stage-1: Map: 1  Reduce: 5   Cumulative CPU: 17.53 sec   HDFS Read: 120752703 HDFS Write: 580 SUCCESS
Stage-Stage-2: Map: 1  Reduce: 1   Cumulative CPU: 4.29 sec   HDFS Read: 9409 HDFS Write: 7 SUCCESS
Total MapReduce CPU Time Spent: 21 seconds 820 msec
OK
_c0
100001
Time taken: 50.795 seconds, Fetched: 1 row(s)

雖然會多用一個Job來完成,但在數據量大的情況下,這個絕對是值得的。

9.3.6 笛卡爾積
儘量避免笛卡爾積,join的時候不加on條件,或者無效的on條件,Hive只能使用1個reducer來完成笛卡爾積。

9.3.7 行列過濾
列處理:在SELECT中,只拿需要的列,如果有,儘量使用分區過濾,少用SELECT *。
行處理:在分區剪裁中,當使用外關聯時,如果將副表的過濾條件寫在Where後面,那麼就會先全表關聯,之後再過濾,比如:
案例實操:
1.測試先關聯兩張表,再用where條件過濾

hive (default)> select o.id from bigtable b
join ori o on o.id = b.id
where o.id <= 10;
Time taken: 34.406 seconds, Fetched: 100 row(s)

2.通過子查詢後,再關聯表

hive (default)> select b.id from bigtable b
join (select id from ori where id <= 10 ) o on b.id = o.id;
Time taken: 30.058 seconds, Fetched: 100 row(s)

9.3.8 動態分區調整
關係型數據庫中,對分區表Insert數據時候,數據庫自動會根據分區字段的值,將數據插入到相應的分區中,Hive中也提供了類似的機制,即動態分區(Dynamic Partition),只不過,使用Hive的動態分區,需要進行相應的配置。
1.開啓動態分區參數設置
(1)開啓動態分區功能(默認true,開啓)

hive.exec.dynamic.partition=true

(2)設置爲非嚴格模式(動態分區的模式,默認strict,表示必須指定至少一個分區爲靜態分區,nonstrict模式表示允許所有的分區字段都可以使用動態分區。)

hive.exec.dynamic.partition.mode=nonstrict

(3)在所有執行MR的節點上,最大一共可以創建多少個動態分區。默認1000

hive.exec.max.dynamic.partitions=1000

(4)在每個執行MR的節點上,最大可以創建多少個動態分區。該參數需要根據實際的數據來設定。比如:源數據中包含了一年的數據,即day字段有365個值,那麼該參數就需要設置成大於365,如果使用默認值100,則會報錯。

hive.exec.max.dynamic.partitions.pernode=100

(5)整個MR Job中,最大可以創建多少個HDFS文件。默認100000

hive.exec.max.created.files=100000

(6)當有空分區生成時,是否拋出異常。一般不需要設置。默認false

hive.error.on.empty.partition=false

2.案例實操
需求:將dept表中的數據按照地區(loc字段),插入到目標表dept_partition的相應分區中。
(1)創建目標分區表

hive (default)> create table dept_partition(id int, name string) partitioned
by (location int) row format delimited fields terminated by '\t';

(2)設置動態分區

set hive.exec.dynamic.partition.mode = nonstrict;
hive (default)> insert into table dept_partition partition(location) select deptno, dname, loc from dept;

(3)查看目標分區表的分區情況

hive (default)> show partitions dept_partition;

思考:目標分區表是如何匹配到分區字段的?

9.3.9 分桶
詳見6.6章。

9.3.10 分區
詳見4.6章。

9.4 合理設置Map及Reduce數
1)通常情況下,作業會通過input的目錄產生一個或者多個map任務。
主要的決定因素有:input的文件總個數,input的文件大小,集羣設置的文件塊大小。
2)是不是map數越多越好?
答案是否定的。如果一個任務有很多小文件(遠遠小於塊大小128m),則每個小文件也會被當做一個塊,用一個map任務來完成,而一個map任務啓動和初始化的時間遠遠大於邏輯處理的時間,就會造成很大的資源浪費。而且,同時可執行的map數是受限的。
3)是不是保證每個map處理接近128m的文件塊,就高枕無憂了?
答案也是不一定。比如有一個127m的文件,正常會用一個map去完成,但這個文件只有一個或者兩個小字段,卻有幾千萬的記錄,如果map處理的邏輯比較複雜,用一個map任務去做,肯定也比較耗時。
針對上面的問題2和3,我們需要採取兩種方式來解決:即減少map數和增加map數;

9.4.1 複雜文件增加Map數
當input的文件都很大,任務邏輯複雜,map執行非常慢的時候,可以考慮增加Map數,來使得每個map處理的數據量減少,從而提高任務的執行效率。
增加map的方法爲:根據computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M公式,調整maxSize最大值。讓maxSize最大值低於blocksize就可以增加map的個數。
案例實操:
1.執行查詢

hive (default)> select count(*) from emp;
Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 1

2.設置最大切片值爲100個字節

hive (default)> set mapreduce.input.fileinputformat.split.maxsize=100;
hive (default)> select count(*) from emp;
Hadoop job information for Stage-1: number of mappers: 6; number of reducers: 1

9.4.2 小文件進行合併
(1)在map執行前合併小文件,減少map數:CombineHiveInputFormat具有對小文件進行合併的功能(系統默認的格式)。HiveInputFormat沒有對小文件合併功能。

set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

(2)在Map-Reduce的任務結束時合併小文件的設置:

在map-only任務結束時合併小文件,默認true

SET hive.merge.mapfiles = true;

在map-reduce任務結束時合併小文件,默認false

SET hive.merge.mapredfiles = true;

合併文件的大小,默認256M

SET hive.merge.size.per.task = 268435456;

當輸出文件的平均大小小於該值時,啓動一個獨立的map-reduce任務進行文件merge

SET hive.merge.smallfiles.avgsize = 16777216;

9.4.3 合理設置Reduce數
1.調整reduce個數方法一
(1)每個Reduce處理的數據量默認是256MB

hive.exec.reducers.bytes.per.reducer=256000000

(2)每個任務最大的reduce數,默認爲1009

hive.exec.reducers.max=1009

(3)計算reducer數的公式

N=min(參數2,總輸入數據量/參數1)

2.調整reduce個數方法二
在hadoop的mapred-default.xml文件中修改
設置每個job的Reduce個數

set mapreduce.job.reduces = 15;

3.reduce個數並不是越多越好
1)過多的啓動和初始化reduce也會消耗時間和資源;
2)另外,有多少個reduce,就會有多少個輸出文件,如果生成了很多個小文件,那麼如果這些小文件作爲下一個任務的輸入,則也會出現小文件過多的問題;
在設置reduce個數的時候也需要考慮這兩個原則:處理大數據量利用合適的reduce數;使單個reduce任務處理數據量大小要合適;

9.5 並行執行
Hive會將一個查詢轉化成一個或者多個階段。這樣的階段可以是MapReduce階段、抽樣階段、合併階段、limit階段。或者Hive執行過程中可能需要的其他階段。默認情況下,Hive一次只會執行一個階段。不過,某個特定的job可能包含衆多的階段,而這些階段可能並非完全互相依賴的,也就是說有些階段是可以並行執行的,這樣可能使得整個job的執行時間縮短。不過,如果有更多的階段可以並行執行,那麼job可能就越快完成。
通過設置參數hive.exec.parallel值爲true,就可以開啓併發執行。不過,在共享集羣中,需要注意下,如果job中並行階段增多,那麼集羣利用率就會增加。

set hive.exec.parallel=true;              //打開任務並行執行
set hive.exec.parallel.thread.number=16;  //同一個sql允許最大並行度,默認爲8。

當然,得是在系統資源比較空閒的時候纔有優勢,否則,沒資源,並行也起不來。

9.6 嚴格模式
Hive提供了一個嚴格模式,可以防止用戶執行那些可能意想不到的不好的影響的查詢。
通過設置屬性hive.mapred.mode值爲默認是非嚴格模式nonstrict 。開啓嚴格模式需要修改hive.mapred.mode值爲strict,開啓嚴格模式可以禁止3種類型的查詢。

<property>
    <name>hive.mapred.mode</name>
    <value>strict</value>
    <description>
      The mode in which the Hive operations are being performed. 
      In strict mode, some risky queries are not allowed to run. They include:
        Cartesian Product.
        No partition being picked up for a query.
        Comparing bigints and strings.
        Comparing bigints and doubles.
        Orderby without limit.
</description>
</property>

1)對於分區表,除非where語句中含有分區字段過濾條件來限制範圍,否則不允許執行。換句話說,就是用戶不允許掃描所有分區。進行這個限制的原因是,通常分區表都擁有非常大的數據集,而且數據增加迅速。沒有進行分區限制的查詢可能會消耗令人不可接受的巨大資源來處理這個表。
2)對於使用了order by語句的查詢,要求必須使用limit語句。因爲order by爲了執行排序過程會將所有的結果數據分發到同一個Reducer中進行處理,強制要求用戶增加這個LIMIT語句可以防止Reducer額外執行很長一段時間。
3)限制笛卡爾積的查詢。對關係型數據庫非常瞭解的用戶可能期望在執行JOIN查詢的時候不使用ON語句而是使用where語句,這樣關係數據庫的執行優化器就可以高效地將WHERE語句轉化成那個ON語句。不幸的是,Hive並不會執行這種優化,因此,如果表足夠大,那麼這個查詢就會出現不可控的情況。

9.7 JVM重用
JVM重用是Hadoop調優參數的內容,其對Hive的性能具有非常大的影響,特別是對於很難避免小文件的場景或task特別多的場景,這類場景大多數執行時間都很短。
Hadoop的默認配置通常是使用派生JVM來執行map和Reduce任務的。這時JVM的啓動過程可能會造成相當大的開銷,尤其是執行的job包含有成百上千task任務的情況。JVM重用可以使得JVM實例在同一個job中重新使用N次。N的值可以在Hadoop的mapred-site.xml文件中進行配置。通常在10-20之間,具體多少需要根據具體業務場景測試得出。

<property>
  <name>mapreduce.job.jvm.numtasks</name>
  <value>10</value>
  <description>How many tasks to run per jvm. If set to -1, there is
  no limit. 
  </description>
</property>

這個功能的缺點是,開啓JVM重用將一直佔用使用到的task插槽,以便進行重用,直到任務完成後才能釋放。如果某個“不平衡的”job中有某幾個reduce task執行的時間要比其他Reduce task消耗的時間多的多的話,那麼保留的插槽就會一直空閒着卻無法被其他的job使用,直到所有的task都結束了纔會釋放。

9.8 推測執行
在分佈式集羣環境下,因爲程序Bug(包括Hadoop本身的bug),負載不均衡或者資源分佈不均等原因,會造成同一個作業的多個任務之間運行速度不一致,有些任務的運行速度可能明顯慢於其他任務(比如一個作業的某個任務進度只有50%,而其他所有任務已經運行完畢),則這些任務會拖慢作業的整體執行進度。爲了避免這種情況發生,Hadoop採用了推測執行(Speculative Execution)機制,它根據一定的法則推測出“拖後腿”的任務,併爲這樣的任務啓動一個備份任務,讓該任務與原始任務同時處理同一份數據,並最終選用最先成功運行完成任務的計算結果作爲最終結果。
設置開啓推測執行參數:Hadoop的mapred-site.xml文件中進行配置,默認是true

<property>
  <name>mapreduce.map.speculative</name>
  <value>true</value>
  <description>If true, then multiple instances of some map tasks 
               may be executed in parallel.</description>
</property>

<property>
  <name>mapreduce.reduce.speculative</name>
  <value>true</value>
  <description>If true, then multiple instances of some reduce tasks 
               may be executed in parallel.</description>
</property>
不過hive本身也提供了配置項來控制reduce-side的推測執行:默認是true
  <property>
    <name>hive.mapred.reduce.tasks.speculative.execution</name>
    <value>true</value>
    <description>Whether speculative execution for reducers should be turned on. </description>
  </property>

關於調優這些推測執行變量,還很難給一個具體的建議。如果用戶對於運行時的偏差非常敏感的話,那麼可以將這些功能關閉掉。如果用戶因爲輸入數據量很大而需要執行長時間的map或者Reduce task的話,那麼啓動推測執行造成的浪費是非常巨大大。

9.9 壓縮
詳見第8章。

9.10 執行計劃(Explain)
1.基本語法
EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query
2.案例實操
(1)查看下面這條語句的執行計劃

hive (default)> explain select * from emp;
hive (default)> explain select deptno, avg(sal) avg_sal from emp group by deptno;

(2)查看詳細執行計劃
hi

ve (default)> explain extended select * from emp;
hive (default)> explain extended select deptno, avg(sal) avg_sal from emp group by deptno;

第10章 常見錯誤及解決方案

1)SecureCRT 7.3出現亂碼或者刪除不掉數據,免安裝版的SecureCRT 卸載或者用虛擬機直接操作或者換安裝版的SecureCRT
2)連接不上mysql數據庫
(1)導錯驅動包,應該把mysql-connector-java-5.1.27-bin.jar導入/opt/module/hive/lib的不是這個包。錯把mysql-connector-java-5.1.27.tar.gz導入hive/lib包下
(2)修改user表中的主機名稱沒有都修改爲%,而是修改爲localhost
3)hive默認的輸入格式處理是CombineHiveInputFormat,會對小文件進行合併。

hive (default)> set hive.input.format;
hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat

可以採用HiveInputFormat就會根據分區數輸出相應的文件。

hive (default)> set hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;

4)不能執行mapreduce程序
可能是hadoop的yarn沒開啓。
5)啓動mysql服務時,報MySQL server PID file could not be found! 異常。
在/var/lock/subsys/mysql路徑下創建hadoop102.pid,並在文件中添加內容:4396
6)報service mysql status MySQL is not running, but lock file (/var/lock/subsys/mysql[失敗])異常。
解決方案:在/var/lib/mysql 目錄下創建: -rw-rw----. 1 mysql mysql 5 12月 22 16:41 hadoop102.pid 文件,並修改權限爲 777。
7)JVM堆內存溢出
描述:java.lang.OutOfMemoryError: Java heap space
解決:在yarn-site.xml中加入如下代碼

<property>
	<name>yarn.scheduler.maximum-allocation-mb</name>
	<value>2048</value>
</property>
<property>
  	<name>yarn.scheduler.minimum-allocation-mb</name>
  	<value>2048</value>
</property>
<property>
	<name>yarn.nodemanager.vmem-pmem-ratio</name>
	<value>2.1</value>
</property>
<property>
	<name>mapred.child.java.opts</name>
	<value>-Xmx1024m</value>
</property>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章