【大數據】Hive學習筆記

 

1 Hive基本概念

1.1 什麼是Hive

Hive:由Facebook開源用於解決海量結構化日誌的數據統計。java

Hive是基於Hadoop的一個數據倉庫工具,能夠將結構化的數據文件映射爲一張表,並提供SQL查詢功能。node

本質是:將HQL轉化成MapReduce程序mysql

1Hive處理的數據存儲在HDFSlinux

2Hive分析數據底層的實現是MapReducegit

3)執行程序運行在Yarngithub

1.2 Hive的優缺點

1.2.1 優勢

1) 操做接口採用類SQL語法,提供快速開發的能力(簡單、容易上手)web

2) 避免了去寫MapReduce,減小開發人員的學習成本正則表達式

3) Hive的執行延遲比較高,所以Hive經常使用於數據分析,對實時性要求不高的場合算法

4) Hive優點在於處理大數據,對於處理小數據沒有優點,由於Hive的執行延遲比較高sql

5) Hive支持用戶自定義函數,用戶能夠根據本身的需求來實現本身的函數

1.2.2 缺點

1.HiveHQL表達能力有限

1)迭代式算法沒法表達

2)數據挖掘方面不擅長因爲MapReduce數據處理流程的限制,效率更高的算法卻沒法實現。

2.Hive的效率比較低

1Hive自動生成的MapReduce做業,一般狀況下不夠智能化

2Hive調優比較困難,粒度較粗

1.3 Hive架構原理

 

6-1 Hive架構原理

1.用戶接口:Client

CLIcommand-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查詢時,也會有較高的延遲。相對的,數據庫的執行延遲較低。固然,這個低是有條件的,即數據規模較0小,當數據規模大到超過數據庫的處理能力的時候,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/目錄下面

[atguigu@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

[atguigu@hadoop102 module]$ mv apache-hive-1.2.1-bin/ hive

4)修改/opt/module/hive/conf目錄下的hive-env.sh.template名稱爲hive-env.sh

[atguigu@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)必須啓動hdfsyarn

[atguigu@hadoop102 hadoop-2.7.2]$ sbin/start-dfs.sh

[atguigu@hadoop103 hadoop-2.7.2]$ sbin/start-yarn.sh

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

[atguigu@hadoop102 hadoop-2.7.2]$ bin/hadoop fs -mkdir /tmp

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

 

[atguigu@hadoop102 hadoop-2.7.2]$ bin/hadoop fs -chmod g+w /tmp

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

3.Hive基本操做

1)啓動hive

[atguigu@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;

說明:(查看hivehdfs中的結構)

數據庫:在hdfs中表現爲${hive.metastore.warehouse.dir}目錄下一個文件夾

表:在hdfs中表現所屬db目錄下一個文件夾,文件夾中存放該表中的具體數據

2.3 將本地文件導入Hive案例

需求

將本地/opt/module/datas/student.txt這個目錄下的數據導入到hivestudent(id int, name string)表中。

1數據準備

/opt/module/datas這個目錄下準備數據

1)在/opt/module/目錄下建立datas

[atguigu@hadoop102 module]$ mkdir datas

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

[atguigu@hadoop102 datas]$ touch student.txt

[atguigu@hadoop102 datas]$ vi student.txt

1001 zhangshan

1002 lishi

1003 zhaoliu

注意以tab鍵間隔。

2.Hive實際操做

1)啓動hive

