亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Hive學(xué)習(xí)筆記

系統(tǒng) 4355 0

本文轉(zhuǎn)載自:http://blog.csdn.net/haojun186/article/details/7977565

1.??HIVE結(jié)構(gòu)

Hive 是建立在 Hadoop 上的數(shù)據(jù)倉庫基礎(chǔ)構(gòu)架。它提供了一系列的工具,可以用來進(jìn)行數(shù)據(jù)提取轉(zhuǎn)化加載(ETL),這是一種可以存儲(chǔ)、查詢和分析存儲(chǔ)在 Hadoop 中的大規(guī)模數(shù)據(jù)的機(jī)制。Hive 定義了簡(jiǎn)單的類 SQL 查詢語言,稱為 QL,它允許熟悉 SQL 的用戶查詢數(shù)據(jù)。同時(shí),這個(gè)語言也允許熟悉 MapReduce 開發(fā)者的開發(fā)自定義的 mapper 和 reducer 來處理內(nèi)建的 mapper 和 reducer 無法完成的復(fù)雜的分析工作。

1.1?HIVE架構(gòu)

?

Hive 的結(jié)構(gòu)可以分為以下幾部分:

·????????用戶接口:包括 CLI, Client, WUI

·????????元數(shù)據(jù)存儲(chǔ)。通常是存儲(chǔ)在關(guān)系數(shù)據(jù)庫如 mysql, derby 中

·????????解釋器、編譯器、優(yōu)化器、執(zhí)行器

·????????Hadoop:用 HDFS 進(jìn)行存儲(chǔ),利用MapReduce 進(jìn)行計(jì)算

1、 用戶接口主要有三個(gè):CLI,Client和 WUI。其中最常用的是 CLI,Cli 啟動(dòng)的時(shí)候,會(huì)同時(shí)啟動(dòng)一個(gè) Hive 副本。Client 是 Hive 的客戶端,用戶連接至 Hive Server。在啟動(dòng) Client 模式的時(shí)候,需要指出 Hive Server 所在節(jié)點(diǎn),并且在該節(jié)點(diǎn)啟動(dòng) Hive Server。 WUI 是通過瀏覽器訪問 Hive。

2、 Hive 將元數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫中,如 mysql、derby。Hive 中的元數(shù)據(jù)包括表的名字,表的列和分區(qū)及其屬性,表的屬性(是否為外部表等),表的數(shù)據(jù)所在目錄等。

3、 解釋器、編譯器、優(yōu)化器完成 HQL 查詢語句從詞法分析、語法分析、編譯、優(yōu)化以及查詢計(jì)劃的生成。生成的查詢計(jì)劃存儲(chǔ)在 HDFS 中,并在隨后有 MapReduce 調(diào)用執(zhí)行。

4、Hive 的數(shù)據(jù)存儲(chǔ)在 HDFS 中,大部分的查詢由 MapReduce 完成(包含 * 的查詢,比如 select * from tbl 不會(huì)生成 MapRedcue 任務(wù))。

1.2?Hive?和Hadoop 關(guān)系

?

Hive構(gòu)建在 Hadoop 之上,

·????????HQL 中對(duì)查詢語句的解釋、優(yōu)化、生成查詢計(jì)劃是由 Hive 完成的

·????????所有的數(shù)據(jù)都是存儲(chǔ)在 Hadoop 中

·????????查詢計(jì)劃被轉(zhuǎn)化為 MapReduce 任務(wù),在 Hadoop 中執(zhí)行(有些查詢沒有 MR 任務(wù),如:select * from table)

·????????Hadoop和Hive都是用UTF-8編碼的

?

1.3?Hive?和普通關(guān)系數(shù)據(jù)庫的異同

?

Hive

RDBMS

查詢語言

HQL

SQL

數(shù)據(jù)存儲(chǔ)

HDFS

Raw Device or Local FS

索引

執(zhí)行

MapReduce

Excutor

執(zhí)行延遲

處理數(shù)據(jù)規(guī)模

1.? 查詢語言。由于 SQL 被廣泛的應(yīng)用在數(shù)據(jù)倉庫中,因此,專門針對(duì) Hive 的特性設(shè)計(jì)了類 SQL 的查詢語言 HQL。熟悉 SQL 開發(fā)的開發(fā)者可以很方便的使用 Hive 進(jìn)行開發(fā)。

2.? 數(shù)據(jù)存儲(chǔ)位置。Hive 是建立在Hadoop 之上的,所有 Hive 的數(shù)據(jù)都是存儲(chǔ)在HDFS 中的。而數(shù)據(jù)庫則可以將數(shù)據(jù)保存在塊設(shè)備或者本地文件系統(tǒng)中。

3.? 數(shù)據(jù)格式。Hive 中沒有定義專門的數(shù)據(jù)格式,數(shù)據(jù)格式可以由用戶指定,用戶定義數(shù)據(jù)格式需要指定三個(gè)屬性:列分隔符(通常為空格、”\t”、”\x001″)、行分隔符(”\n”)以及讀取文件數(shù)據(jù)的方法(Hive 中默認(rèn)有三個(gè)文件格式 TextFile,SequenceFile 以及 RCFile)。由于在加載數(shù)據(jù)的過程中,不需要從用戶數(shù)據(jù)格式到 Hive 定義的數(shù)據(jù)格式的轉(zhuǎn)換,因此,Hive 在加載的過程中不會(huì)對(duì)數(shù)據(jù)本身進(jìn)行任何修改,而只是將數(shù)據(jù)內(nèi)容復(fù)制或者移動(dòng)到相應(yīng)的 HDFS 目錄中。而在數(shù)據(jù)庫中,不同的數(shù)據(jù)庫有不同的存儲(chǔ)引擎,定義了自己的數(shù)據(jù)格式。所有數(shù)據(jù)都會(huì)按照一定的組織存儲(chǔ),因此,數(shù)據(jù)庫加載數(shù)據(jù)的過程會(huì)比較耗時(shí)。

4.? 數(shù)據(jù)更新。由于 Hive 是針對(duì)數(shù)據(jù)倉庫應(yīng)用設(shè)計(jì)的,而數(shù)據(jù)倉庫的內(nèi)容是讀多寫少的。因此,Hive 中不支持對(duì)數(shù)據(jù)的改寫和添加,所有的數(shù)據(jù)都是在加載的時(shí)候中確定好的。而數(shù)據(jù)庫中的數(shù)據(jù)通常是需要經(jīng)常進(jìn)行修改的,因此可以使用 INSERT INTO ...? VALUES 添加數(shù)據(jù),使用 UPDATE... SET 修改數(shù)據(jù)。

5.? 索引。之前已經(jīng)說過,Hive 在加載數(shù)據(jù)的過程中不會(huì)對(duì)數(shù)據(jù)進(jìn)行任何處理,甚至不會(huì)對(duì)數(shù)據(jù)進(jìn)行掃描,因此也沒有對(duì)數(shù)據(jù)中的某些 Key 建立索引。Hive 要訪問數(shù)據(jù)中滿足條件的特定值時(shí),需要暴力掃描整個(gè)數(shù)據(jù),因此訪問延遲較高。由于 MapReduce 的引入, Hive 可以并行訪問數(shù)據(jù),因此即使沒有索引,對(duì)于大數(shù)據(jù)量的訪問,Hive 仍然可以體現(xiàn)出優(yōu)勢(shì)。數(shù)據(jù)庫中,通常會(huì)針對(duì)一個(gè)或者幾個(gè)列建立索引,因此對(duì)于少量的特定條件的數(shù)據(jù)的訪問,數(shù)據(jù)庫可以有很高的效率,較低的延遲。由于數(shù)據(jù)的訪問延遲較高,決定了 Hive 不適合在線數(shù)據(jù)查詢。

6.? 執(zhí)行。Hive 中大多數(shù)查詢的執(zhí)行是通過 Hadoop 提供的 MapReduce 來實(shí)現(xiàn)的(類似 select * from tbl 的查詢不需要 MapReduce)。而數(shù)據(jù)庫通常有自己的執(zhí)行引擎。

7.? 執(zhí)行延遲。之前提到,Hive 在查詢數(shù)據(jù)的時(shí)候,由于沒有索引,需要掃描整個(gè)表,因此延遲較高。另外一個(gè)導(dǎo)致 Hive 執(zhí)行延遲高的因素是 MapReduce 框架。由于 MapReduce 本身具有較高的延遲,因此在利用 MapReduce 執(zhí)行 Hive 查詢時(shí),也會(huì)有較高的延遲。相對(duì)的,數(shù)據(jù)庫的執(zhí)行延遲較低。當(dāng)然,這個(gè)低是有條件的,即數(shù)據(jù)規(guī)模較小,當(dāng)數(shù)據(jù)規(guī)模大到超過數(shù)據(jù)庫的處理能力的時(shí)候,Hive 的并行計(jì)算顯然能體現(xiàn)出優(yōu)勢(shì)。

8.? 可擴(kuò)展性。由于 Hive 是建立在 Hadoop 之上的,因此 Hive 的可擴(kuò)展性是和 Hadoop 的可擴(kuò)展性是一致的(世界上最大的 Hadoop 集群在 Yahoo!,2009年的規(guī)模在4000 臺(tái)節(jié)點(diǎn)左右)。而數(shù)據(jù)庫由于 ACID 語義的嚴(yán)格限制,擴(kuò)展行非常有限。目前最先進(jìn)的并行數(shù)據(jù)庫 Oracle 在理論上的擴(kuò)展能力也只有 100 臺(tái)左右。

9.?數(shù)據(jù)規(guī)模。由于 Hive 建立在集群上并可以利用 MapReduce 進(jìn)行并行計(jì)算,因此可以支持很大規(guī)模的數(shù)據(jù);對(duì)應(yīng)的,數(shù)據(jù)庫可以支持的數(shù)據(jù)規(guī)模較小。

1.4?HIVE元數(shù)據(jù)庫

Hive 將元數(shù)據(jù)存儲(chǔ)在 RDBMS 中,一般常用的有MYSQL和DERBY。

1.4.1?????DERBY

啟動(dòng)HIVE的元數(shù)據(jù)庫

進(jìn)入到hive的安裝目錄

Eg:

1、啟動(dòng)derby數(shù)據(jù)庫

/home/admin/caona/hive/build/dist/

運(yùn)行startNetworkServer -h 0.0.0.0

?

2、連接Derby數(shù)據(jù)庫進(jìn)行測(cè)試

查看/home/admin/caona/hive/build/dist/conf/hive-default.xml。

找到<property>

???<name>javax.jdo.option.ConnectionURL</name>

???<value>jdbc:derby://hadoop1:1527/metastore_db;create=true</value>

???<description>JDBC connect string for a JDBCmetastore</description>

? </property>

進(jìn)入derby安裝目錄

/home/admin/caona/hive/build/dist/db-derby-10.4.1.3-bin/bin

輸入./ij

Connect'jdbc:derby://hadoop1:1527/metastore_db;create=true';

?

3、元數(shù)據(jù)庫數(shù)據(jù)字典

表名

說明

關(guān)聯(lián)鍵

BUCKETING_COLS????????

? ?

????COLUMNS??????? ????

Hive表字段信息(字段注釋,字段名,字段類型,字段序號(hào))

SD_ID

DBS

 元數(shù)據(jù)庫信息,存放HDFS路徑信息

DB_ID

PARTITION_KEYS????????

Hive分區(qū)表分區(qū)鍵

PART_ID

SDS???????????????????

所有hive表、表分區(qū)所對(duì)應(yīng)的hdfs數(shù)據(jù)目錄和數(shù)據(jù)格式。

SD_ID,SERDE_ID

SD_PARAMS?????????????

序列化反序列化信息,如行分隔符、列分隔符、NULL的表示字符等

SERDE_ID

SEQUENCE_TABLE????????

SEQUENCE_TABLE表保存了hive對(duì)象的下一個(gè)可用ID,如’org.apache.hadoop.hive.metastore.model.MTable’, 21,則下一個(gè)新創(chuàng)建的hive表其TBL_ID就是21,同時(shí)SEQUENCE_TABLE表中271786被更新為26(這里每次都是+5?)。同樣,COLUMN,PARTITION等都有相應(yīng)的記錄

?

SERDES????????????????

? ?

SERDE_PARAMS??????????

? ?

SORT_COLS?????????????

? ?

TABLE_PARAMS??????????

表級(jí)屬性,如是否外部表,表注釋等

TBL_ID

TBLS??????????????????

所有hive表的基本信息

TBL_ID,SD_ID

?

從上面幾張表的內(nèi)容來看,hive整個(gè)創(chuàng)建表的過程已經(jīng)比較清楚了

  1. 解析用戶提交hive語句,對(duì)其進(jìn)行解析,分解為表、字段、分區(qū)等hive對(duì)象
  2. 根據(jù)解析到的信息構(gòu)建對(duì)應(yīng)的表、字段、分區(qū)等對(duì)象,從SEQUENCE_TABLE中獲取構(gòu)建對(duì)象的最新ID,與構(gòu)建對(duì)象信息(名稱,類型等)一同通過DAO方法寫入到元數(shù)據(jù)表中去,成功后將SEQUENCE_TABLE中對(duì)應(yīng)的最新ID+5。

實(shí)際上我們常見的RDBMS都是通過這種方法進(jìn)行組織的,典型的如postgresql,其系統(tǒng)表中和hive元數(shù)據(jù)一樣裸露了這些id信息(oid,cid等),而Oracle等商業(yè)化的系統(tǒng)則隱藏了這些具體的ID。通過這些元數(shù)據(jù)我們可以很容易的讀到數(shù)據(jù)諸如創(chuàng)建一個(gè)表的數(shù)據(jù)字典信息,比如導(dǎo)出建表語名等。

導(dǎo)出建表語句的shell腳本見 附一 待完成

1.4.2?????Mysql

將存放元數(shù)據(jù)的Derby數(shù)據(jù)庫遷移到Mysql數(shù)據(jù)庫