[atguigu@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;

8Hive查詢結果

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 -p OEXaQuS8IWkG19Xs

3.修改密碼

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

4.退出mysql

mysql>exit

2.4.4 MySqluser表中主機配置

配置只要是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 配置MetastoreMySql

1./opt/module/hive/conf目錄下建立一個hive-site.xml

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

[atguigu@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

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

查看有幾個數據庫

mysql> show databases;

+--------------------+

| Database           |

+--------------------+

| information_schema |

| mysql             |

| performance_schema |

| test               |

+--------------------+

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

[atguigu@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服務

[atguigu@hadoop102 hive]$ bin/hiveserver2

2.6.2 啓動beeline

[atguigu@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: atguigu(回車)

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經常使用交互命令

[atguigu@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語句

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

2.「-f」執行腳本中sql語句

1)在/opt/module/datas目錄下建立hivef.sql文件

[atguigu@hadoop102 datas]$ touch hivef.sql

文件中寫入正確的sql語句

select *from student;

2)執行文件中的sql語句

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

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

[atguigu@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/atguigu

2)查看. hivehistory文件

[atguigu@hadoop102 ~]$ cat .hivehistory

2.9 Hive常見屬性配置

2.9.1 Hive數據倉庫位置配置

1Default數據倉庫的最原始位置是在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.Hivelog默認存放在/tmp/atguigu/hive.log目錄下(當前用戶名下)

2.修改hivelog存放日誌到/opt/module/hive/logs

1)修改/opt/module/hive/conf/hive-log4j.properties.template文件名稱爲

hive-log4j.properties

[atguigu@hadoop102 conf]$ pwd

/opt/module/hive/conf

[atguigu@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來設定參數。

例如:

[atguigu@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

 

字節數組

 

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

3.2 集合數據類型

6-2

數據類型

描述

語法示例

STRUCT

c語言中的struct相似,均可以經過「點」符號訪問元素內容。例如,若是某個列的數據類型是STRUCT{first STRING, last STRING},那麼1個元素能夠經過字段.first來引用

struct()

例如struct<street:string, city:string>

MAP

MAP是一組鍵-值對元組集合,使用數組表示法能夠訪問數據。例如,若是某個列的數據類型是MAP,其中鍵->值對是’first->John’和’last->Doe’,那麼能夠經過字段名[last]獲取最後一個元素

map()

例如map<string, int>

ARRAY

數組是一組具備相同類型和名稱的變量的集合。這些變量稱爲數組的元素,每一個數組元素都有一個編號,編號從零開始。例如,數組值爲[John, Doe],那麼2個元素能夠經過數組名[1]進行引用

Array()

例如array<string>

Hive有三種複雜數據類型ARRAYMAP STRUCTARRAYMAPJava中的ArrayMap相似,而STRUCTC語言中的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

注意:MAPSTRUCTARRAY裏的元素間關係均可以用同一個字符表示,這裏用「_」

3Hive上建立測試表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中的keyvalue的分隔符

lines terminated by '\n'; -- 行分隔符

4導入文本數據到測試表

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

5)訪問三種集合列裏的數據,如下分別是ARRAYMAPSTRUCT的訪問方式

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能夠轉換成INTINT能夠轉換成BIGINT

2)全部整數類型、FLOATSTRING類型均可以隱式地轉換成DOUBLE

3TINYINTSMALLINTINT均可以轉換爲FLOAT

4BOOLEAN類型不能夠轉換爲任何其它的類型。

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 atguiguUSER

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

hive> desc database extended db_hive;

OK

db_hive hdfs://hadoop102:9000/user/hive/warehouse/db_hive.db atguiguUSER

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    atguigu 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.字段解釋說明 

1CREATE TABLE 建立一個指定名字的表。若是相同名字的表已經存在,則拋出異常;用戶能夠用 IF NOT EXISTS 選項來忽略這個異常。

2EXTERNAL關鍵字可讓用戶建立一個外部表,在建表的同時能夠指定一個指向實際數據的路徑(LOCATION在刪除表的時候,內部表的元數據和數據會被一塊兒刪除,而外部表只刪除元數據,不刪除數據

3COMMENT:爲表和列添加註釋。

4PARTITIONED BY建立分區表

5CLUSTERED BY建立分桶表

6SORTED BY不經常使用,對桶中的一個或多個列另外排序

7ROW 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。在建表的時候,用戶還須要爲表指定列,用戶在指定表的列的同時也會指定自定義的SerDeHive經過SerDe肯定表的具體的列的數據。

SerDeSerialize/Deserilize的簡稱, hive使用Serde進行行對象的序列與反序列化。

8STORED AS指定存儲文件類型

經常使用的存儲文件類型:SEQUENCEFILE(二進制序列文件)、TEXTFILE(文本)、RCFILE(列式存儲格式文件)

若是文件數據是純文本,可使用STORED AS TEXTFILE。若是數據須要壓縮,使用 STORED AS SEQUENCEFILE

9LOCATION :指定表在HDFS上的存儲位置。

10AS:後跟查詢語句,根據查詢結果建立表

11LIKE容許用戶複製現有的表結構,可是不復制數據。

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中的數據還在,可是metadatastu_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’);

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

 

6-5 加載數據到分區表

 

6-6 分區表

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,…)];

1load data:表示加載數據

2local:表示從本地加載數據到hive表;不然從HDFS加載數據到hive

3inpath:表示加載數據的路徑

4overwrite:表示覆蓋表中已有數據,不然表示追加

5into table:表示加載到哪張表

6student:表示具體的表

7partition:表示上傳到指定分區

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/atguigu/hive;

加載HDFS上數據

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

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

上傳文件到HDFS

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

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

hive (default)> load data inpath '/user/atguigu/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;

2. 建立表,並指定在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/atguigu/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

[atguigu@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';

exportimport主要用於兩個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;

注意:

1SQL 語言大小寫不敏感。 

2SQL 能夠寫在一行或者多行

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

AB 相加

A-B

A減去B

A*B

AB 相乘

A/B

A除以B

A%B

AB取餘

A&B

AB按位取與

A|B

AB按位取或

A^B

AB按位取異或

~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子句用於限制返回的行數。

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

6.2 Where語句

1.使用WHERE子句,將不知足條件的行過濾掉

2WHERE子句緊隨FROM子句

3.案例實操

查詢出薪水大於1000的全部員工

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

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

6.2.1 比較運算符(Between/In/ Is Null

1)下面表中描述了謂詞操做符,這些操做符一樣能夠用於JOIN…ONHAVING語句中。

6-4

操做符

支持的數據類型

描述

A=B

基本數據類型

若是A等於B則返回TRUE,反之返回FALSE

A<=>B

基本數據類型

若是AB都爲NULL,則返回TRUE,其餘的和等號(=)操做符的結果一致,若是任一爲NULL則結果爲NULL

A<>B, A!=B

基本數據類型

A或者BNULL則返回NULL;若是A不等於B,則返回TRUE,反之返回FALSE

A<B

基本數據類型

A或者BNULL,則返回NULL;若是A小於B,則返回TRUE,反之返回FALSE

A<=B

基本數據類型

A或者BNULL,則返回NULL;若是A小於等於B,則返回TRUE,反之返回FALSE

A>B

基本數據類型

A或者BNULL,則返回NULL;若是A大於B,則返回TRUE,反之返回FALSE

A>=B

基本數據類型

A或者BNULL,則返回NULL;若是A大於等於B,則返回TRUE,反之返回FALSE

A [NOT] BETWEEN B AND C

基本數據類型

若是AB或者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;反之返回FALSEB的表達式說明以下:‘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)查詢工資在5001000的員工信息

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 LikeRLike

1)使用LIKE運算選擇相似的值

2)選擇條件能夠包含字符或數字:

% 表明零個或多個字符(任意個字符)

_ 表明一個字符。

3RLIKE子句是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每一個部門中每一個崗位的最高薪水

hive (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.havingwhere不一樣點

1where後面不能寫分組函數,而having後面可使用分組函數。

2having只用於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 子句排序

ASCascend: 升序(默認)

DESCdescend: 降序

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相似MRpartition(自定義分區),進行分區,結合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的分區規則是根據分區字段hashreduce的個數進行模除後,餘數相同的分到一個

2. Hive要求DISTRIBUTE BY語句要寫在SORT BY語句以前。

6.5.6 Cluster By

distribute bysorts 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所示

 

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的分桶採用對分桶字段的值進行哈希,而後除以桶的個數求餘的方式決定該條記錄存放在哪一個桶當中

6.6.2 分桶抽樣查詢

對於很是大的數據集,有時用戶須要使用的是一個具備表明性的查詢結果而不是所有結果。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必須是tablebucket數的倍數或者因子。hive根據y的大小,決定抽樣的比例。例如,table總共分了4份,當y=2時,抽取(4/2=)2bucket的數據,當y=8時,抽取(4/8=)1/2bucket的數據。

x表示從哪一個bucket開始抽取,若是須要取多個分區,之後的分區號爲當前分區號加上y。例如,tablebucket數爲4tablesample(bucket 1 out of 2),表示總共抽取(4/2=2bucket的數據,抽取第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)。它的功能是若是valueNULL,則NVL函數返回default_value的值,不然返回value的值,若是兩個參數都爲NULL ,則返回NULL

  1. 數據準備:採用員工表
  2. 查詢:若是員工的commNULL,則用-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

  1. 查詢:若是員工的commNULL,則用領導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. 數據準備

name

dept_id

sex

悟空

A

大海

A

宋宋

B

 

 

鳳姐

A

婷姐

B

婷婷

B

2.需求

求出不一樣部門男女各多少人。結果以下:

A     2       1

B     1       2

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

[atguigu@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.數據準備

6-6 數據準備

name

constellation

blood_type

孫悟空

白羊座

A

大海

射手座

A

宋宋

白羊座

B

豬八戒

白羊座

A

鳳姐

射手座

A

3.需求

把星座和血型同樣的人歸類到一塊兒。結果以下:

射手座,A            大海|鳳姐

白羊座,A            孫悟空|豬八戒

白羊座,B            宋宋

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

[atguigu@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.按需求查詢數據

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, explodeUDTF一塊兒使用,它可以將一列數據拆成多行數據,在此基礎上能夠對拆分後的數據進行聚合。

2.數據準備

6-7 數據準備

movie

category

《疑犯追蹤》

懸疑,動做,科幻,劇情

Lie to me

懸疑,警匪,動做,心理,劇情

《戰狼2

戰爭,動做,災難

3.需求

將電影分類中的數組數據展開。結果以下:

《疑犯追蹤》      懸疑

《疑犯追蹤》      動做

《疑犯追蹤》      科幻

《疑犯追蹤》      劇情

Lie to me》   懸疑

Lie to me》   警匪

Lie to me》   動做

Lie to me》   心理

Lie to me》   劇情

《戰狼2》        戰爭

《戰狼2》        動做

《戰狼2》        災難

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

[atguigu@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;

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)查詢在20174月份購買過的顧客及總人數

(2)查詢顧客的購買明細及月購買總額

(3)上述的場景,要將cost按照日期進行累加

(4)查詢每一個顧客上次的購買時間

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

4.建立本地business.txt,導入數據

[atguigu@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)查詢在20174月份購買過的顧客及總人數

select name,count(*) over ()

from business 

where substring(orderdate,1,7) = '2017-04'

group by name;

(2)查詢顧客的購買明細及月購買總額

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.數據準備

6-7 數據準備

name

subject

score

孫悟空

語文

87

孫悟空

數學

95

孫悟空

英語

68

大海

語文

94

大海

數學

56

大海

英語

84

宋宋

語文

64

宋宋

數學

86

宋宋

英語

84

婷婷

語文

65

婷婷

數學

85

婷婷

英語

78

3.需求

計算每門學科成績排名。

4.建立本地score.txt,導入數據

[atguigu@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 自定義函數

1Hive 自帶了一些函數,好比:max/min等,可是數量有限,本身能夠經過自定義UDF來方便的擴展。

2)當Hive提供的內置函數沒法知足你的業務處理須要時,此時就能夠考慮使用用戶自定義函數(UDFuser-defined function)。

3)根據用戶自定義函數類別分爲如下三種:

1UDFUser-Defined-Function

一進一出

2UDAFUser-Defined Aggregation Function

彙集函數,多進一出

相似於:count/max/min

3UDTFUser-Defined Table-Generating Functions

一進多出

lateral view explore()

4)官方文檔地址

https://cwiki.apache.org/confluence/display/Hive/HivePlugins

5)編程步驟:

1)繼承org.apache.hadoop.hive.ql.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)注意事項

1UDF必需要有返回類型,能夠返回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.atguigu.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.atguigu.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 mavenprotobuf)

1hadoop-2.7.2-src.tar.gz

2jdk-8u144-linux-x64.tar.gz

3snappy-1.1.3.tar.gz

4apache-maven-3.0.5-bin.tar.gz

5protobuf-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支持的壓縮編碼

6-8

壓縮格式

工具

算法

文件擴展名

是否可切分

DEFLATE

DEFLATE

.deflate

Gzip

gzip

DEFLATE

.gz

bzip2

bzip2

bzip2

.bz2

LZO

lzop

LZO

.lzo

Snappy

Snappy

.snappy

爲了支持多種壓縮/解壓縮算法,Hadoop引入了編碼/解碼器,以下表所示

6-9

壓縮格式

對應的編碼/解碼器

DEFLATE

org.apache.hadoop.io.compress.DefaultCodec

gzip

org.apache.hadoop.io.compress.GzipCodec

bzip2

org.apache.hadoop.io.compress.BZip2Codec

LZO

com.hadoop.compression.lzo.LzopCodec

Snappy

org.apache.hadoop.io.compress.SnappyCodec

壓縮性能的比較

6-10

壓縮算法

原始文件大小

壓縮文件大小

壓縮速度

解壓速度

gzip

8.3GB

1.8GB

17.5MB/s

58MB/s

bzip2

8.3GB

1.1GB

2.4MB/s

9.5MB/s

LZO

8.3GB

2.9GB

49.3MB/s

74.6MB/s

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文件中):

6-11

參數

默認值

階段

建議

io.compression.codecs   

(在core-site.xml中配置)

org.apache.hadoop.io.compress.DefaultCodec, org.apache.hadoop.io.compress.GzipCodec, org.apache.hadoop.io.compress.BZip2Codec,

org.apache.hadoop.io.compress.Lz4Codec

輸入壓縮

Hadoop使用文件擴展名判斷是否支持某種編解碼器

mapreduce.map.output.compress

false

mapper輸出

這個參數設爲true啓用壓縮

mapreduce.map.output.compress.codec

org.apache.hadoop.io.compress.DefaultCodec

mapper輸出

使用LZOLZ4snappy編解碼器在此階段壓縮數據

mapreduce.output.fileoutputformat.compress

false

reducer輸出

這個參數設爲true啓用壓縮

mapreduce.output.fileoutputformat.compress.codec

org.apache.hadoop.io.compress. DefaultCodec

reducer輸出

使用標準工具或者編解碼器,如gzipbzip2

mapreduce.output.fileoutputformat.compress.type

RECORD

reducer輸出

SequenceFile輸出使用的壓縮類型:NONEBLOCK

 

8.3 開啓Map輸出階段壓縮