步驟:

?

1.5?HIVE的數(shù)據(jù)存儲(chǔ)

??? 首先,Hive 沒有專門的數(shù)據(jù)存儲(chǔ)格式,也沒有為數(shù)據(jù)建立索引,用戶可以非常自由的組織 Hive 中的表,只需要在創(chuàng)建表的時(shí)候告訴 Hive 數(shù)據(jù)中的列分隔符和行分隔符,Hive 就可以解析數(shù)據(jù)。

其次,Hive 中所有的數(shù)據(jù)都存儲(chǔ)在 HDFS 中,Hive 中包含以下數(shù)據(jù)模型:Table,External Table,Partition,Bucket。

  1. Hive 中的 Table 和數(shù)據(jù)庫中的 Table 在概念上是類似的,每一個(gè) Table 在 Hive 中都有一個(gè)相應(yīng)的目錄存儲(chǔ)數(shù)據(jù)。例如,一個(gè)表 xiaojun,它在 HDFS 中的路徑為:/ warehouse /xiaojun,其中,wh 是在 hive-site.xml 中由 ${hive.metastore.warehouse.dir} 指定的數(shù)據(jù)倉庫的目錄,所有的 Table 數(shù)據(jù)(不包括 External Table)都保存在這個(gè)目錄中。
  2. Partition 對(duì)應(yīng)于數(shù)據(jù)庫中的 Partition 列的密集索引,但是 Hive 中 Partition 的組織方式和數(shù)據(jù)庫中的很不相同。在 Hive 中,表中的一個(gè) Partition 對(duì)應(yīng)于表下的一個(gè)目錄,所有的 Partition 的數(shù)據(jù)都存儲(chǔ)在對(duì)應(yīng)的目錄中。例如:xiaojun 表中包含 dt 和 city 兩個(gè) Partition,則對(duì)應(yīng)于 dt = 20100801, ctry = US 的 HDFS 子目錄為:/ warehouse /xiaojun/dt=20100801/ctry=US;對(duì)應(yīng)于 dt = 20100801, ctry = CA 的 HDFS 子目錄為;/ warehouse /xiaojun/dt=20100801/ctry=CA
  3. Buckets 對(duì)指定列計(jì)算 hash,根據(jù) hash 值切分?jǐn)?shù)據(jù),目的是為了并行,每一個(gè) Bucket 對(duì)應(yīng)一個(gè)文件。將 user 列分散至 32 個(gè) bucket,首先對(duì) user 列的值計(jì)算 hash,對(duì)應(yīng) hash 值為 0 的 HDFS 目錄為:/ warehouse /xiaojun/dt =20100801/ctry=US/part-00000;hash 值為 20 的 HDFS 目錄為:/ warehouse /xiaojun/dt =20100801/ctry=US/part-00020
  4. External Table 指向已經(jīng)在 HDFS 中存在的數(shù)據(jù),可以創(chuàng)建 Partition。它和 Table 在元數(shù)據(jù)的組織上是相同的,而實(shí)際數(shù)據(jù)的存儲(chǔ)則有較大的差異。
  • Table 的創(chuàng)建過程和數(shù)據(jù)加載過程(這兩個(gè)過程可以在同一個(gè)語句中完成),在加載數(shù)據(jù)的過程中,實(shí)際數(shù)據(jù)會(huì)被移動(dòng)到數(shù)據(jù)倉庫目錄中;之后對(duì)數(shù)據(jù)對(duì)訪問將會(huì)直接在數(shù)據(jù)倉庫目錄中完成。刪除表時(shí),表中的數(shù)據(jù)和元數(shù)據(jù)將會(huì)被同時(shí)刪除。
  • External Table 只有一個(gè)過程,加載數(shù)據(jù)和創(chuàng)建表同時(shí)完成(CREATE EXTERNAL TABLE ……LOCATION),實(shí)際數(shù)據(jù)是存儲(chǔ)在 LOCATION 后面指定的 HDFS 路徑中,并不會(huì)移動(dòng)到數(shù)據(jù)倉庫目錄中。當(dāng)刪除一個(gè) External Table 時(shí),僅刪除

?

1.6?其它HIVE操作

?

1、 啟動(dòng)HIVE的WEB的界面

sh $HIVE_HOME/bin/hive --service hwi

?

2、查看HDFS上的文件數(shù)據(jù)

hadoopfs -text /user/admin/daiqf/createspu_fp/input/cateinfo |head

?

?

2.??HIVE?基本操作

2.1?createtable

2.1.1??? 總述

l? CREATETABLE 創(chuàng)建一個(gè)指定名字的表。如果相同名字的表已經(jīng)存在,則拋出異常;用戶可以用 IF NOT EXIST 選項(xiàng)來忽略這個(gè)異常。

l? EXTERNAL關(guān)鍵字可以讓用戶創(chuàng)建一個(gè)外部表,在建表的同時(shí)指定一個(gè)指向?qū)嶋H數(shù)據(jù)的路徑(LOCATION),Hive?創(chuàng)建內(nèi)部表時(shí),會(huì)將數(shù)據(jù)移動(dòng)到數(shù)據(jù)倉庫指向的路徑;若創(chuàng)建外部表,僅記錄數(shù)據(jù)所在的路徑,不對(duì)數(shù)據(jù)的位置做任何改變。在刪除表的時(shí)候,內(nèi)部表的元數(shù)據(jù)和數(shù)據(jù)會(huì)被一起刪除,而外部表只刪除元數(shù)據(jù),不刪除數(shù)據(jù)。

l? LIKE 允許用戶復(fù)制現(xiàn)有的表結(jié)構(gòu),但是不復(fù)制數(shù)據(jù)。

l? 用戶在建表的時(shí)候可以自定義 SerDe 或者使用自帶的 SerDe。如果沒有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,將會(huì)使用自帶的 SerDe。在建表的時(shí)候,用戶還需要為表指定列,用戶在指定表的列的同時(shí)也會(huì)指定自定義的SerDe,Hive 通過 SerDe 確定表的具體的列的數(shù)據(jù)。

l? 如果文件數(shù)據(jù)是純文本,可以使用 STORED AS TEXTFILE。如果數(shù)據(jù)需要壓縮,使用 STORED ASSEQUENCE 。

l? 有分區(qū)的表可以在創(chuàng)建的時(shí)候使用 PARTITIONED BY 語句。一個(gè)表可以擁有一個(gè)或者多個(gè)分區(qū),每一個(gè)分區(qū)單獨(dú)存在一個(gè)目錄下。而且,表和分區(qū)都可以對(duì)某個(gè)列進(jìn)行 CLUSTERED BY 操作,將若干個(gè)列放入一個(gè)桶(bucket)中。也可以利用SORT BY 對(duì)數(shù)據(jù)進(jìn)行排序。這樣可以為特定應(yīng)用提高性能。

l? 表名和列名不區(qū)分大小寫,SerDe 和屬性名區(qū)分大小寫。表和列的注釋是字符串。

2.1.2??? 語法

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name

??[(col_namedata_type [COMMENT col_comment], ...)]

??[COMMENTtable_comment]

??[PARTITIONED BY(col_name data_type [COMMENT col_comment], ...)]

??[CLUSTERED BY(col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTOnum_buckets BUCKETS]

??[

???[ROW FORMATrow_format] [STORED AS file_format]

???| STORED BY'storage.handler.class.name' [ WITH SERDEPROPERTIES (...) ]? (Note:?only available starting with 0.6.0)

??]

??[LOCATIONhdfs_path]

??[TBLPROPERTIES(property_name=property_value, ...)]?(Note:? only available startingwith 0.6.0)

??[ASselect_statement]? (Note: this feature isonly available starting with 0.5.0.)

?

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name

??LIKEexisting_table_name

??[LOCATIONhdfs_path]

?

data_type

??: primitive_type

??| array_type

??| map_type

??| struct_type

?

primitive_type

??: TINYINT

??| SMALLINT

??| INT

??| BIGINT

??| BOOLEAN

??| FLOAT

??| DOUBLE

??| STRING

?

array_type

??: ARRAY <data_type >

?

map_type

??: MAP <primitive_type, data_type >

?

struct_type

??: STRUCT <col_name : data_type [COMMENT col_comment], ...>

?

row_format

??: DELIMITED[FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char]

????????[MAP KEYSTERMINATED BY char] [LINES TERMINATED BY char]

??| SERDEserde_name [WITH SERDEPROPERTIES (property_name=property_value,property_name=property_value, ...)]

?

file_format:

??: SEQUENCEFILE

??| TEXTFILE

??| RCFILE???? (Note:?only available starting with 0.6.0)

??| INPUTFORMATinput_format_classname OUTPUTFORMAT output_format_classname

?

?

目前在hive中常用的數(shù)據(jù)類型有:

?? BIGINT – 主要用于狀態(tài),類別,數(shù)量的字段, 如status/option/type/quantity

?? DOUBLE – 主要用于金額的字段, 如fee/price/bid

?? STRING – 除上述之外的字段基本都使用String, 尤其是id和日期時(shí)間這樣的字段

?

2.1.3?????基本例子

1、如果一個(gè)表已經(jīng)存在,可以使用if not exists

2、 create table xiaojun(id int,cont string) row format delimitedfields terminated by '\005' stored as textfile;

terminated by:關(guān)于來源的文本數(shù)據(jù)的字段間隔符

如果要將自定義間隔符的文件讀入一個(gè)表,需要通過創(chuàng)建表的語句來指明輸入文件間隔符,然后load data到這個(gè)表。

4、Alibaba數(shù)據(jù)庫常用間隔符的讀取

我們的常用間隔符一般是Ascii碼5,Ascii碼7等。在hive中Ascii碼5用’\005’表示, Ascii碼7用’\007’表示,依此類推。

5、裝載數(shù)據(jù)

查看一下:Hadoop fs -ls

LOAD DATA INPATH'/user/admin/xiaojun/a.txt' OVERWRITE INTO TABLE xiaojun;

6、如果使用external建表和普通建表區(qū)別

A、指定一個(gè)位置,而不使用默認(rèn)的位置。如:

create? EXTERNAL?table xiaojun(id int,cont string) row format delimited fields terminatedby '\005' stored as textfile location '/user/admin/xiaojun/';

--------------check結(jié)果

ij> selectLOCATION from tbls a,sds b where a.sd_id=b.sd_id and tbl_name='xiaojun';?

-----

LOCATION???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

--------------------------------------------------------------------------------------------------------------------------------

hdfs://hadoop1:7000/user/admin/xiaojun??

?

ij> selectLOCATION from tbls a,sds b where a.sd_id=b.sd_id and tbl_name='c';

----

LOCATION???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

--------------------------------------------------------------------------------------------------------------------------------

hdfs://hadoop1:7000/user/hive/warehouse/c

B、對(duì)于使用create table external建表完成后,再drop掉表,表中的數(shù)據(jù)還在文件系統(tǒng)中。

如:

hive>create? EXTERNAL? table xiaojun(id int,cont string) row formatdelimited fields terminated by '\005' stored as textfile;

----

OK

?

hive> LOADDATA INPATH '/user/admin/xiaojun' OVERWRITE INTO TABLE xiaojun;

--------------------------------------------------

Loading data totable xiaojun

OK

?

hive> droptable xiaojun;

----

OK

?

[admin@hadoop1bin]$ ./hadoop fs -ls hdfs://hadoop1:7000/user/hive/warehouse/xiaojun

Found 1 items

使用普通的建表DROP后則找不到

2.1.4??? 創(chuàng)建分區(qū)

?? HIVE的分區(qū)通過在創(chuàng)建表時(shí)啟用partitionby實(shí)現(xiàn),用來partition的維度并不是實(shí)際數(shù)據(jù)的某一列,具體分區(qū)的標(biāo)志是由插入內(nèi)容時(shí)給定的。當(dāng)要查詢某一分區(qū)的內(nèi)容時(shí)可以采用where語句,形似where tablename.partition_key >a來實(shí)現(xiàn)。

創(chuàng)建含分區(qū)的表。

命令原型:

CREATE TABLE page_view(viewTime INT, userid BIGINT,

?????page_urlSTRING, referrer_url STRING,

?????ip STRINGCOMMENT 'IP Address of the User')

?COMMENT 'This isthe page view table'

?PARTITIONED BY(dtSTRING, country STRING)

?CLUSTEREDBY(userid) SORTED BY(viewTime) INTO 32 BUCKETS

?ROW FORMATDELIMITED

???FIELDSTERMINATED BY '\001'

???COLLECTION ITEMSTERMINATED BY '\002'

???MAP KEYSTERMINATED BY '\003'

?STORED ASSEQUENCEFILE;

?

Eg:

建表:

CREATE TABLE c02_clickstat_fatdt1

(yyyymmdd? string,

?id????????????? INT,

?ip?????????????? string,

?country????????? string,

?cookie_id??????? string,

?page_id????????? string? ,?

?clickstat_url_id int,

?query_string???? string,

?refer??????????? string

)PARTITIONED BY(dt STRING)

row format delimited fields terminated by '\005' stored astextfile;

?

裝載數(shù)據(jù):

LOAD DATA INPATH'/user/admin/SqlldrDat/CnClickstat/20101101/19/clickstat_gp_fatdt0/0' OVERWRITEINTO TABLE c02_clickstat_fatdt1

?PARTITION(dt='20101101');

?

訪問某一個(gè)分區(qū)

SELECT count(*)

??? FROMc02_clickstat_fatdt1 a

??? WHERE a.dt >='20101101' AND a.dt < '20101102';

2.1.5??? 其它例子

1、指定LOCATION位置

CREATE EXTERNAL TABLE page_view(viewTime INT, useridBIGINT,

?????page_urlSTRING, referrer_url STRING,

?????ip STRING COMMENT'IP Address of the User',

?????country STRINGCOMMENT 'country of origination')

?COMMENT 'This isthe staging page view table'

?ROW FORMATDELIMITED FIELDS TERMINATED BY '\054'

?STORED AS TEXTFILE

?LOCATION'<hdfs_location>';

2、 復(fù)制一個(gè)空表

CREATE TABLE empty_key_value_store

LIKE key_value_store;

?

?

?

2.2?AlterTable

2.2.1??? AddPartitions

ALTER TABLE table_name ADD [IF NOT EXISTS] partition_spec[ LOCATION 'location1' ] partition_spec [ LOCATION 'location2' ] ...

?

partition_spec:

??: PARTITION(partition_col = partition_col_value, partition_col = partiton_col_value, ...)

Eg:

ALTER TABLE c02_clickstat_fatdt1 ADD

PARTITION (dt='20101202') location'/user/hive/warehouse/c02_clickstat_fatdt1/part20101202'

PARTITION (dt='20101203') location'/user/hive/warehouse/c02_clickstat_fatdt1/part20101203';

?

2.2.2??? DropPartitions

ALTER TABLE table_name DROP partition_spec, partition_spec,...

?

ALTER TABLE c02_clickstat_fatdt1 DROP PARTITION(dt='20101202');

2.2.3??? RenameTable

ALTER TABLE table_name RENAME TO new_table_name

這個(gè)命令可以讓用戶為表更名。數(shù)據(jù)所在的位置和分區(qū)名并不改變。換而言之,老的表名并未“釋放”,對(duì)老表的更改會(huì)改變新表的數(shù)據(jù)。

2.2.4??? ChangeColumn

ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_namecolumn_type [COMMENT col_comment] [FIRST|AFTER column_name]

這個(gè)命令可以允許改變列名、數(shù)據(jù)類型、注釋、列位置或者它們的任意組合

Eg:

?

2.2.5??? Add/ReplaceColumns

ALTER TABLE table_name ADD|REPLACE COLUMNS (col_name data_type[COMMENT col_comment], ...)

?

ADD是代表新增一字段,字段位置在所有列后面(partition列前);REPLACE則是表示替換表中所有字段。

Eg:

hive> desc xi;

OK

id????? int

cont??? string

dw_ins_date???? string

Time taken: 0.061 seconds

hive> create table xibak like xi;????????????????????????

OK

Time taken: 0.157 seconds

hive> alter table xibak replace columns (ins_datestring);??

OK

Time taken: 0.109 seconds

hive> desc xibak;

OK

ins_date??????? string

2.3?CreateView

CREATE VIEW [IF NOT EXISTS] view_name [ (column_name [COMMENTcolumn_comment], ...) ]

[COMMENT view_comment]

[TBLPROPERTIES (property_name = property_value, ...)]

AS SELECT ...

?

2.4?Show

查看表名

SHOWTABLES;

?

查看表名,部分匹配

SHOWTABLES 'page.*';

SHOWTABLES '.*view';

?

查看某表的所有Partition,如果沒有就報(bào)錯(cuò):

SHOWPARTITIONS page_view;

?

查看某表結(jié)構(gòu):

DESCRIBE? invites ;

?

查看分區(qū)內(nèi)容

SELECTa.foo FROM invites a WHERE a. ds [王黎1] ?='2008-08-15';

?

查看有限行內(nèi)容,同Greenplum,用limit關(guān)鍵詞

SELECTa.foo FROM invites a limit 3;

?

查看表分區(qū)定義

DESCRIBE? EXTENDED [王黎2] ??page_view PARTITION (ds='2008-08-08');

2.5?Load

?? HIVE裝載數(shù)據(jù)沒有做任何轉(zhuǎn)換加載到表中的數(shù)據(jù)只是進(jìn)入相應(yīng)的配置單元表的位置移動(dòng)數(shù)據(jù)文件。純加載操作復(fù)制/移動(dòng)操作。

?

3.1 語法

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTOTABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]

Load 操作只是單純的復(fù)制/移動(dòng)操作,將數(shù)據(jù)文件移動(dòng)到 Hive 表對(duì)應(yīng)的位置。

  • filepath 可以是:
    • 相對(duì)路徑,例如:project/data1
    • 絕對(duì)路徑,例如: /user/hive/project/data1
    • 包含模式的完整 URI,例如:hdfs://namenode:9000/user/hive/project/data1
  • 加載的目標(biāo)可以是一個(gè)表或者分區(qū)。如果表包含分區(qū),必須指定每一個(gè)分區(qū)的分區(qū)名。
  • filepath 可以引用一個(gè)文件(這種情況下,Hive 會(huì)將文件移動(dòng)到表所對(duì)應(yīng)的目錄中)或者是一個(gè)目錄(在這種情況下,Hive 會(huì)將目錄中的所有文件移動(dòng)至表所對(duì)應(yīng)的目錄中)。
  • 如果指定了 LOCAL,那么:
    • load 命令會(huì)去查找本地文件系統(tǒng)中的 filepath。如果發(fā)現(xiàn)是相對(duì)路徑,則路徑會(huì)被解釋為相對(duì)于當(dāng)前用戶的當(dāng)前路徑。用戶也可以為本地文件指定一個(gè)完整的 URI,比如:file:///user/hive/project/data1.
    • load 命令會(huì)將 filepath 中的文件復(fù)制到目標(biāo)文件系統(tǒng)中。目標(biāo)文件系統(tǒng)由表的位置屬性決定。被復(fù)制的數(shù)據(jù)文件移動(dòng)到表的數(shù)據(jù)對(duì)應(yīng)的位置。
  • 如果沒有指定 LOCAL 關(guān)鍵字,如果 filepath 指向的是一個(gè)完整的 URI,hive 會(huì)直接使用這個(gè) URI。 否則:
    • 如果沒有指定 schema 或者 authority,Hive 會(huì)使用在 hadoop 配置文件中定義的 schema 和 authority,fs.default.name 指定了 Namenode 的 URI。
    • 如果路徑不是絕對(duì)的,Hive 相對(duì)于 /user/ 進(jìn)行解釋。
    • Hive 會(huì)將 filepath 中指定的文件內(nèi)容移動(dòng)到 table (或者 partition)所指定的路徑中。
  • 如果使用了 OVERWRITE 關(guān)鍵字,則目標(biāo)表(或者分區(qū))中的內(nèi)容(如果有)會(huì)被刪除,然后再將 filepath 指向的文件/目錄中的內(nèi)容添加到表/分區(qū)中。
  • 如果目標(biāo)表(分區(qū))已經(jīng)有一個(gè)文件,并且文件名和 filepath 中的文件名沖突,那么現(xiàn)有的文件會(huì)被新文件所替代。

?

從本地導(dǎo)入數(shù)據(jù)到表格并追加原表

LOAD DATALOCAL INPATH `/tmp/pv_2008-06-08_us.txt` INTO TABLE c02PARTITION(date='2008-06-08', country='US')

?

從本地導(dǎo)入數(shù)據(jù)到表格并追加記錄

LOAD DATALOCAL INPATH './examples/files/kv1.txt' INTO TABLE pokes;

?

從hdfs導(dǎo)入數(shù)據(jù)到表格并覆蓋原表

LOAD DATAINPATH '/user/admin/SqlldrDat/CnClickstat/20101101/18/clickstat_gp_fatdt0/0'INTO table c02_clickstat_fatdt1 OVERWRITE PARTITION (dt='20101201');

關(guān)于來源的文本數(shù)據(jù)的字段間隔符

如果要將自定義間隔符的文件讀入一個(gè)表,需要通過創(chuàng)建表的語句來指明輸入文件間隔符,然后load data到這個(gè)表就ok了。

?

2.6?Insert

2.6.1???Inserting data into HiveTables from queries

?

Standard syntax:

INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1,partcol2=val2 ...)] select_statement1 FROM from_statement

?

Hive extension (multiple inserts):

FROM from_statement

INSERT OVERWRITE TABLE tablename1 [PARTITION(partcol1=val1, partcol2=val2 ...)] select_statement1

[INSERT OVERWRITE TABLE tablename2 [PARTITION ...]select_statement2] ...

?

Hive extension (dynamic partition inserts):

INSERT OVERWRITE TABLE tablename PARTITION(partcol1[=val1], partcol2[=val2] ...) select_statement FROM from_statement

?

Insert時(shí),from子句既可以放在select子句后,也可以放在insert子句前,下面兩句是等價(jià)的

hive> FROM invites a INSERT OVERWRITE TABLEevents SELECT a.bar, count(*) WHERE a.foo > 0 GROUP BY a.bar;

??hive> INSERT OVERWRITE TABLE events SELECTa.bar, count(*) FROM invites a WHERE a.foo > 0 GROUP BY a.bar;

hive沒有直接插入一條數(shù)據(jù)的sql,不過可以通過其他方法實(shí)現(xiàn):
假設(shè)有一張表B至少有一條數(shù)據(jù),我們想向表A(int,string)中插入一條數(shù)據(jù),可以用下面的方法實(shí)現(xiàn):
from B
insert table A select??1,‘a(chǎn)bc’ limit 1;

?

我覺得hive好像不能夠插入一個(gè)記錄,因?yàn)槊看文銓慽nsert語句的時(shí)候都是要將整個(gè)表的值overwrite。我想這個(gè)應(yīng)該是與hive的storage layer是有關(guān)系的,因?yàn)樗拇鎯?chǔ)層是HDFS,插入一個(gè)數(shù)據(jù)要全表掃描,還不如用整個(gè)表的替換來的快些。

?

Hive不支持一條一條的用insert語句進(jìn)行插入操作,也不支持update的操作。數(shù)據(jù)是以load的方式,加載到建立好的表中。數(shù)據(jù)一旦導(dǎo)入,則不可修改。要么drop掉整個(gè)表,要么建立新的表,導(dǎo)入新的數(shù)據(jù)。

2.6.2???Writing data intofilesystem from queries

Standard syntax:

INSERT OVERWRITE [LOCAL] DIRECTORY directory1 SELECT ...FROM ...

?

Hive extension (multiple inserts):

FROM from_statement

INSERT OVERWRITE [LOCAL] DIRECTORY directory1select_statement1

[INSERT OVERWRITE [LOCAL] DIRECTORY directory2select_statement2] ...

?

導(dǎo)出文件到本地

INSERTOVERWRITE LOCAL DIRECTORY '/tmp/local_out' SELECT a.* FROM pokes a;

?

導(dǎo)出文件到HDFS

INSERTOVERWRITE DIRECTORY'/user/admin/SqlldrDat/CnClickstat/20101101/19/clickstat_gp_fatdt0/0' SELECTa.* FROM c02_clickstat_fatdt1 a WHERE dt=’20101201’;

?

一個(gè)源可以同時(shí)插入到多個(gè)目標(biāo)表或目標(biāo)文件,多目標(biāo)insert可以用一句話來完成

FROM src

??INSERT OVERWRITE TABLE dest1 SELECT src.*WHERE src.key < 100

??INSERT OVERWRITE TABLE dest2 SELECT src.key,src.value WHERE src.key >= 100 and src.key < 200

??INSERT OVERWRITE TABLE dest3PARTITION(ds='2008-04-08', hr='12') SELECT src.key WHERE src.key >= 200 andsrc.key < 300

??INSERT OVERWRITE LOCAL DIRECTORY'/tmp/dest4.out' SELECT src.value WHERE src.key >= 300;

Eg:

from xi?

insert overwrite?table test2 select? '1,2,3' limit1

insert overwrite?table d select? '4,5,6' limit 1;

2.7Cli [王黎3] ?

2.7.1??? HiveCommand line Options

$HIVE_HOME/bin/hive是一個(gè)shell工具,它可以用來運(yùn)行于交互或批處理方式配置單元查詢。

語法:

??Usage: hive[-hiveconf x=y]* [<-i filename>]* [<-f filename>|<-equery-string>] [-S]

?

??-i<filename>????????????Initialization Sql from file (executed automatically and silently beforeany other commands)

??-e 'quoted querystring'? Sql from command line

??-f<filename>???????????? Sql fromfile

??-S??????????????????????? Silent mode ininteractive shell where only data is emitted

??-hiveconfx=y???????????? Use this to sethive/hadoop configuration variables.

??

???-e and -f cannotbe specified together. In the absence of these options, interactive shell isstarted.?

???However, -i canbe used with any other options.? Multipleinstances of -i can be used to execute multiple init scripts.

?

???To see thisusage help, run hive -h

?

運(yùn)行一個(gè)查詢:

$HIVE_HOME/bin/?hive -e 'select count(*) fromc02_clickstat_fatdt1'

Example of setting hive configurationvariables

$HIVE_HOME/bin/hive -e 'select a.col from tab1 a'-hiveconf? hive.exec.scratchdir=/home/my/hive_scratch?? -hiveconf mapred.reduce.tasks=32 [王黎4] ?

將查詢結(jié)果導(dǎo)出到一個(gè)文件

HIVE_HOME/bin/hive -S -e '?select count(*) from c02_clickstat_fatdt1'> a.txt

運(yùn)行一個(gè)腳本

HIVE_HOME/bin/hive -f /home/my/hive-script.sql

Example of running an initialization scriptbefore entering interactive mode

HIVE_HOME/bin/hive -i /home/my/hive-init.sql

?

2.7.2??? Hiveinteractive Shell Command

Command

Description

quit

使用 quit or exit 退出

set <key>=<value>

使用這個(gè)方式來設(shè)置特定的配置變量的值。有一點(diǎn)需要注意的是,如果你拼錯(cuò)了變量名,CLI將不會(huì)顯示錯(cuò)誤。

set

這將打印的配置變量,如果沒有指定變量則由顯示HIVE和用戶變量。如set I 則顯示i的值,set則顯示hive內(nèi)部變量值

set -v

This will give all possible hadoop/hive configuration variables.

add FILE <value> <value>*

Adds a file to the list of resources.

list FILE

list all the resources already added

list FILE <value>*

Check given resources are already added or not.

! <cmd>

execute a shell command from hive shell

dfs <dfs command>

execute dfs command command from hive shell