開啓map輸出階段壓縮能夠減小jobmapReduce 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 SEQUENCEFILEORCPARQUET

8.5.1 列式存儲和行式存儲

 

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

如圖6-10所示左邊爲邏輯表,右邊第一個爲行式存儲,第二個爲列式存儲。

1行存儲的特色

查詢知足條件的一整行數據的時候,列存儲則須要去每一個彙集的字段找到對應的每一個列的值,行存儲只須要找到其中一個值,其他的值都在相鄰地方,因此此時行存儲查詢的速度更快。

2列存儲的特色

由於每一個字段的數據彙集存儲,在查詢只須要少數幾個字段的時候,能大大減小讀取的數據量;每一個字段的數據類型必定是相同的,列式存儲能夠針對性的設計更好的設計壓縮算法。

TEXTFILESEQUENCEFILE的存儲格式都是基於行存儲的;

ORCPARQUET是基於列式存儲的。

8.5.2 TextFile格式

默認格式,數據不作壓縮,磁盤開銷大,數據解析開銷大。可結合GzipBzip2使用,但使用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格式

   1Index Data:一個輕量級的index,默認是每隔1W行作一個索引。這裏作的索引應該只是記錄某行的各字段在Row Data中的offset

    2Row Data:存的是具體的數據,先取部分行,而後對這些行按列進行存儲對每一個列進行了編碼,分紅多個Stream來存儲

    3Stripe 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文件中至少存儲一個行組,相似於orcstripe的概念。

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命令使用

[atguigu@hadoop104 hadoop-2.7.2]$ hadoop

   checknative [-a|-h]  check native hadoop and compression libraries availability

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

[atguigu@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到當前路徑

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

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

[atguigu@hadoop102 native]$ pwd

/opt/software/hadoop-2.7.2/lib/native

[atguigu@hadoop102 native]$ ll

-rw-r--r--. 1 atguigu atguigu  472950 9月   1 10:19 libsnappy.a

-rwxr-xr-x. 1 atguigu atguigu     955 9月   1 10:19 libsnappy.la

lrwxrwxrwx. 1 atguigu atguigu      18 12月 24 20:39 libsnappy.so -> libsnappy.so.1.3.0

lrwxrwxrwx. 1 atguigu atguigu      18 12月 24 20:39 libsnappy.so.1 -> libsnappy.so.1.3.0

-rwxr-xr-x. 1 atguigu atguigu  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路徑上

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

7.分發集羣

[atguigu@hadoop102 lib]$ xsync native/

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

[atguigu@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存儲方式的壓縮:

6-12

Key

Default

Notes

orc.compress

ZLIB

high level compression (one of NONE, ZLIB, SNAPPY)

orc.compress.size

262,144

number of bytes in each compression chunk

orc.stripe.size

268,435,456

number of bytes in each stripe

orc.row.index.stride

10,000

number of rows between index entries (must be >= 1000)

orc.create.index

true

whether to create row indexes

orc.bloom.filter.columns

""

comma separated list of column names for which bloom filter should be created

orc.bloom.filter.fpp

0.05

false positive probability for bloom filter (must >0.0 and <1.0)

注意:全部關於ORCFile的參數都是在HQL語句的TBLPROPERTIES字段裏面出現

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小表進行了優化。小表放在左邊和右邊已經沒有明顯區別。

案例實操

需求

測試大表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的結果中,此時咱們能夠表akey爲空的字段賦一個隨機的值,使得數據隨機均勻地分不到不一樣的reducer上。例如:

案例實操:

不隨機分佈空null值:

1)設置5reduce個數

set mapreduce.job.reduces = 5;

2JOIN兩張表

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)設置5reduce個數

set mapreduce.job.reduces = 5;

2JOIN兩張表

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=100hive也只會啓動一個reducer。,這就形成一個Reduce處理的數據量太大,致使整個Job很難完成,通常COUNT DISTINCT使用先GROUP BYCOUNT的方式替換:

案例實操

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只能使用1reducer來完成笛卡爾積

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 數據傾斜

9.4.1 合理設置Map

1)一般狀況下,做業會經過input的目錄產生一個或者多個map任務。

主要的決定因素有:input的文件總個數,input的文件大小,集羣設置的文件塊大小。

2)是否是map數越多越好?

答案是否認的。若是一個任務有不少小文件(遠遠小於塊大小128m),則每一個小文件也會被當作一個塊,用一個map任務來完成,而一個map任務啓動和初始化的時間遠遠大於邏輯處理的時間,就會形成很大的資源浪費。並且,同時可執行的map數是受限的。

3)是否是保證每一個map處理接近128m的文件塊,就高枕無憂了?