<query string>

executes hive query and prints results to stdout

Eg:

??hive> set? i=32;

??hive> set i;

??hive> selecta.* from xiaojun a;

??hive> !ls;

??hive> dfs -ls;

?

還可以這樣用

hive> set $i='121.61.99.14.128160791368.5';

hive> select count(*) from c02_clickstat_fatdt1 wherecookie_id=$i;

11

2.7.3???Hive Resources

Hive can manage theaddition of resources to a session where those resources need to be made availableat query execution time. Any locally accessible file can be added to thesession. Once a file is added to a session, hive query can refer to this fileby its name (in? map/reduce/transformclauses [王黎5] ?) and this file is available locally at execution time on the entirehadoop cluster. Hive uses Hadoop's Distributed Cache to distribute the addedfiles to all the machines in the cluster at query execution time.

Usage:

·???????????ADD { FILE[S] | JAR[S] |ARCHIVE[S] } <filepath1> [<filepath2>]*

·???????????LIST { FILE[S] | JAR[S] |ARCHIVE[S] } [<filepath1> <filepath2> ..]

·???????????DELETE { FILE[S] | JAR[S] |ARCHIVE[S] } [<filepath1> <filepath2> ..]

  • FILE resources are just added to the distributed cache. Typically, this might be something like a transform script to be executed.
  • JAR resources are also added to the Java classpath. This is required in order to reference objects they contain such as UDF's.
  • ARCHIVE resources are automatically unarchived as part of distributing them.

Example:

·??????????hive> add FILE /tmp/tt.py;

·??????????hive> list FILES;

·??????????/tmp/tt.py

·??????????hive> from networks a? MAP a.networkid USING 'python tt.py' as nnwhere a.ds = '2009-01-04' limit? 10;

It is not neccessary to addfiles to the session if the files used in a transform script are alreadyavailable on all machines in the hadoop cluster using the same path name. Forexample:

  • ... MAP a.networkid USING 'wc -l' ...: here wc is an executable available on all machines
  • ... MAP a.networkid USING '/home/nfsserv1/hadoopscripts/tt.py' ...: here tt.py may be accessible via a nfs mount point that's configured identically on all the cluster nodes

[王黎6] ?

2.7.4??? 調(diào)用python、shell等語言

如下面這句sql就是借用了weekday_mapper.py對(duì)數(shù)據(jù)進(jìn)行了處理

CREATETABLE u_data_new (

??userid INT,

??movieid INT,

??rating INT,

??weekday INT)

ROWFORMAT DELIMITED

FIELDSTERMINATED BY '\t';

?

add FILEweekday_mapper.py;

?

INSERTOVERWRITE TABLE u_data_new

SELECT

?? TRANSFORM? [王黎7] ?(userid,movieid, rating, unixtime)

??USING 'python weekday_mapper.py'

??AS (userid, movieid, rating, weekday)

FROMu_data;

,其中weekday_mapper.py內(nèi)容如下

import sys

import datetime

?

for line in sys.stdin:

??line =line.strip()

??userid,movieid, rating, unixtime = line.split('\t')

??weekday= datetime.datetime.fromtimestamp(float(unixtime)).isoweekday()

??print'\t'.join([userid, movieid, rating, str(weekday)])

?

如下面的例子則是使用了shell的cat命令來處理數(shù)據(jù)

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

[王黎8] ?

?

?

?

?

2.8?DROP

刪除一個(gè)內(nèi)部表的同時(shí)會(huì)同時(shí)刪除表的元數(shù)據(jù)和數(shù)據(jù)。刪除一個(gè)外部表,只刪除元數(shù)據(jù)而保留數(shù)據(jù)。

?

2.9?其它

2.9.1??? Limit

Limit可以限制查詢的記錄數(shù)。查詢的結(jié)果是隨機(jī)選擇的。下面的查詢語句從 t1 表中隨機(jī)查詢5條記錄:

SELECT* FROM t1 LIMIT 5

2.9.2??? Top k

下面的查詢語句查詢銷售記錄最大的 5 個(gè)銷售代表。

SETmapred.reduce.tasks = 1

? SELECT * FROM sales SORT BY amount DESC LIMIT5

?

2.9.3??? REGEX Column Specification

SELECT 語句可以使用正則表達(dá)式做列選擇,下面的語句查詢除了 ds 和 hr 之外的所有列:

SELECT `(ds|hr)?+.+`FROM sales

[王黎9] ?

3.??Hive Select

語法:

SELECT [ALL | DISTINCT] select_expr, select_expr, ...

FROM table_reference

[WHERE where_condition]

[GROUP BY col_list]

[???CLUSTER BYcol_list

??| [DISTRIBUTE BYcol_list] [SORT BY col_list]

]

[LIMIT number]

?

3.1?GroupBy

基本語法:

groupByClause: GROUP BY groupByExpression (,groupByExpression)*

?

groupByExpression: expression

?

groupByQuery: SELECT expression (, expression)* FROM srcgroupByClause?

?

高級(jí)特性:

l? 聚合可進(jìn)一步分為多個(gè)表,甚至發(fā)送到Hadoop的DFS的文件(可以進(jìn)行操作,然后使用HDFS的utilitites)。例如我們可以根據(jù)性別劃分,需要找到獨(dú)特的頁面瀏覽量按年齡劃分。如下面的例子:

??FROM pv_users

??INSERT OVERWRITETABLE pv_gender_sum

????SELECTpv_users.gender, count(DISTINCT pv_users.userid)

????GROUP BYpv_users.gender

??INSERT OVERWRITEDIRECTORY '/user/facebook/tmp/pv_age_sum'

????SELECTpv_users.age, count(DISTINCT pv_users.userid)

????GROUP BYpv_users.age;

?

l? hive.map.aggr可以控制怎么進(jìn)行匯總。默認(rèn)為為true,配置單元會(huì)做的第一級(jí)聚合直接在MAP上的任務(wù)。這通常提供更好的效率,但可能需要更多的內(nèi)存來運(yùn)行成功。

?sethive.map.aggr=true;

SELECT COUNT(*) FROM table2;

PS:在要特定的場(chǎng)合使用可能會(huì)加效率。不過我試了一下,比直接使用False慢很多。

3.2?Order/Sort By

Order by 語法:

colOrder: ( ASC | DESC )

orderBy: ORDER BY colName colOrder? (',' colNamecolOrder?)*

query: SELECT expression (',' expression)* FROM srcorderBy

?

Sort By 語法:

Sort順序?qū)⒏鶕?jù)列類型而定。如果數(shù)字類型的列,則排序順序也以數(shù)字順序。如果字符串類型的列,則排序順序?qū)⒆值漤樞颉?

colOrder: ( ASC | DESC )

sortBy: SORT BY colName colOrder? (',' colNamecolOrder?)*

query: SELECT expression (',' expression)* FROM srcsortBy

?

4.??Hive Join

語法

join_table:

????table_referenceJOIN table_factor [join_condition]

??| table_reference{LEFT|RIGHT|FULL} [OUTER] JOIN table_reference join_condition

??| table_reference LEFT SEMIJOIN [王黎10] ??table_reference join_condition

?

table_reference:

????table_factor

??| join_table

?

table_factor:

????tbl_name[alias]

??| table_subqueryalias

??| (table_references )

?

join_condition:

????ONequality_expression ( AND equality_expression )*

?

equality_expression:

????expression =expression

Hive 只支持等值連接(equality joins)、外連接(outer joins)和(left/right joins)。Hive 不支持所有非等值的連接,因?yàn)榉堑戎颠B接非常難轉(zhuǎn)化到 map/reduce 任務(wù)。另外,Hive 支持多于 2 個(gè)表的連接。

寫 join 查詢時(shí),需要注意幾個(gè)關(guān)鍵點(diǎn):

1、只支持等值join

例如:

? SELECT a.* FROMa JOIN b ON (a.id = b.id)

? SELECT a.* FROM a JOIN b

??? ON (a.id = b.id AND a.department =b.department)

是正確的,然而:

? SELECT a.* FROM a JOIN b ON (a.id? b.id)

是錯(cuò)誤的。

?

1.?可以 join 多于 2 個(gè)表。

例如

? SELECT a.val,b.val, c.val FROM a JOIN b

??? ON (a.key =b.key1) JOIN c ON (c.key = b.key2)

如果join中多個(gè)表的join key 是同一個(gè),則 join 會(huì)被轉(zhuǎn)化為單個(gè)map/reduce 任務(wù),例如:

? SELECT a.val,b.val, c.val FROM a JOIN b

??? ON (a.key =b.key1) JOIN c

??? ON (c.key =b.key1)

被轉(zhuǎn)化為單個(gè) map/reduce 任務(wù),因?yàn)?join 中只使用了 b.key1 作為 join key。

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key =b.key1)

? JOIN c ON(c.key = b.key2)

而這一 join 被轉(zhuǎn)化為2 個(gè) map/reduce 任務(wù)。因?yàn)?b.key1 用于第一次 join 條件,而 b.key2 用于第二次 join。

??

3.join 時(shí),每次map/reduce 任務(wù)的邏輯:

??? reducer 會(huì)緩存 join 序列中除了最后一個(gè)表的所有表的記錄,再通過最后一個(gè)表將結(jié)果序列化到文件系統(tǒng)。這一實(shí)現(xiàn)有助于在 reduce 端減少內(nèi)存的使用量。實(shí)踐中,應(yīng)該把最大的那個(gè)表寫在最后(否則會(huì)因?yàn)榫彺胬速M(fèi)大量?jī)?nèi)存)。例如:

?SELECT a.val, b.val, c.val FROM a

??? JOIN b ON (a.key = b.key1)JOIN c ON (c.key = b.key1)

所有表都使用同一個(gè) join key(使用 1 次map/reduce 任務(wù)計(jì)算)。Reduce 端會(huì)緩存 a 表和 b 表的記錄,然后每次取得一個(gè) c 表的記錄就計(jì)算一次 join 結(jié)果,類似的還有:

? SELECT a.val, b.val, c.val FROMa

??? JOIN b ON (a.key = b.key1)JOIN c ON (c.key = b.key2)

這里用了 2 次 map/reduce 任務(wù)。第一次緩存 a 表,用 b 表 序列化 [王黎11] ?;第二次緩存第一次 map/reduce 任務(wù)的結(jié)果,然后用 c 表序列化。

[王黎12] ?

4.LEFT,RIGHT 和 FULLOUTER 關(guān)鍵字用于處理 join 中空記錄的情況。

例如:

? SELECT a.val,b.val FROM a LEFT OUTER

??? JOIN b ON(a.key=b.key)

對(duì)應(yīng)所有 a 表中的記錄都有一條記錄輸出。輸出的結(jié)果應(yīng)該是 a.val, b.val,當(dāng) a.key=b.key 時(shí),而當(dāng) b.key 中找不到等值的 a.key 記錄時(shí)也會(huì)輸出 a.val, NULL。“FROM a LEFT OUTER JOIN b”這句一定要寫在同一行——意思是 a 表在 b 表的 左邊 ,所以 a 表中的所有記錄都被保留了;“a RIGHT OUTER JOIN b”會(huì)保留所有 b 表的記錄。OUTER JOIN 語義應(yīng)該是遵循標(biāo)準(zhǔn) SQL spec的。

Join 發(fā)生在 WHERE 子句 之前 。如果你想限制 join 的輸出,應(yīng)該在 WHERE 子句中寫過濾條件——或是在join 子句中寫。這里面一個(gè)容易混淆的問題是表分區(qū)的情況:

? SELECT a.val,b.val FROM a

? LEFT OUTER JOINb ON (a.key=b.key)

? WHEREa.ds='2009-07-07' AND b.ds='2009-07-07'

會(huì) join a 表到 b 表(OUTER JOIN),列出 a.val 和 b.val 的記錄。WHERE 從句中可以使用其他列作為過濾條件。但是,如前所述,如果 b 表中找不到對(duì)應(yīng) a 表的記錄,b 表的所有列都會(huì)列出 NULL, 包括 ds 列 。也就是說,join 會(huì)過濾 b 表中不能找到匹配a 表 join key 的所有記錄。這樣的話,LEFTOUTER 就使得查詢結(jié)果與 WHERE 子句無關(guān)了。解決的辦法是在 OUTER JOIN 時(shí)使用以下語法:

? SELECT a.val,b.val FROM a LEFT OUTER JOIN b

? ON (a.key=b.keyAND

?????b.ds='2009-07-07' AND

?????a.ds='2009-07-07')

這一查詢的結(jié)果是預(yù)先在 join 階段過濾過的,所以不會(huì)存在上述問題。這一邏輯也可以應(yīng)用于 RIGHT 和 FULL 類型的join 中。

Join 是不能交換位置的。無論是 LEFT 還是 RIGHT join,都是左連接的。

? SELECT a.val1,a.val2, b.val, c.val

? FROM a

? JOIN b ON(a.key = b.key)

? LEFT OUTER JOINc ON (a.key = c.key)

先 join a 表到 b 表,丟棄掉所有 join key 中不匹配的記錄,然后用這一中間結(jié)果和 c 表做 join。這一表述有一個(gè)不太明顯的問題,就是當(dāng)一個(gè) key 在 a 表和 c 表都存在,但是 b 表中不存在的時(shí)候:整個(gè)記錄在第一次 join,即 a JOIN b 的時(shí)候都被丟掉了(包括a.val1,a.val2和a.key),然后我們?cè)俸?c 表 join 的時(shí)候,如果c.key 與 a.key 或 b.key 相等,就會(huì)得到這樣的結(jié)果:NULL, NULL, NULL, c.val。

?

5. LEFT SEMI JOIN [王黎13] ? 是 IN/EXISTS 子查詢的一種更高效的實(shí)現(xiàn)。Hive 當(dāng)前沒有實(shí)現(xiàn) IN/EXISTS 子查詢,所以你可以用 LEFT SEMI JOIN 重寫你的子查詢語句。LEFT SEMI JOIN 的限制是, JOIN 子句中右邊的表只能在 ON 子句中設(shè)置過濾條件,在 WHERE 子句、SELECT 子句或其他地方過濾都不行。

? SELECT a.key,a.value

? FROM a

? WHERE a.key in

?? (SELECT b.key

??? FROM B);

可以被重寫為:

?? SELECT a.key,a.val

?? FROM a LEFTSEMI JOIN b on (a.key = b.key)

?

5.??HIVE參數(shù)設(shè)置

??? 開發(fā)Hive應(yīng)用時(shí),不可避免地需要設(shè)定Hive的參數(shù)。設(shè)定Hive的參數(shù)可以調(diào)優(yōu)HQL代碼的執(zhí)行效率,或幫助定位問題。然而實(shí)踐中經(jīng)常遇到的一個(gè)問題是,為什么設(shè)定的參數(shù)沒有起作用?

這通常是錯(cuò)誤的設(shè)定方式導(dǎo)致的。

對(duì)于一般參數(shù),有以下三種設(shè)定方式:

  • 配置文件
  • 命令行參數(shù)
  • 參數(shù)聲明

配置文件 :Hive的配置文件包括

  • 用戶自定義配置文件:$HIVE_CONF_DIR/hive-site.xml
  • 默認(rèn)配置文件:$HIVE_CONF_DIR/hive-default.xml

用戶自定義配置會(huì)覆蓋默認(rèn)配置。另外,Hive也會(huì)讀入Hadoop的配置,因?yàn)镠ive是作為Hadoop的客戶端啟動(dòng)的,Hadoop的配置文件包括

  • $HADOOP_CONF_DIR/hive-site.xml
  • $HADOOP_CONF_DIR/hive-default.xml

Hive的配置會(huì)覆蓋Hadoop的配置。

配置文件的設(shè)定對(duì)本機(jī)啟動(dòng)的所有Hive進(jìn)程都有效。

命令行參數(shù) :?jiǎn)?dòng)Hive(客戶端或Server方式)時(shí),可以在命令行添加-hiveconf param=value來設(shè)定參數(shù),例如:

bin/hive -hiveconf hive.root.logger=INFO,console

這一設(shè)定對(duì)本次啟動(dòng)的Session(對(duì)于Server方式啟動(dòng),則是所有請(qǐng)求的Sessions)有效。

參數(shù)聲明 :可以在HQL中使用SET關(guān)鍵字設(shè)定參數(shù),例如:

set mapred.reduce.tasks=100;

這一設(shè)定的作用域也是Session級(jí)的。

上述三種設(shè)定方式的優(yōu)先級(jí)依次遞增。即參數(shù)聲明覆蓋命令行參數(shù),命令行參數(shù)覆蓋配置文件設(shè)定。注意某些系統(tǒng)級(jí)的參數(shù),例如log4j相關(guān)的設(shè)定,必須用前兩種方式設(shè)定,因?yàn)槟切﹨?shù)的讀取在Session建立以前已經(jīng)完成了。

另外, SerDe 參數(shù) [王黎14] ?必須寫在DDL(建表)語句中。例如:

create table if not exists t_dummy(

dummy???? string

)

ROW FORMAT SERDE'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'

WITH SERDEPROPERTIES (

'field.delim'='\t',

'escape.delim'='\\',

'serialization.null.format'=' '

) STORED AS TEXTFILE;

類似serialization.null.format這樣的參數(shù),必須和某個(gè)表或分區(qū)關(guān)聯(lián)。在DDL外部聲明將不起作用。

?

6.??HIVE UDF

6.1?基本函數(shù)

SHOW FUNCTIONS;

DESCRIBE FUNCTION <function_name>;

6.1.1?????關(guān)系操作符

Operator

Operand types

Description

A = B

All primitive types

TRUE if expression A is equal to expression B otherwise FALSE

A == B

None!

Fails because of invalid syntax. SQL uses =, not ==

A <> B

All primitive types

NULL if A or B is NULL, TRUE if expression A is NOT equal to expression B otherwise FALSE

A < B

All primitive types

NULL if A or B is NULL, TRUE if expression A is less than expression B otherwise FALSE

A <= B

All primitive types

NULL if A or B is NULL, TRUE if expression A is less than or equal to expression B otherwise FALSE

A > B

All primitive types

NULL if A or B is NULL, TRUE if expression A is greater than expression B otherwise FALSE

A >= B

All primitive types

NULL if A or B is NULL, TRUE if expression A is greater than or equal to expression B otherwise FALSE

A IS NULL

all types

TRUE if expression A evaluates to NULL otherwise FALSE

A IS NOT NULL

All types

TRUE if expression A evaluates to NULL otherwise FALSE

A LIKE B

strings

NULL if A or B is NULL, TRUE if string A matches the SQL simple regular expression B, otherwise FALSE. The comparison is done character by character. The _ character in B matches any character in A(similar to . in posix regular expressions) while the % character in B matches an arbitrary number of characters in A(similar to .* in posix regular expressions) e.g. 'foobar' like 'foo' evaluates to FALSE where as 'foobar' like 'foo_ _ _' evaluates to TRUE and so does 'foobar' like 'foo%'

A RLIKE B

strings

NULL if A or B is NULL, TRUE if string A matches the Java regular expression B(See Java regular expressions syntax), otherwise FALSE e.g. 'foobar' rlike 'foo' evaluates to FALSE where as 'foobar' rlike '^f.*r$' evaluates to TRUE

A REGEXP B

strings

Same as RLIKE

6.1.2?????代數(shù)操作符

返回?cái)?shù)字類型,如果任意一個(gè)操作符為NULL,則結(jié)果為NULL

Operator

Operand types

Description

A + B

All number types

Gives the result of adding A and B. The type of the result is the same as the common parent(in the type hierarchy) of the types of the operands. e.g. since every integer is a float, therefore float is a containing type of integer so the + operator on a float and an int will result in a float.

A - B

All number types

Gives the result of subtracting B from A. The type of the result is the same as the common parent(in the type hierarchy) of the types of the operands.

A * B

All number types

Gives the result of multiplying A and B. The type of the result is the same as the common parent(in the type hierarchy) of the types of the operands. Note that if the multiplication causing overflow, you will have to cast one of the operators to a type higher in the type hierarchy.

A / B

All number types

Gives the result of dividing B from A. The result is a double type.

A % B

All number types

Gives the reminder resulting from dividing A by B. The type of the result is the same as the common parent(in the type hierarchy) of the types of the operands.

A & B

All number types

Gives the result of bitwise AND of A and B. The type of the result is the same as the common parent(in the type hierarchy) of the types of the operands.

A | B

All number types

Gives the result of bitwise OR of A and B. The type of the result is the same as the common parent(in the type hierarchy) of the types of the operands.

A ^ B

All number types

Gives the result of bitwise XOR of A and B. The type of the result is the same as the common parent(in the type hierarchy) of the types of the operands.

~A

All number types

Gives the result of bitwise NOT of A. The type of the result is the same as the type of A.

?

6.1.3?????邏輯操作符

6.1.4?????復(fù)雜類型操作符

Constructor Function

Operands

Description

Map

(key1, value1, key2, value2, ...)

Creates a map with the given key/value pairs

Struct

(val1, val2, val3, ...)

Creates a struct with the given field values. Struct field names will be col1, col2, ...

Array

(val1, val2, ...)

Creates an array with the given elements

?

6.1.5?????內(nèi)建函數(shù)

6.1.6?????數(shù)學(xué)函數(shù)

6.1.7?????集合函數(shù)

6.1.8?????類型轉(zhuǎn)換

?

6.1.9?????日期函數(shù)

返回值類型

名稱

描述

string

from_unixtime(int unixtime)

將時(shí)間戳(unix epoch秒數(shù))轉(zhuǎn)換為日期時(shí)間字符串,例如from_unixtime(0)="1970-01-01 00:00:00"

bigint

unix_timestamp()

獲得當(dāng)前時(shí)間戳

bigint

unix_timestamp(string date)

獲得date表示的時(shí)間戳

bigint

to_date(string timestamp)

返回日期字符串,例如to_date("1970-01-01 00:00:00") = "1970-01-01"

string

year(string date)

返回年,例如year("1970-01-01 00:00:00") = 1970,year("1970-01-01") = 1970

int

month(string date)

int

day(string date) dayofmonth(date)

int

hour(string date)

int

minute(string date)

int

second(string date)

int

weekofyear(string date)

int

datediff(string enddate, string startdate)

返回enddate和startdate的天數(shù)的差,例如datediff('2009-03-01', '2009-02-27') = 2

int

date_add(string startdate, int days)

加days天數(shù)到startdate: date_add('2008-12-31', 1) = '2009-01-01'

int

date_sub(string startdate, int days)

減days天數(shù)到startdate: date_sub('2008-12-31', 1) = '2008-12-30'

?

6.1.10?????????????條件函數(shù)

返回值類型

名稱

描述

-

if(boolean testCondition, T valueTrue, T valueFalseOrNull)

當(dāng)testCondition為真時(shí)返回valueTrue,testCondition為假或NULL時(shí)返回valueFalseOrNull

-

COALESCE(T v1, T v2, ...)

返回列表中的第一個(gè)非空元素,如果列表元素都為空則返回NULL

-

CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END

a = b,返回c;a = d,返回e;否則返回f

-

CASE WHEN a THEN b [WHEN c THEN d]* [ELSE e] END

a?為真,返回b;c為真,返回d;否則e

?

6.1.11?????????????字符串函數(shù)

The following are built-in String functionsare supported in hive:

返回值類型

名稱?

描述

Int

length(string A)

返回字符串長(zhǎng)度

String

reverse(string A)

反轉(zhuǎn)字符串

String

concat(string A, string B...)

合并字符串,例如concat('foo', 'bar')='foobar'。注意這一函數(shù)可以接受任意個(gè)數(shù)的參數(shù)

String

substr(string A, int start) substring(string A, int start)

返回子串,例如substr('foobar', 4)='bar'

String

substr(string A, int start, int len) substring(string A, int start, int len)

返回限定長(zhǎng)度的子串,例如substr('foobar', 4, 1)='b'

String

upper(string A) ucase(string A)

轉(zhuǎn)換為大寫

String

lower(string A) lcase(string A)

轉(zhuǎn)換為小寫

String

trim(string A)

String

ltrim(string A)

String

rtrim(string A)

String

regexp_replace(string A, string B, string C)

Returns the string resulting from replacing all substrings in B that match the Java regular expression syntax(See Java regular expressions syntax) with C e.g. regexp_replace("foobar", "oo|ar", "") returns 'fb.' Note that some care is necessary in using predefined character classes: using '\s' as the second argument will match the letter s; '\\s' is necessary to match whitespace, etc.

String

regexp_extract(string subject, string pattern, int intex)

返回使用正則表達(dá)式提取的子字串。例如,regexp_extract('foothebar', 'foo(.*?)(bar)', 2)='bar'。注意使用特殊字符的規(guī)則:使用'\s'代表的是字符's';空白字符需要使用'\\s',以此類推。

String

parse_url(string urlString, string partToExtract)

解析URL字符串,partToExtract的可選項(xiàng)有:HOST, PATH, QUERY, REF, PROTOCOL, FILE, AUTHORITY, USERINFO。

例如,

parse_url('http://facebook.com/path/p1.php?query=1', 'HOST')='facebook.com'

parse_url('http://facebook.com/path/p1.php?query=1', 'PATH')='/path/p1.php'

parse_url('http://facebook.com/path/p1.php?query=1', 'QUERY')='query=1',可以指定key來返回特定參數(shù),key的格式是QUERY:<KEY_NAME>,例如QUERY:k1

parse_url('http://facebook.com/path/p1.php?query=1&field=2','QUERY','query')='1'可以用來取出外部渲染參數(shù)key對(duì)應(yīng)的value值

parse_url('http://facebook.com/path/p1.php?query=1&field=2','QUERY','field')='2'

parse_url('http://facebook.com/path/p1.php?query=1#Ref', 'REF')='Ref'

parse_url('http://facebook.com/path/p1.php?query=1#Ref', 'PROTOCOL')='http'

String

get_json_object(string json_string, string path)

解析json字符串。若源json字符串非法則返回NULL。path參數(shù)支持JSONPath的一個(gè)子集,包括以下標(biāo)記:

$: Root object

[]: Subscript operator for array

&: Wildcard for []

.: Child operator

String

space(int n)

返回一個(gè)包含n個(gè)空格的字符串

String

repeat(string str, int n)

重復(fù)str字符串n遍

String

ascii(string str)

返回str中第一個(gè)字符的ascii碼

String

lpad(string str, int len, string pad)

左端補(bǔ)齊str到長(zhǎng)度為len。補(bǔ)齊的字符串由pad指定。

String

rpad(string str, int len, string pad)

右端補(bǔ)齊str到長(zhǎng)度為len。補(bǔ)齊的字符串由pad指定。

Array

split(string str, string pat)

返回使用pat作為正則表達(dá)式分割str字符串的列表。例如,split('foobar', 'o')[2] = 'bar'。?不是很明白這個(gè)結(jié)果

Int

find_in_set(string str, string strList)

Returns the first occurance of str in strList where strList is a comma-delimited string. Returns null if either argument is null. Returns 0 if the first argument contains any commas. e.g. find_in_set('ab', 'abc,b,ab,c,def') returns 3

?

6.2?UDTF

UDTF即Built-inTable-Generating Functions

使用這些UDTF函數(shù)有一些限制:

1、SELECT里面不能有其它字段

如:SELECTpageid, explode(adid_list) AS myCol...

2、不能嵌套

如:SELECTexplode(explode(adid_list)) AS myCol...不支持

3、不支持GROUP BY / CLUSTER BY / DISTRIBUTE BY / SORTBY

如:SELECTexplode(adid_list) AS myCol ... GROUP BY myCol

?

6.2.1??Explode

將數(shù)組進(jìn)行轉(zhuǎn)置