答案也是不必定。好比有一個127m的文件,正常會用一個map去完成,但這個文件只有一個或者兩個小字段,卻有幾千萬的記錄,若是map處理的邏輯比較複雜,用一個map任務去作,確定也比較耗時。

針對上面的問題23,咱們須要採起兩種方式來解決:即減小map數和增長map數;

9.4.2 小文件進行合併

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

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

9.4.3 複雜文件增長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.4 合理設置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來執行mapReduce任務的。這時JVM的啓動過程可能會形成至關大的開銷,尤爲是執行的job包含有成百上千task任務的狀況。JVM重用可使得JVM實例在同一個job中從新使用N次。N的值能夠在Hadoopmapred-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)查看詳細執行計劃

hive (default)> explain extended select * from emp;

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

10 Hive實戰之穀粒影音

10.1 需求描述

統計硅谷影音視頻網站的常規指標,各類TopN指標:

--統計視頻觀看數Top10

--統計視頻類別熱度Top10

--統計視頻觀看數Top20所屬類別

--統計視頻觀看數Top50所關聯視頻的所屬類別Rank

--統計每一個類別中的視頻熱度Top10

--統計每一個類別中視頻流量Top10

--統計上傳視頻最多的用戶Top10以及他們上傳的視頻

--統計每一個類別視頻觀看數Top10

10.2 項目

10.2.1 數據結構

1.視頻表

6-13 視頻表

字段

備註

詳細描述

video id

視頻惟一id

11位字符串

uploader

視頻上傳者

上傳視頻的用戶名String

age

視頻年齡

視頻在平臺上的整數天

category

視頻類別

上傳視頻指定的視頻分類

length

視頻長度

整形數字標識的視頻長度

views

觀看次數

視頻被瀏覽的次數

rate

視頻評分

滿分5

Ratings

流量

視頻的流量,整型數字

conments

評論數

一個視頻的整數評論數

related ids

相關視頻id

相關視頻的id,最多20

2.用戶表

6-14 用戶表

字段

備註

字段類型

uploader

上傳者用戶名

string

videos

上傳視頻數

int

friends

朋友數量

int

10.2.2 ETL原始數據

經過觀察原始數據形式,能夠發現,視頻能夠有多個所屬分類,每一個所屬分類用&符號分割,且分割的兩邊有空格字符,同時相關視頻也是能夠有多個元素,多個相關視頻又用「\t」進行分割。爲了分析數據時方便對存在多個子元素的數據進行操做,咱們首先進行數據重組清洗操做。即:將全部的類別用「&」分割,同時去掉兩邊空格,多個相關視頻id也使用「&」進行分割。

1ETLETLUtil

public class ETLUtil {

public static String oriString2ETLString(String ori){

StringBuilder etlString = new StringBuilder();

String[] splits = ori.split("\t");

if(splits.length < 9) return null;

splits[3] = splits[3].replace(" ", "");

for(int i = 0; i < splits.length; i++){

if(i < 9){

if(i == splits.length - 1){

etlString.append(splits[i]);

}else{

etlString.append(splits[i] + "\t");

}

}else{

if(i == splits.length - 1){

etlString.append(splits[i]);

}else{

etlString.append(splits[i] + "&");

}

}

}

 

return etlString.toString();

}

}

2ETLMapper

import java.io.IOException;

 

import org.apache.commons.lang.StringUtils;

import org.apache.hadoop.io.NullWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Mapper;

 

import com.atguigu.util.ETLUtil;

 

public class VideoETLMapper extends Mapper<Object, Text, NullWritable, Text>{

Text text = new Text();

 

@Override

protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {

String etlString = ETLUtil.oriString2ETLString(value.toString());

 

if(StringUtils.isBlank(etlString)) return;

 

text.set(etlString);

context.write(NullWritable.get(), text);

}

}

3ETLRunner

import java.io.IOException;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.NullWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;

import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import org.apache.hadoop.util.Tool;

import org.apache.hadoop.util.ToolRunner;

 

public class VideoETLRunner implements Tool {

private Configuration conf = null;

 

@Override

public void setConf(Configuration conf) {

this.conf = conf;

}

 

@Override

public Configuration getConf() {

return this.conf;

}

 

@Override

public int run(String[] args) throws Exception {

conf = this.getConf();

conf.set("inpath", args[0]);

conf.set("outpath", args[1]);

 

Job job = Job.getInstance(conf);

 

job.setJarByClass(VideoETLRunner.class);

 

job.setMapperClass(VideoETLMapper.class);

job.setMapOutputKeyClass(NullWritable.class);

job.setMapOutputValueClass(Text.class);

job.setNumReduceTasks(0);

 

this.initJobInputPath(job);

this.initJobOutputPath(job);

 

return job.waitForCompletion(true) ? 0 : 1;

}

 

private void initJobOutputPath(Job job) throws IOException {

Configuration conf = job.getConfiguration();

String outPathString = conf.get("outpath");

 

FileSystem fs = FileSystem.get(conf);

 

Path outPath = new Path(outPathString);

if(fs.exists(outPath)){

fs.delete(outPath, true);

}

 

FileOutputFormat.setOutputPath(job, outPath);

 

}

 

private void initJobInputPath(Job job) throws IOException {

Configuration conf = job.getConfiguration();

String inPathString = conf.get("inpath");

 

FileSystem fs = FileSystem.get(conf);

 

Path inPath = new Path(inPathString);

if(fs.exists(inPath)){

FileInputFormat.addInputPath(job, inPath);

}else{

throw new RuntimeException("HDFS中該文件目錄不存在:" + inPathString);

}

}

 

public static void main(String[] args) {

try {

int resultCode = ToolRunner.run(new VideoETLRunner(), args);

if(resultCode == 0){

System.out.println("Success!");

}else{

System.out.println("Fail!");

}

System.exit(resultCode);

} catch (Exception e) {

e.printStackTrace();

System.exit(1);

}

}

}

4.執行ETL

$ bin/yarn jar ~/softwares/jars/gulivideo-0.0.1-SNAPSHOT.jar \

com.atguigu.etl.ETLVideosRunner \

/gulivideo/video/2008/0222 \

/gulivideo/output/video/2008/0222

 

10.3 準備工做

10.3.1 建立表

建立表:gulivideo_ori,gulivideo_user_ori

建立表:gulivideo_orc,gulivideo_user_orc

gulivideo_ori:

create table gulivideo_ori(

    videoId string,

    uploader string,

    age int,

    category array<string>,

    length int,

    views int,

    rate float,

    ratings int,

    comments int,

    relatedId array<string>)

row format delimited

fields terminated by "\t"

collection items terminated by "&"

stored as textfile;

gulivideo_user_ori

create table gulivideo_user_ori(

    uploader string,

    videos int,

    friends int)

row format delimited

fields terminated by "\t"

stored as textfile;

 

而後把原始數據插入到orc表中

gulivideo_orc:

create table gulivideo_orc(

    videoId string,

    uploader string,

    age int,

    category array<string>,

    length int,

    views int,

    rate float,

    ratings int,

    comments int,

    relatedId array<string>)

row format delimited fields terminated by "\t"

collection items terminated by "&"

stored as orc;

gulivideo_user_orc:

create table gulivideo_user_orc(

    uploader string,

    videos int,

    friends int)

row format delimited

fields terminated by "\t"

stored as orc;

10.3.2 導入ETL後的數據

gulivideo_ori:

load data inpath "/gulivideo/output/video/2008/0222" into table gulivideo_ori;

gulivideo_user_ori

load data inpath "/gulivideo/user/2008/0903" into table gulivideo_user_ori;

10.3.3 ORC表插入數據

gulivideo_orc:

insert into table gulivideo_orc select * from gulivideo_ori;

 

gulivideo_user_orc:

insert into table gulivideo_user_orc select * from gulivideo_user_ori;

10.4 業務分析

10.4.1 統計視頻觀看數Top10

思路:使用order by按照views字段作一個全局排序便可,同時咱們設置只顯示前10條。

最終代碼:

select

    videoId,

    uploader,

    age,

    category,

    length,

    views,

    rate,

    ratings,

    comments

from

    gulivideo_orc

order by

    views

desc limit

    10;

10.4.2 統計視頻類別熱度Top10

思路:

1) 即統計每一個類別有多少個視頻,顯示出包含視頻最多的前10個類別。

2) 咱們須要按照類別group by聚合,而後count組內的videoId個數便可。

3) 由於當前表結構爲:一個視頻對應一個或多個類別。因此若是要group by類別,須要先將類別進行列轉行(展開),而後再進行count便可。

4) 最後按照熱度排序,顯示前10條。

最終代碼:

select

    category_name as category,

    count(t1.videoId) as hot

from (

    select

        videoId,

        category_name

    from

        gulivideo_orc lateral view explode(category) t_catetory as category_name) t1

group by

    t1.category_name

order by

    hot

desc limit

    10;

10.4.3 統計出視頻觀看數最高的20個視頻的所屬類別以及類別包含Top20視頻的個數

思路:

1) 先找到觀看數最高的20個視頻所屬條目的全部信息,降序排列

2) 把這20條信息中的category分裂出來(列轉行)

3) 最後查詢視頻分類名稱和該分類下有多少個Top20的視頻

最終代碼:

select

    category_name as category,

    count(t2.videoId) as hot_with_views

from (

    select

        videoId,

        category_name

    from (

        select

            *

        from

            gulivideo_orc

        order by

            views

        desc limit

            20) t1 lateral view explode(category) t_catetory as category_name) t2