例如:

1、create table test2(mycol array<int>);

2、insert OVERWRITE table test2 select * from (select array(1,2,3) froma union all select array(7,8,9)? fromd)c;

3、hive> select * from test2;

OK

[1,2,3]

[7,8,9]

3、? hive> SELECT explode(myCol) AS myNewCol FROM test2;

OK

1

2

3

7

8

9

?

?

?

7.??HIVE?的MAP/REDUCE

7.1?JOIN

對(duì)于 JOIN 操作:

INSERT OVERWRITE TABLE pv_users

SELECT pv.pageid, u.age FROM page_view pv JOIN user u ON (pv.userid = u.userid);

實(shí)現(xiàn)過程為:

  • Map:
    • 以 JOIN ON 條件中的列作為 Key,如果有多個(gè)列,則 Key 是這些列的組合
    • 以 JOIN 之后所關(guān)心的列作為 Value,當(dāng)有多個(gè)列時(shí),Value 是這些列的組合。在 Value 中還會(huì)包含表的 Tag 信息,用于標(biāo)明此 Value 對(duì)應(yīng)于哪個(gè)表。
    • 按照 Key 進(jìn)行排序。
  • Shuffle:
    • 根據(jù) Key 的值進(jìn)行 Hash,并將 Key/Value 對(duì)按照 Hash 值推至不同對(duì) Reduce 中。
  • Reduce:
    • Reducer 根據(jù) Key 值進(jìn)行 Join 操作,并且通過 Tag 來識(shí)別不同的表中的數(shù)據(jù)。

具體實(shí)現(xiàn)過程如圖:

7.2?GROUPBY

SELECT pageid, age, count(1) FROM pv_users GROUP BY pageid, age;

具體實(shí)現(xiàn)過程如圖:

7.3?DISTINCT

SELECT age, count(distinct pageid) FROM pv_users GROUP BY age;

實(shí)現(xiàn)過程如圖:

?

8.??使用HIVE注意點(diǎn)

8.1?字符集

Hadoop和Hive都是用UTF-8編碼的,所以,?所有中文必須是UTF-8編碼,?才能正常使用

備注:中文數(shù)據(jù)load到表里面,?如果字符集不同,很有可能全是亂碼需要做轉(zhuǎn)碼的,?但是hive本身沒有函數(shù)來做這個(gè)

?

8.2?壓縮

hive.exec.compress.output?這個(gè)參數(shù),?默認(rèn)是?false,但是很多時(shí)候貌似要單獨(dú)顯式設(shè)置一遍

否則會(huì)對(duì)結(jié)果做壓縮的,如果你的這個(gè)文件后面還要在hadoop下直接操作,?那么就不能壓縮了

?

8.3?count(distinct)

當(dāng)前的 Hive 不支持在一條查詢語句中有多 Distinct。如果要在 Hive 查詢語句中實(shí)現(xiàn)多Distinct,需要使用至少n+1 條查詢語句(n為distinct的數(shù)目),前n 條查詢分 別對(duì) n 個(gè)列去重,最后一條查詢語句對(duì) n 個(gè)去重之后的列做 Join 操作,得到最終結(jié)果。

?

8.4?JOIN

只支持等值連接

?

8.5?DML操作

只支持INSERT/LOAD操作,無UPDATE和DELTE

8.6?HAVING

不支持HAVING操作。如果需要這個(gè)功能要嵌套一個(gè)子查詢用where限制

8.7?子查詢

Hive不支持where子句中的子查詢

子查詢,只允許子查詢?cè)趂rom中出現(xiàn)

SELECT station, year, AVG(max_temperature)FROM (SELECT station, year, MAX(temperature) AS max_temperature FROM records2WHERE temperature != 9999 AND (quality = 0 OR quality = 1 OR quality = 4 ORquality = 5 OR quality = 9) GROUP BY station, year) mt GROUP BY station, year;

?

8.8?Join中處理null值的語義區(qū)別

SQL標(biāo)準(zhǔn)中,任何對(duì)null的操作(數(shù)值比較,字符串操作等)結(jié)果都為null。Hive對(duì)null值處理的邏輯和標(biāo)準(zhǔn)基本一致,除了Join時(shí)的特殊邏輯。

這里的特殊邏輯指的是,Hive的Join中,作為Join key的字段比較,null=null是有意義的,且返回值為true。檢查以下查詢:

select u.uid, count(u.uid)

from t_weblog l join t_user u on (l.uid = u.uid) group by u.uid;

查詢中,t_weblog表中uid為空的記錄將和t_user表中uid為空的記錄做連接,即l.uid =u.uid=null成立。

如果需要與標(biāo)準(zhǔn)一致的語義,我們需要改寫查詢手動(dòng)過濾null值的情況:

select u.uid, count(u.uid)

from t_weblog l join t_user u

on (l.uid = u.uid and l.uid is not null and u.uid isnot null)

group by u.uid;

實(shí)踐中,這一語義區(qū)別也是經(jīng)常導(dǎo)致數(shù)據(jù)傾斜的原因之一。

?

8.9?分號(hào)字符

分號(hào)是SQL語句結(jié)束標(biāo)記,在HiveQL中也是,但是在HiveQL中,對(duì)分號(hào)的識(shí)別沒有那么智慧,例如:

select concat(cookie_id,concat(';',’zoo’))from c02_clickstat_fatdt1 limit 2;

FAILED: Parse Error: line 0:-1 cannotrecognize input '<EOF>' in function specification

可以推斷,Hive解析語句的時(shí)候,只要遇到分號(hào)就認(rèn)為語句結(jié)束,而無論是否用引號(hào)包含起來。

解決的辦法是,使用分號(hào)的八進(jìn)制的ASCII碼進(jìn)行轉(zhuǎn)義,那么上述語句應(yīng)寫成:

selectconcat(cookie_id,concat('\073','zoo')) from c02_clickstat_fatdt1 limit 2;

為什么是八進(jìn)制ASCII碼?

我嘗試用十六進(jìn)制的ASCII碼,但Hive會(huì)將其視為字符串處理并未轉(zhuǎn)義,好像僅支持八進(jìn)制,原因不詳。這個(gè)規(guī)則也適用于其他非SELECT語句,如CREATE TABLE中需要定義分隔符,那么對(duì)不可見字符做分隔符就需要用八進(jìn)制的ASCII碼來轉(zhuǎn)義。

?

8.10????????Insert

8.10.1?????????????新增數(shù)據(jù)

根據(jù)語法Insert必須加“OVERWRITE”關(guān)鍵字,也就是說每一次插入都是一次重寫。那如何實(shí)現(xiàn)表中新增數(shù)據(jù)呢?

假設(shè)Hive中有表xiaojun1,

hive> DESCRIBE xiaojun1;

OK

id int

value int

hive> SELECT * FROM xiaojun1;

OK

3 4

1 2

2 3

現(xiàn)增加一條記錄:

hive> INSERT OVERWRITE TABLE xiaojun1

SELECT id, value FROM (

SELECT id, value FROM xiaojun1

UNION ALL

SELECT 4 AS id, 5 AS value FROM xiaojun1 limit 1

) u;

結(jié)果是:

hive>SELECT * FROM p1;

OK

3 4

4 5

2 3

1 2

其中的關(guān)鍵在于, 關(guān)鍵字UNION ALL的應(yīng)用, 即將原有數(shù)據(jù)集和新增數(shù)據(jù)集進(jìn)行結(jié)合, 然后重寫表.

?

8.10.2?????????????插入次序

?

INSERT OVERWRITE TABLE在插入數(shù)據(jù)時(shí),是按照后面的SELECT語句中的字段順序插入的. 也就說, 當(dāng)id 和value 的位置互換, 那么value將被寫入id, 同id被寫入value.

8.10.3?????????????初始值

INSERT OVERWRITE TABLE在插入數(shù)據(jù)時(shí), 后面的字段的初始值應(yīng)注意與表定義中的一致性. 例如, 當(dāng)為一個(gè)STRING類型字段初始為NULL時(shí):

NULL AS field_name // 這可能會(huì)被提示定義類型為STRING, 但這里是void

CAST(NULL AS STRING) AS field_name // 這樣是正確的

又如, 為一個(gè)BIGINT類型的字段初始為0時(shí):

CAST(0 AS BIGINT) AS field_name

?

9.??優(yōu)化

9.1?HADOOP計(jì)算框架特性

  • 數(shù)據(jù)量大不是問題,數(shù)據(jù)傾斜是個(gè)問題。
  • jobs數(shù)比較多的作業(yè)運(yùn)行效率相對(duì)比較低,比如即使有幾百行的表,如果多次關(guān)聯(lián)多次匯總,產(chǎn)生十幾個(gè)jobs,耗時(shí)很長(zhǎng)。原因是map reduce作業(yè)初始化的時(shí)間是比較長(zhǎng)的。
  • sum,count,max,min等UDAF,不怕數(shù)據(jù)傾斜問題,hadoop在map端的匯總合并優(yōu)化,使數(shù)據(jù)傾斜不成問題。
  • count(distinct ),在數(shù)據(jù)量大的情況下,效率較低,如果是多count(distinct )效率更低,因?yàn)閏ount(distinct)是按group by 字段分組,按distinct字段排序,一般這種分布方式是很傾斜的,比如男uv,女uv,淘寶一天30億的pv,如果按性別分組,分配2個(gè)reduce,每個(gè)reduce處理15億數(shù)據(jù)。

9.2?優(yōu)化的常用手段

  • 好的模型設(shè)計(jì)事半功倍。
  • 解決數(shù)據(jù)傾斜問題。
  • 減少job數(shù)。
  • 設(shè)置合理的map reduce的task數(shù),能有效提升性能。(比如,10w+級(jí)別的計(jì)算,用160個(gè)reduce,那是相當(dāng)?shù)睦速M(fèi),1個(gè)足夠)。
  • 了解數(shù)據(jù)分布,自己動(dòng)手解決數(shù)據(jù)傾斜問題是個(gè)不錯(cuò)的選擇。set hive.groupby.skewindata=true;這是通用的算法優(yōu)化,但算法優(yōu)化有時(shí)不能適應(yīng)特定業(yè)務(wù)背景,開發(fā)人員了解業(yè)務(wù),了解數(shù)據(jù),可以通過業(yè)務(wù)邏輯精確有效的解決數(shù)據(jù)傾斜問題。
  • 數(shù)據(jù)量較大的情況下,慎用count(distinct),count(distinct)容易產(chǎn)生傾斜問題。
  • 對(duì)小文件進(jìn)行合并,是行至有效的提高調(diào)度效率的方法,假如所有的作業(yè)設(shè)置合理的文件數(shù),對(duì)云梯的整體調(diào)度效率也會(huì)產(chǎn)生積極的正向影響。
  • 優(yōu)化時(shí)把握整體,單個(gè)作業(yè)最優(yōu)不如整體最優(yōu)。

???

9.3?全排序

Hive的排序關(guān)鍵字是SORT BY,它有意區(qū)別于傳統(tǒng)數(shù)據(jù)庫的ORDER BY也是為了強(qiáng)調(diào)兩者的區(qū)別–SORT BY只能在單機(jī)范圍內(nèi)排序。 [王黎15] ?

9.3.1?????例1

set mapred.reduce.tasks=2;

原值

select cookie_id,page_id,id fromc02_clickstat_fatdt1

where cookie_id IN('1.193.131.218.1288611279693.0','1.193.148.164.1288609861509.2')

1.193.148.164.1288609861509.2??113181412886099008861288609901078194082403????? 684000005

1.193.148.164.1288609861509.2??127001128860563972141288609859828580660473????? 684000015

1.193.148.164.1288609861509.2?? 113181412886099165721288609915890452725326????? 684000018

1.193.131.218.1288611279693.0??01c183da6e4bc50712881288611540109914561053????? 684000114

1.193.131.218.1288611279693.0??01c183da6e4bc22412881288611414343558274174????? 684000118

1.193.131.218.1288611279693.0??01c183da6e4bc50712881288611511781996667988????? 684000121

1.193.131.218.1288611279693.0??01c183da6e4bc22412881288611523640691739999????? 684000126

1.193.131.218.1288611279693.0??01c183da6e4bc50712881288611540109914561053????? 684000128

?

?

hive> select cookie_id,page_id,id fromc02_clickstat_fatdt1 where

cookie_idIN('1.193.131.218.1288611279693.0','1.193.148.164.1288609861509.2')

SORT BY COOKIE_ID,PAGE_ID;

SORT排序后的值

1.193.131.218.1288611279693.0?????????? 684000118?????? 01c183da6e4bc22412881288611414343558274174????? 684000118

1.193.131.218.1288611279693.0?????????? 684000114??????01c183da6e4bc50712881288611540109914561053????? 684000114

1.193.131.218.1288611279693.0?????????? 684000128??????01c183da6e4bc50712881288611540109914561053????? 684000128

1.193.148.164.1288609861509.2?????????? 684000005??????113181412886099008861288609901078194082403????? 684000005

1.193.148.164.1288609861509.2?????????? 684000018??????113181412886099165721288609915890452725326????? 684000018

1.193.131.218.1288611279693.0?????????? 684000126??????01c183da6e4bc22412881288611523640691739999????? 684000126

1.193.131.218.1288611279693.0?????????? 684000121??????01c183da6e4bc50712881288611511781996667988????? 684000121

1.193.148.164.1288609861509.2?????????? 684000015??????127001128860563972141288609859828580660473????? 684000015

?

select cookie_id,page_id,id fromc02_clickstat_fatdt1

where cookie_idIN('1.193.131.218.1288611279693.0','1.193.148.164.1288609861509.2')

ORDER BY PAGE_ID,COOKIE_ID;

1.193.131.218.1288611279693.0?????????? 684000118??????01c183da6e4bc22412881288611414343558274174????? 684000118

1.193.131.218.1288611279693.0?????????? 684000126??????01c183da6e4bc22412881288611523640691739999????? 684000126

1.193.131.218.1288611279693.0?????????? 684000121??????01c183da6e4bc50712881288611511781996667988????? 684000121

1.193.131.218.1288611279693.0?????????? 684000114??????01c183da6e4bc50712881288611540109914561053????? 684000114

1.193.131.218.1288611279693.0?????????? 684000128?????? 01c183da6e4bc50712881288611540109914561053????? 684000128

1.193.148.164.1288609861509.2?????????? 684000005??????113181412886099008861288609901078194082403????? 684000005

1.193.148.164.1288609861509.2?????????? 684000018??????113181412886099165721288609915890452725326???? ?684000018

1.193.148.164.1288609861509.2?????????? 684000015??????127001128860563972141288609859828580660473????? 684000015

可以看到SORT和ORDER排序出來的值不一樣。一開始我指定了2個(gè)reduce進(jìn)行數(shù)據(jù)分發(fā)(各自進(jìn)行排序)。結(jié)果不一樣的主要原因是上述查詢沒有reduce key,hive會(huì)生成隨機(jī)數(shù)作為reduce key。這樣的話輸入記錄也隨機(jī)地被分發(fā)到不同reducer機(jī)器上去了。為了保證reducer之間沒有重復(fù)的cookie_id記錄,可以使用DISTRIBUTE BY關(guān)鍵字指定分發(fā)key為cookie_id。

select cookie_id,country,id,page_id,id fromc02_clickstat_fatdt1 where cookie_idIN('1.193.131.218.1288611279693.0','1.193.148.164.1288609861509.2')? distribute by cookie_id SORT BY COOKIE_ID,page_id;

1.193.131.218.1288611279693.0?????????? 684000118??????01c183da6e4bc22412881288611414343558274174????? 684000118

1.193.131.218.1288611279693.0?????????? 684000126??????01c183da6e4bc22412881288611523640691739999????? 684000126

1.193.131.218.1288611279693.0?????????? 684000121??????01c183da6e4bc50712881288611511781996667988????? 684000121

1.193.131.218.1288611279693.0?????????? 684000114??????01c183da6e4bc50712881288611540109914561053????? 684000114

1.193.131.218.1288611279693.0??????? ???684000128??????01c183da6e4bc50712881288611540109914561053????? 684000128

1.193.148.164.1288609861509.2?????????? 684000005??????113181412886099008861288609901078194082403????? 684000005

1.193.148.164.1288609861509.2?????????? 684000018?????? 113181412886099165721288609915890452725326????? 684000018

1.193.148.164.1288609861509.2?????????? 684000015??????127001128860563972141288609859828580660473????? 684000015

9.3.2?????例2

CREATE TABLE if not exists t_order(

?

id int, -- 訂單編號(hào)

?

sale_id int, -- 銷售ID

?

customer_id int, -- 客戶ID

?

product _id int, -- 產(chǎn)品ID

?

amount int -- 數(shù)量

?

) PARTITIONED BY (ds STRING);

在表中查詢所有銷售記錄,并按照銷售ID和數(shù)量排序:

set mapred.reduce.tasks=2;

?

Select sale_id, amount from t_order

?

Sort by sale_id, amount;

這一查詢可能得到非期望的排序。指定的2個(gè)reducer分發(fā)到的數(shù)據(jù)可能是(各自排序):

Reducer1:

Sale_id | amount

?

0 | 100

?

1 | 30

?

1 | 50

?

2 | 20

Reducer2:

Sale_id | amount

?

0?| 110

?

0 | 120

?

3 | 50

?

4 | 20

使用DISTRIBUTE BY關(guān)鍵字指定分發(fā)key為sale_id。改造后的HQL如下:

set mapred.reduce.tasks=2;

?

Select sale_id, amount from t_order

?

Distribute by sale_id

?

Sort by sale_id, amount;

這樣能夠保證查詢的銷售記錄集合中,銷售ID對(duì)應(yīng)的數(shù)量是正確排序的,但是銷售ID不能正確排序,原因是hive使用hadoop默認(rèn)的HashPartitioner分發(fā)數(shù)據(jù)。

這就涉及到一個(gè)全排序的問題。解決的辦法無外乎兩種:

1.) 不分發(fā)數(shù)據(jù),使用單個(gè)reducer:

set mapred.reduce.tasks=1;

這一方法的缺陷在于reduce端成為了性能瓶頸,而且在數(shù)據(jù)量大的情況下一般都無法得到結(jié)果。但是實(shí)踐中這仍然是最常用的方法,原因是通常排序的查詢是為了得到排名靠前的若干結(jié)果,因此可以用limit子句大大減少數(shù)據(jù)量。使用limit n后,傳輸?shù)絩educe端(單機(jī))的數(shù)據(jù)記錄數(shù)就減少到n* (map個(gè)數(shù))。

2.) 修改Partitioner,這種方法可以做到全排序。這里可以使用Hadoop自帶的TotalOrderPartitioner(來自于Yahoo!的TeraSort項(xiàng)目),這是一個(gè)為了支持跨reducer分發(fā)有序數(shù)據(jù)開發(fā)的Partitioner,它需要一個(gè)SequenceFile格式的文件指定分發(fā)的數(shù)據(jù)區(qū)間。如果我們已經(jīng)生成了這一文件(存儲(chǔ)在/tmp/range_key_list,分成100個(gè)reducer),可以將上述查詢改寫為

set mapred.reduce.tasks=100;

?

sethive.mapred.partitioner=org.apache.hadoop.mapred.lib.TotalOrderPartitioner;

?

settotal.order.partitioner.path=/tmp/ range_key_list;

?

Select sale_id, amount from t_order

?

Cluster by sale_id

?

Sort by amount;

有很多種方法生成這一區(qū)間文件(例如hadoop自帶的o.a.h.mapreduce.lib.partition.InputSampler工具)。這里介紹用Hive生成的方法,例如有一個(gè)按id有序的t_sale表:

CREATE TABLE if not exists t_sale (

?

id int,

?

name string,

?

loc string

?

);

則生成按sale_id分發(fā)的區(qū)間文件的方法是:

create external table range_keys(sale_idint)

?

row format serde

?

'org.apache.hadoop.hive.serde2.binarysortable.BinarySortableSerDe'

?

stored as

?

inputformat

?

'org.apache.hadoop.mapred.TextInputFormat'

?

outputformat

?

'org.apache.hadoop.hive.ql.io.HiveNullValueSequenceFileOutputFormat'

?

location '/tmp/range_key_list';

?

?

?

insert overwrite table range_keys

?

select distinct sale_id

?

from source t_salesampletable(BUCKET 100 OUT OF 100 ON rand()) s

?

sort by sale_id;

生成的文件(/tmp/range_key_list目錄下)可以讓TotalOrderPartitioner按sale_id有序地分發(fā)reduce處理的數(shù)據(jù)。區(qū)間文件需要考慮的主要問題是數(shù)據(jù)分發(fā)的均衡性,這有賴于對(duì)數(shù)據(jù)深入的理解。

9.4?怎樣做笛卡爾積

當(dāng)Hive設(shè)定為嚴(yán)格模式(hive.mapred.mode=strict)時(shí),不允許在HQL語句中出現(xiàn)笛卡爾積,這實(shí)際說明了Hive對(duì)笛卡爾積支持較弱。因?yàn)檎也坏絁oin key,Hive只能使用1個(gè)reducer來完成笛卡爾積。

當(dāng)然也可以用上面說的limit的辦法來減少某個(gè)表參與join的數(shù)據(jù)量,但對(duì)于需要笛卡爾積語義的需求來說,經(jīng)常是一個(gè)大表和一個(gè)小表的Join操作,結(jié)果仍然很大(以至于無法用單機(jī)處理),這時(shí)MapJoin才是最好的解決辦法。

MapJoin,顧名思義,會(huì)在Map端完成Join操作。這需要將Join操作的一個(gè)或多個(gè)表完全讀入內(nèi)存。

MapJoin的用法是在查詢/子查詢的SELECT關(guān)鍵字后面添加/*+ MAPJOIN(tablelist) */提示優(yōu)化器轉(zhuǎn)化為MapJoin(目前Hive的優(yōu)化器不能自動(dòng)優(yōu)化MapJoin)。其中tablelist可以是一個(gè)表,或以逗號(hào)連接的表的列表。tablelist中的表將會(huì)讀入內(nèi)存,應(yīng)該將小表寫在這里。

PS:有用戶說MapJoin在子查詢中可能出現(xiàn)未知BUG。在大表和小表做笛卡爾積時(shí),規(guī)避笛卡爾積的方法是,給Join添加一個(gè)Join key,原理很簡(jiǎn)單:將小表擴(kuò)充一列join key,并將小表的條目復(fù)制數(shù)倍,join key各不相同;將大表擴(kuò)充一列join key為隨機(jī)數(shù)。

9.5?怎樣寫exist/in子句

Hive不支持where子句中的子查詢,SQL常用的exist in子句需要改寫。這一改寫相對(duì)簡(jiǎn)單。考慮以下SQL查詢語句:

SELECT a.key, a.value

?

FROM a

?

WHERE a.key in

?

(SELECT b.key

?

FROM B);

可以改寫為

SELECT a.key, a.value

?

FROM a LEFT OUTER JOIN b ON (a.key =b.key)

?

WHERE b.key <> NULL;

一個(gè)更高效的實(shí)現(xiàn)是利用left semi join改寫為:

SELECT a.key, a.val

?

FROM a LEFT SEMI JOIN b on (a.key =b.key);

left semi join是0.5.0以上版本的特性。

9.6?怎樣決定reducer個(gè)數(shù)

Hadoop MapReduce程序中,reducer個(gè)數(shù)的設(shè)定極大影響執(zhí)行效率,這使得Hive怎樣決定reducer個(gè)數(shù)成為一個(gè)關(guān)鍵問題。遺憾的是Hive的估計(jì)機(jī)制很弱,不指定reducer個(gè)數(shù)的情況下,Hive會(huì)猜測(cè)確定一個(gè)reducer個(gè)數(shù),基于以下兩個(gè)設(shè)定:

1. hive.exec.reducers.bytes.per.reducer(默認(rèn)為1000^3)

2. hive.exec.reducers.max(默認(rèn)為999)

計(jì)算reducer數(shù)的公式很簡(jiǎn)單:

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

通常情況下,有必要手動(dòng)指定reducer個(gè)數(shù)。考慮到map階段的輸出數(shù)據(jù)量通常會(huì)比輸入有大幅減少,因此即使不設(shè)定reducer個(gè)數(shù),重設(shè)參數(shù)2還是必要的。依據(jù)Hadoop的經(jīng)驗(yàn),可以將參數(shù)2設(shè)定為0.95*(集群中TaskTracker個(gè)數(shù))。

9.7?合并MapReduce操作

Multi-group by

Multi-group by是Hive的一個(gè)非常好的特性,它使得Hive中利用中間結(jié)果變得非常方便。例如,

FROM (SELECT a.status, b.school,b.gender

?

FROM status_updates a JOIN profilesb

?

ON (a.userid = b.userid and

?

a.ds='2009-03-20' )

?

) subq1

?

INSERT OVERWRITE TABLEgender_summary

?

PARTITION(ds='2009-03-20')

?

SELECT subq1.gender, COUNT(1) GROUPBY subq1.gender

?

INSERT OVERWRITE TABLEschool_summary

?

PARTITION(ds='2009-03-20')

?

SELECT subq1.school, COUNT(1) GROUPBY subq1.school

上述查詢語句使用了Multi-group by特性連續(xù)group by了2次數(shù)據(jù),使用不同的groupby key。這一特性可以減少一次MapReduce操作。

Multi-distinct

Multi-distinct是淘寶開發(fā)的另一個(gè)multi-xxx特性,使用Multi-distinct可以在同一查詢/子查詢中使用多個(gè)distinct,這同樣減少了多次MapReduce操作

?

9.8? Bucket? 與sampling

Bucket是指將數(shù)據(jù)以指定列的值為key進(jìn)行hash,hash到指定數(shù)目的桶中。這樣就可以支持高效采樣了。

如下例就是以u(píng)serid這一列為bucket的依據(jù),共設(shè)置32個(gè)buckets

CREATETABLE page_view(viewTime INT, userid BIGINT,

????????????????????page_url STRING,referrer_url STRING,

????????????????????ip STRING COMMENT 'IPAddress of the User')

????COMMENT 'This is the page view table'

????PARTITIONED BY(dt STRING, country STRING)

????CLUSTEREDBY(userid) SORTED BY(viewTime) INTO 32 BUCKETS

????ROW FORMAT DELIMITED

????????????FIELDS TERMINATED BY '1'

????????????COLLECTION ITEMS TERMINATED BY '2'

????????????MAP KEYS TERMINATED BY '3'

???? STORED AS SEQUENCEFILE; [王黎16] ?

Sampling可以在全體數(shù)據(jù)上進(jìn)行采樣,這樣效率自然就低,它還是要去訪問所有數(shù)據(jù)。而如果一個(gè)表已經(jīng)對(duì)某一列制作了bucket,就可以采樣所有桶中指定序號(hào)的某個(gè)桶,這就減少了訪問量。

如下例所示就是采樣了page_view中32個(gè)桶中的第三個(gè)桶。

SELECT *FROM page_view?TABLESAMPLE(BUCKET 3 OUT OF 32);

?

9.9?Partition

Partition就是分區(qū)。分區(qū)通過在創(chuàng)建表時(shí)啟用partition by實(shí)現(xiàn),用來partition的維度并不是實(shí)際數(shù)據(jù)的某一列,具體分區(qū)的標(biāo)志是由插入內(nèi)容時(shí)給定的。當(dāng)要查詢某一分區(qū)的內(nèi)容時(shí)可以采用where語句,形似where tablename.partition_key >a來實(shí)現(xiàn)。

創(chuàng)建含分區(qū)的表