group by

    category_name

order by

    hot_with_views

desc;

10.4.4 統計視頻觀看數Top50所關聯視頻的所屬類別排序

思路:

1) 查詢出觀看數最多的前50個視頻的全部信息(固然包含了每一個視頻對應的關聯視頻),記爲臨時表t1

t1:觀看數前50的視頻

select

    *

from

    gulivideo_orc

order by

    views

desc limit

    50;

2) 將找到的50條視頻信息的相關視頻relatedId列轉行,記爲臨時表t2

t2:將相關視頻的id進行列轉行操做

select

    explode(relatedId) as videoId

from

t1;

3) 將相關視頻的idgulivideo_orc表進行inner join操做

t5:獲得兩列數據,一列是category,一列是以前查詢出來的相關視頻id

 (select

    distinct(t2.videoId),

    t3.category

from

    t2

inner join

    gulivideo_orc t3 on t2.videoId = t3.videoId) t4 lateral view explode(category) t_catetory as category_name;

4) 按照視頻類別進行分組,統計每組視頻個數,而後排行

最終代碼:

select

    category_name as category,

    count(t5.videoId) as hot

from (

    select

        videoId,

        category_name

    from (

        select

            distinct(t2.videoId),

            t3.category

        from (

            select

                explode(relatedId) as videoId

            from (

                select

                    *

                from

                    gulivideo_orc

                order by

                    views

                desc limit

                    50) t1) t2

        inner join

            gulivideo_orc t3 on t2.videoId = t3.videoId) t4 lateral view explode(category) t_catetory as category_name) t5

group by

    category_name

order by

    hot

desc;

 

10.4.5 統計每一個類別中的視頻熱度Top10,以Music爲例

思路:

1) 要想統計Music類別中的視頻熱度Top10,須要先找到Music類別,那麼就須要將category展開,因此能夠建立一張表用於存放categoryId展開的數據。

2) category展開的表中插入數據。

3) 統計對應類別(Music)中的視頻熱度。

最終代碼:

建立表類別表:

create table gulivideo_category(

    videoId string,

    uploader string,

    age int,

    categoryId string,

    length int,

    views int,

    rate float,

    ratings int,

    comments int,

    relatedId array<string>)

row format delimited

fields terminated by "\t"

collection items terminated by "&"

stored as orc;

向類別表中插入數據:

insert into table gulivideo_category  

    select

        videoId,

        uploader,

        age,

        categoryId,

        length,

        views,

        rate,

        ratings,

        comments,

        relatedId

    from

        gulivideo_orc lateral view explode(category) catetory as categoryId;

 

統計Music類別的Top10(也能夠統計其餘)

select

    videoId,

    views

from

    gulivideo_category

where

    categoryId = "Music"

order by

    views

desc limit

    10;

10.4.6 統計每一個類別中視頻流量Top10,以Music爲例

思路:

1) 建立視頻類別展開表(categoryId列轉行後的表)

2) 按照ratings排序便可

最終代碼:

select

    videoId,

    views,

    ratings

from

    gulivideo_category

where

    categoryId = "Music"

order by

    ratings

desc limit

    10;

 

10.4.7 統計上傳視頻最多的用戶Top10以及他們上傳的觀看次數在前20的視頻

思路:

1) 先找到上傳視頻最多的10個用戶的用戶信息

select

    *

from

    gulivideo_user_orc

order by

    videos

desc limit

    10;

 

2) 經過uploader字段與gulivideo_orc表進行join,獲得的信息按照views觀看次數進行排序便可。

最終代碼:

select

    t2.videoId,

    t2.views,

    t2.ratings,

    t1.videos,

    t1.friends

from (

    select

        *

    from

        gulivideo_user_orc

    order by

        videos desc

    limit

        10) t1

join

    gulivideo_orc t2

on

    t1.uploader = t2.uploader

order by

    views desc

limit

    20;

10.4.8 統計每一個類別視頻觀看數Top10

思路:

1) 先獲得categoryId展開的表數據

2) 子查詢按照categoryId進行分區,而後分區內排序,並生成遞增數字,該遞增數字這一列起名爲rank

3) 經過子查詢產生的臨時表,查詢rank值小於等於10的數據行便可。

最終代碼:

select

    t1.*

from (

    select

        videoId,

        categoryId,

        views,

        row_number() over(partition by categoryId order by views desc) rank from gulivideo_category) t1

where

    rank <= 10;

11 常見錯誤及解決方案

1SecureCRT 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

3hive默認的輸入格式處理是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程序

多是hadoopyarn沒開啓。

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 1222 16:41 hadoop102.pid 文件,並修改權限爲 777

7JVM堆內存溢出

描述: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>

相關文章
相關標籤/搜索