????CREATE TABLE page_view(viewTime INT, useridBIGINT,

????????????????????page_url STRING, referrer_url STRING,

????????????????????ip STRING COMMENT 'IPAddress of the User')

????PARTITIONED BY(date STRING, country STRING)

????ROW FORMAT DELIMITED

????????????FIELDS TERMINATED BY '1'

???? STORED AS TEXTFILE; [王黎17] ?

載入內(nèi)容,并指定分區(qū)標(biāo)志

LOAD DATALOCAL INPATH `/tmp/pv_2008-06-08_us.txt` INTO TABLE page_view?PARTITION(date='2008-06-08',country='US');

查詢指定標(biāo)志的分區(qū)內(nèi)容

SELECTpage_views.*

????FROM page_views

????WHERE?page_views.date >='2008-03-01' AND page_views.date <= '2008-03-31'?AND page_views.referrer_urllike '%xyz.com';

?

9.10????????JOIN

9.10.1?????????????JOIN原則

在使用寫有 Join 操作的查詢語句時(shí)有一條原則:應(yīng)該將條目少的表/子查詢放在 Join 操作符的左邊。原因是在 Join 操作的 Reduce 階段,位于 Join 操作符左邊的表的內(nèi)容會(huì)被加載進(jìn)內(nèi)存,將條目少的表放在左邊,可以有效減少發(fā)生OOM 錯(cuò)誤的幾率。對(duì)于一條語句中有多個(gè) Join 的情況,如果 Join 的條件相同,比如查詢:

INSERT OVERWRITE TABLE pv_users

?SELECT pv.pageid, u.age FROM page_view p

?JOIN user u ON (pv.userid = u.userid)

?JOIN newuser x ON (u.userid = x.userid);?

  • 如果 Join 的 key 相同,不管有多少個(gè)表,都會(huì)則會(huì)合并為一個(gè) Map-Reduce
  • 一個(gè) Map-Reduce 任務(wù),而不是 ‘n’ 個(gè)
  • 在做 OUTER JOIN 的時(shí)候也是一樣

如果 Join 的條件不相同,比如:

INSERT OVERWRITE TABLE pv_users

?? SELECT pv.pageid, u.age FROM page_view p

?? JOIN user u ON (pv.userid = u.userid)

?? JOIN newuser x on (u.age = x.age);??

Map-Reduce 的任務(wù)數(shù)目和Join 操作的數(shù)目是對(duì)應(yīng)的,上述查詢和以下查詢是等價(jià)的:

INSERT OVERWRITE TABLE tmptable

?? SELECT * FROM page_view p JOIN user u

?? ON (pv.userid = u.userid);

?INSERT OVERWRITE TABLE pv_users

?? SELECT x.pageid, x.age FROM tmptable x

?? JOIN newuser y ON (x.age = y.age);???

9.10.2?????????????Map Join

Join 操作在 Map 階段完成,不再需要Reduce,前提條件是需要的數(shù)據(jù)在 Map 的過程中可以訪問到。比如查詢:

INSERT OVERWRITE TABLE pv_users

?? SELECT /*+ MAPJOIN(pv) */ pv.pageid, u.age

?? FROM page_view pv

???? JOIN user u ON (pv.userid = u.userid);???

可以在 Map 階段完成 Join,如圖所示:

相關(guān)的參數(shù)為:

  • hive.join.emit.interval = 1000 ?How many rows in the right-most join operand Hive should buffer before emitting the join result.
  • hive.mapjoin.size.key = 10000
  • hive.mapjoin.cache.numrows = 10000

?

9.11????????數(shù)據(jù)傾斜

9.11.1?????????????空值數(shù)據(jù)傾斜

場(chǎng)景: 如日志中,常會(huì)有信息丟失的問題,比如全網(wǎng)日志中的user_id,如果取其中的user_id和bmw_users關(guān)聯(lián),會(huì)碰到數(shù)據(jù)傾斜的問題。

解決方法1: ?user_id為空的不參與關(guān)聯(lián)

Select * From log a

Join bmw_users b

On a.user_id is not null

And a.user_id = b.user_id

Union all

Select * from log a

where a.user_id is null;

解決方法2 : 賦與空值分新的key值

Select * ?

from log a?

left outer join bmw_users b?

on case when a.user_id is null thenconcat(‘dp_hive’,rand() ) else a.user_id end = b.user_id;?

結(jié)論: 方法2比方法效率更好,不但io少了,而且作業(yè)數(shù)也少了。方法1 log讀取兩次,jobs是2。方法2 job數(shù)是1 。這個(gè)優(yōu)化適合無效id(比如-99,’’,null等)產(chǎn)生的傾斜問題。把空值的key變成一個(gè)字符串加上隨機(jī)數(shù),就能把傾斜的數(shù)據(jù)分到不同的reduce上 ,解決數(shù)據(jù)傾斜問題。附上hadoop通用關(guān)聯(lián)的實(shí)現(xiàn)方法(關(guān)聯(lián)通過二次排序?qū)崿F(xiàn)的,關(guān)聯(lián)的列為parition key,關(guān)聯(lián)的列c1和表的tag組成排序的group key,根據(jù)parition key分配reduce。同一reduce內(nèi)根據(jù)group key排序)

?

9.11.2?????????????不同數(shù)據(jù)類型關(guān)聯(lián)產(chǎn)生數(shù)據(jù)傾斜

場(chǎng)景: 一張表s8的日志,每個(gè)商品一條記錄,要和商品表關(guān)聯(lián)。但關(guān)聯(lián)卻碰到傾斜的問題。s8的日志中有字符串商品id,也有數(shù)字的商品id,類型是string的,但商品中的數(shù)字id是bigint的。猜測(cè)問題的原因是把s8的商品id轉(zhuǎn)成數(shù)字id做hash來分配reduce,所以字符串id的s8日志,都到一個(gè)reduce上了,解決的方法驗(yàn)證了這個(gè)猜測(cè)。

解決方法: 把數(shù)字類型轉(zhuǎn)換成字符串類型

Select * from s8_log a

Left outer join r_auction_auctions b

On a.auction_id = cast(b.auction_id asstring);

9.11.3?????????????大表Join的數(shù)據(jù)偏斜

MapReduce編程模型下開發(fā)代碼需要考慮數(shù)據(jù)偏斜的問題,Hive代碼也是一樣。數(shù)據(jù)偏斜的原因包括以下兩點(diǎn):

1. Map輸出key數(shù)量極少,導(dǎo)致reduce端退化為單機(jī)作業(yè)。

2. Map輸出key分布不均,少量key對(duì)應(yīng)大量value,導(dǎo)致reduce端單機(jī)瓶頸。

Hive中我們使用MapJoin解決數(shù)據(jù)偏斜的問題,即將其中的某個(gè)表(全量)分發(fā)到所有Map端進(jìn)行Join,從而避免了reduce。這要求分發(fā)的表可以被全量載入內(nèi)存。

極限情況下,Join兩邊的表都是大表,就無法使用MapJoin。

這種問題最為棘手,目前已知的解決思路有兩種:

?

1. 如果是上述情況1,考慮先對(duì)Join中的一個(gè)表去重,以此結(jié)果過濾無用信息。這樣一般會(huì)將其中一個(gè)大表轉(zhuǎn)化為小表,再使用MapJoin?。

一個(gè)實(shí)例是廣告投放效果分析,例如將廣告投放者信息表i中的信息填充到廣告曝光日志表w中,使用投放者id關(guān)聯(lián)。因?yàn)閷?shí)際廣告投放者數(shù)量很少(但是投放者信息表i很大),因此可以考慮先在w表中去重查詢所有實(shí)際廣告投放者id列表,以此Join過濾表i,這一結(jié)果必然是一個(gè)小表,就可以使用MapJoin。

?

2. 如果是上述情況2,考慮切分Join中的一個(gè)表為多片,以便將切片全部載入內(nèi)存,然后采用多次MapJoin得到結(jié)果。

一個(gè)實(shí)例是商品瀏覽日志分析,例如將商品信息表i中的信息填充到商品瀏覽日志表w中,使用商品id關(guān)聯(lián)。但是某些熱賣商品瀏覽量很大,造成數(shù)據(jù)偏斜。例如,以下語句實(shí)現(xiàn)了一個(gè)inner join邏輯,將商品信息表拆分成2個(gè)表:

select * from

(

select w.id, w.time, w.amount, i1.name, i1.loc, i1.cat

from w left outer join i sampletable(1 out of 2 on id) i1

)

union all

(

select w.id, w.time, w.amount, i2.name, i2.loc, i2.cat

from w left outer join i sampletable(1 out of 2 on id) i2

)

);

以下語句實(shí)現(xiàn)了left outer join邏輯:

select t1.id, t1.time, t1.amount,

??? coalease(t1.name,t2.name),

??? coalease(t1.loc, t2.loc),

??? coalease(t1.cat, t2.cat)

from (?

??? select w.id, w.time,w.amount, i1.name, i1.loc, i1.cat

??? from w left outer join isampletable(1 out of 2 on id) i1

) t1 left outer join i sampletable(2 out of 2 on id)t2;

上述語句使用Hive的sample table特性對(duì)表做切分。

?

9.12????????合并小文件

文件數(shù)目過多,會(huì)給 HDFS 帶來壓力,并且會(huì)影響處理效率,可以通過合并 Map 和 Reduce 的結(jié)果文件來消除這樣的影響:

hive.merge.mapfiles = true 是否和并 Map 輸出文件,默認(rèn)為 True

hive.merge.mapredfiles = false 是否合并 Reduce 輸出文件,默認(rèn)為 False

hive.merge.size.per.task = 256*1000*1000 合并文件的大小

?

9.13????????GroupBy

·????????Map 端部分聚合:

???? 并不是所有的聚合操作都需要在 Reduce 端完成,很多聚合操作都可以先在Map 端進(jìn)行部分聚合,最后在 Reduce 端得出最終結(jié)果。

????? 基于 Hash

????? 參數(shù)包括:

§? hive.map.aggr = true 是否在 Map 端進(jìn)行聚合,默認(rèn)為 True

§? hive.groupby.mapaggr.checkinterval= 100000 在 Map 端進(jìn)行聚合操作的條目數(shù)目

·????????有數(shù)據(jù)傾斜的時(shí)候進(jìn)行負(fù)載均衡

????? hive.groupby.skewindata= false

???? 當(dāng)選項(xiàng)設(shè)定為 true,生成的查詢計(jì)劃會(huì)有兩個(gè) MR Job。第一個(gè) MR Job 中,Map 的輸出結(jié)果集合會(huì)隨機(jī)分布到 Reduce 中,每個(gè) Reduce 做部分聚合操作,并輸出結(jié)果,這樣處理的結(jié)果是相同的 Group By Key 有可能被分發(fā)到不同的Reduce 中,從而達(dá)到負(fù)載均衡的目的;第二個(gè) MR Job再根據(jù)預(yù)處理的數(shù)據(jù)結(jié)果按照 Group By Key 分布到 Reduce 中(這個(gè)過程可以保證相同的Group By Key 被分布到同一個(gè) Reduce 中),最后完成最終的聚合操作。

?

10.????????HIVE FAQ

1、 [admin@hadoop1 ~]$ hive

Cannot find hadoop installation: $HADOOP_HOME must be set orhadoop must be in the path

原因:HADOOP路徑?jīng)]有在環(huán)境變量中定義

解決方法:admin@hadoop1~]$ export HADOOP_HOME=$HOME/hadoop-0.19.2

?

2、FAILED: Execution Error, return code 1 fromorg.apache.hadoop.hive.ql.exec.DDLTask

解決方案:Hive的元數(shù)據(jù)庫derby服務(wù)沒有啟動(dòng)

進(jìn)入到hive的安裝目錄

/home/admin/caona/hive/build/dist/db-derby-10.4.1.3-bin/bin

運(yùn)行startNetworkServer -h 0.0.0.0

?

3、[admin@hadoop1 conf]$ hive

Unable to createlog directory ${build.dir}/tmp

原因:存放日志文件的目錄被人刪除了。

解決方法:進(jìn)行到${build.dir}下面,創(chuàng)建一個(gè)tmp目錄。

如:[admin@hadoop1build]$ pwd

/home/admin/caona/hive/build

[admin@hadoop1build]$ mkdir tmp

?

11.????????常用參考資料路徑

Hive地址

http://wiki.apache.org/hadoop/Hive

http://hive.apache.org/

Velocity地址

http://velocity.apache.org/engine/releases/velocity-1.7/user-guide.html

Hadoop地址

http://hadoop.apache.org/

http://www.cloudera.com/

Hadoop中文文檔地址

http://hadoop.apache.org/common/docs/r0.18.2/cn/commands_manual.html


Hive學(xué)習(xí)筆記


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 色婷婷中文字幕 | 在线播放国产一区 | 天天拍天天干 | 精品视频一区二区三区 | 色综合久久综合欧美综合图片 | 天天干天天干天天 | 免费高清一级欧美片在线观看 | 91精彩视频在线观看 | 色就操 | 国产亚洲一区二区三区在线观看 | 深夜男人天堂 | 久久69精品久久久久久hb | 日本黄色小视频在线观看 | 国产精品色婷婷在线观看 | 色综合久久一本首久久 | 97久久久久国产精品嫩草影院 | 国产在线色视频 | 国产一区在线mmai | 成人毛片在线播放 | 亚洲免费资源 | 日本三级做a全过程在线观看 | 亚洲最大激情网 | 丁香六月色婷婷 | 四虎网站入口 | a一级网站| 久久这里只有精品国产 | 国产精品夜色一区二区三区 | 热综合一本伊人久久精品 | 日韩三集片 | 婷婷四房色播 | 日本最新免费二区三区 | 亚洲欧美久久精品一区 | 欧美一区视频 | 天天综合干| www.黄色一片 | 国产一级特黄aaa大片 | 国产色站 | 国产在线精品福利91香蕉 | 久久青草免费91线频观看站街 | 成人9久久国产精品品 | 国产精品成人扳一级aa毛片 |