Hive基礎學習文檔和入門教程

1.hive除了包含用戶接口、元數據,還包含哪些內容?
2.hive包含哪些操作?
3.hive數據能否被修改?
4.hive優化有哪些常用方法?





摘要:

  Hive 是建立在 Hadoop 上的數據倉庫基礎構架。它提供了一系列的工具,可以用來進行數據提取轉化加載(ETL),這是一種可以存儲、查詢和分析存儲在 Hadoop 中的大規模數據的機制。Hive 定義了簡單的類 SQL 查詢語言,稱爲 QL,它允許熟悉 SQL 的用戶查詢數據。同時,這個語言也允許熟悉 MapReduce 開發者的開發自定義的 mapper 和 reducer 來處理內建的 mapper 和 reducer 無法完成的複雜的分析工作。



1. HIVE結構
  Hive 是建立在 Hadoop 上的數據倉庫基礎構架。它提供了一系列的工具,可以用來進行數據提取轉化加載(ETL),這是一種可以存儲、查詢和分析存儲在 Hadoop 中的大規模數據的機制。Hive 定義了簡單的類 SQL 查詢語言,稱爲 QL,它允許熟悉 SQL 的用戶查詢數據。同時,這個語言也允許熟悉 MapReduce 開發者的開發自定義的 mapper 和 reducer 來處理內建的 mapper 和 reducer 無法完成的複雜的分析工作。

1.1 HIVE架構  
Hive 的結構可以分爲以下幾部分:
  · 用戶接口:包括 CLI, Client, WUI
  · 元數據存儲。通常是存儲在關係數據庫如 mysql, derby 中
  · 解釋器、編譯器、優化器、執行器
  · Hadoop:用 HDFS 進行存儲,利用MapReduce 進行計算
  1、 用戶接口主要有三個:CLI,Client和 WUI。其中最常用的是 CLI,Cli 啓動的時候,會同時啓動一個 Hive 副本。Client 是 Hive 的客戶端,用戶連接至 Hive Server。在啓動 Client 模式的時候,需要指出 Hive Server 所在節點,並且在該節點啓動 Hive Server。 WUI 是通過瀏覽器訪問 Hive。
  2、 Hive 將元數據存儲在數據庫中,如 mysql、derby。Hive 中的元數據包括表的名字,表的列和分區及其屬性,表的屬性(是否爲外部表等),表的數據所在目錄等。
  3、 解釋器、編譯器、優化器完成 HQL 查詢語句從詞法分析、語法分析、編譯、優化以及查詢計劃的生成。生成的查詢計劃存儲在 HDFS 中,並在隨後有 MapReduce 調用執行。
  4、Hive 的數據存儲在 HDFS 中,大部分的查詢由 MapReduce 完成(包含 * 的查詢,比如 select * from tbl 不會生成 MapRedcue 任務)。

1.2 Hive和Hadoop 關係
  Hive構建在 Hadoop 之上,
  · HQL 中對查詢語句的解釋、優化、生成查詢計劃是由 Hive 完成的
  · 所有的數據都是存儲在 Hadoop 中
  · 查詢計劃被轉化爲 MapReduce 任務,在 Hadoop 中執行(有些查詢沒有 MR 任務,如:select * from table)
  · Hadoop和Hive都是用UTF-8編碼的

1.3 Hive
和普通關係數據庫的異同
  Hive RDBMS
查詢語言 HQL SQL
數據存儲 HDFS Raw Device or Local FS
索引
執行 MapReduce Excutor
執行延遲
處理數據規模

  1. 查詢語言。由於 SQL 被廣泛的應用在數據倉庫中,因此,專門針對 Hive 的特性設計了類 SQL 的查詢語言 HQL。熟悉 SQL 開發的開發者可以很方便的使用 Hive 進行開發。
  2. 數據存儲位置。Hive 是建立在Hadoop 之上的,所有 Hive 的數據都是存儲在HDFS 中的。而數據庫則可以將數據保存在塊設備或者本地文件系統中。
  3. 數據格式。Hive 中沒有定義專門的數據格式,數據格式可以由用戶指定,用戶定義數據格式需要指定三個屬性:列分隔符(通常爲空格、”\t”、”\x001″)、行分隔符(”\n”)以及讀取文件數據的方法(Hive 中默認有三個文件格式 TextFile,SequenceFile 以及 RCFile)。由於在加載數據的過程中,不需要從用戶數據格式到 Hive 定義的數據格式的轉換,因此,Hive 在加載的過程中不會對數據本身進行任何修改,而只是將數據內容複製或者移動到相應的 HDFS
目錄中。而在數據庫中,不同的數據庫有不同的存儲引擎,定義了自己的數據格式。所有數據都會按照一定的組織存儲,因此,數據庫加載數據的過程會比較耗時。
  4. 數據更新。由於 Hive 是針對數據倉庫應用設計的,而數據倉庫的內容是讀多寫少的。因此,Hive 中不支持對數據的改寫和添加,所有的數據都是在加載的時候中確定好的。而數據庫中的數據通常是需要經常進行修改的,因此可以使用 INSERT INTO … VALUES 添加數據,使用 UPDATE… SET 修改數據。
  5. 索引。之前已經說過,Hive 在加載數據的過程中不會對數據進行任何處理,甚至不會對數據進行掃描,因此也沒有對數據中的某些 Key 建立索引。Hive 要訪問數據中滿足條件的特定值時,需要暴力掃描整個數據,因此訪問延遲較高。由於 MapReduce 的引入, Hive 可以並行訪問數據,因此即使沒有索引,對於大數據量的訪問,Hive 仍然可以體現出優勢。數據庫中,通常會針對一個或者幾個列建立索引,因此對於少量的特定條件的數據的訪問,數據庫可以有很高的效率,較低的延遲。由於數據的訪問延遲較高,決定了
Hive 不適合在線數據查詢。
  6. 執行。Hive 中大多數查詢的執行是通過 Hadoop 提供的 MapReduce 來實現的(類似 select * from tbl 的查詢不需要 MapReduce)。而數據庫通常有自己的執行引擎。
  7. 執行延遲。之前提到,Hive 在查詢數據的時候,由於沒有索引,需要掃描整個表,因此延遲較高。另外一個導致 Hive 執行延遲高的因素是 MapReduce 框架。由於 MapReduce 本身具有較高的延遲,因此在利用 MapReduce 執行 Hive 查詢時,也會有較高的延遲。相對的,數據庫的執行延遲較低。當然,這個低是有條件的,即數據規模較小,當數據規模大到超過數據庫的處理能力的時候,Hive 的並行計算顯然能體現出優勢。
  8. 可擴展性。由於 Hive 是建立在 Hadoop 之上的,因此 Hive 的可擴展性是和 Hadoop 的可擴展性是一致的(世界上最大的 Hadoop 集羣在 Yahoo!,2009年的規模在4000 臺節點左右)。而數據庫由於 ACID 語義的嚴格限制,擴展行非常有限。目前最先進的並行數據庫 Oracle 在理論上的擴展能力也只有 100 臺左右。
  9. 數據規模。由於 Hive 建立在集羣上並可以利用 MapReduce 進行並行計算,因此可以支持很大規模的數據;對應的,數據庫可以支持的數據規模較小。
1.4 HIVE元數據庫  

Hive 將元數據存儲在 RDBMS 中,一般常用的有MYSQL和DERBY。

1.4.1 DERBY  
啓動HIVE的元數據庫
  進入到hive的安裝目錄
  Eg:
  1、啓動derby數據庫
  /home/admin/caona/hive/build/dist/
  運行startNetworkServer -h 0.0.0.0

  2、連接Derby數據庫進行測試
  查看/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>
  進入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、元數據庫數據字典
表名
說明
關聯鍵
BUCKETING_COLS
COLUMNS
Hive表字段信息(字段註釋,字段名,字段類型,字段序號)
SD_ID
DBS
元數據庫信息,存放HDFS路徑信息
DB_ID
PARTITION_KEYS
Hive分區表分區鍵
PART_ID
SDS
所有hive表、表分區所對應的hdfs數據目錄和數據格式。
SD_ID,SERDE_ID
SD_PARAMS
序列化反序列化信息,如行分隔符、列分隔符、NULL的表示字符等
SERDE_ID
SEQUENCE_TABLE
SEQUENCE_TABLE表保存了hive對象的下一個可用ID,如’org.apachtastore.model.MTable’, 21,則下一個新創建的hive表其TBL_ID就是21,同時SEQUENCE_TABLE表中271786被更新爲26(這裏每次都是+5?)。同樣,COLUMN,PARTITION等都有相應的記錄
SERDES
SERDE_PARAMS
SORT_COLS
TABLE_PARAMS
表級屬性,如是否外部表,表註釋等
TBL_ID
TBLS
所有hive表的基本信息
TBL_ID,SD_ID
  

從上面幾張表的內容來看,hive整個創建表的過程已經比較清楚了


解析用戶提交hive語句,對其進行解析,分解爲表、字段、分區等hive對象 
根據解析到的信息構建對應的表、字段、分區等對象,從SEQUENCE_TABLE中獲取構建對象的最新ID,與構建對象信息(名稱,類型等)一同通過DAO方法寫入到元數據表中去,成功後將SEQUENCE_TABLE中對應的最新ID+5。  實際上我們常見的RDBMS都是通過這種方法進行組織的,典型的如postgresql,其系統表中和hive元數據一樣裸露了這些id信息(oid,cid等),而Oracle等商業化的系統則隱藏了這些具體的ID。通過這些元數據我們可以很容易的讀到數據諸如創建一個表的數據字典信息,比如導出建表語名等。
  導出建表語句的shell腳本見附一 待完成

1.4.2 Mysql  

將存放元數據的Derby數據庫遷移到Mysql數據庫
  步驟:

1.5 HIVE的數據存儲  

首先,Hive 沒有專門的數據存儲格式,也沒有爲數據建立索引,用戶可以非常自由的組織 Hive 中的表,只需要在創建表的時候告訴 Hive 數據中的列分隔符和行分隔符,Hive 就可以解析數據。
  其次,Hive 中所有的數據都存儲在 HDFS 中,Hive 中包含以下數據模型:Table,External Table,Partition,Bucket。


Hive 中的 Table 和數據庫中的 Table 在概念上是類似的,每一個 Table 在 Hive 中都有一個相應的目錄存儲數據。例如,一個表 xiaojun,它在 HDFS 中的路徑爲:/ warehouse /xiaojun,其中,wh 是在 hive-site.xml 中由 ${tastore.warehouse.dir} 指定的數據倉庫的目錄,所有的 Table 數據(不包括 External Table)都保存在這個目錄中。 

Partition 對應於數據庫中的 Partition 列的密集索引,但是 Hive 中 Partition 的組織方式和數據庫中的很不相同。在 Hive 中,表中的一個 Partition 對應於表下的一個目錄,所有的 Partition 的數據都存儲在對應的目錄中。例如:xiaojun 表中包含 dt 和 city 兩個 Partition,則對應於 dt = 20100801, ctry = US 的 HDFS 子目錄爲:/ warehouse /xiaojun/dt=20100801/ctry=US;對應於
dt = 20100801, ctry = CA 的 HDFS 子目錄爲;/ warehouse /xiaojun/dt=20100801/ctry=CA 
Buckets 對指定列計算 hash,根據 hash 值切分數據,目的是爲了並行,每一個 Bucket 對應一個文件。將 user 列分散至 32 個 bucket,首先對 user 列的值計算 hash,對應 hash 值爲 0 的 HDFS 目錄爲:/ warehouse /xiaojun/dt =20100801/ctry=US/part-00000;hash 值爲 20 的 HDFS 目錄爲:/ warehouse /xiaojun/dt =20100801/ctry=US/part-00020 
External Table 指向已經在 HDFS 中存在的數據,可以創建 Partition。它和 Table 在元數據的組織上是相同的,而實際數據的存儲則有較大的差異。 
Table 的創建過程和數據加載過程(這兩個過程可以在同一個語句中完成),在加載數據的過程中,實際數據會被移動到數據倉庫目錄中;之後對數據對訪問將會直接在數據倉庫目錄中完成。刪除表時,表中的數據和元數據將會被同時刪除。 
External Table 只有一個過程,加載數據和創建表同時完成(CREATE EXTERNAL TABLE ……LOCATION),實際數據是存儲在 LOCATION 後面指定的 HDFS 路徑中,並不會移動到數據倉庫目錄中。當刪除一個 External Table 時,僅刪除 


1.6 其它HIVE操作  

1、 啓動HIVE的WEB的界面
  sh $HIVE_HOME/bin/hive –service hwi
2、查看HDFS上的文件數據
  Hadoopfs -text /user/admin/daiqf/createspu_fp/input/cateinfo |head

2. HIVE 基本操作 
2.1 createtable 
2.1.1 總述  
       l CREATETABLE 創建一個指定名字的表。如果相同名字的表已經存在,則拋出異常;用戶可以用 IF NOT EXIST 選項來忽略這個異常。
  l EXTERNAL關鍵字可以讓用戶創建一個外部表,在建表的同時指定一個指向實際數據的路徑(LOCATION),Hive
創建內部表時,會將數據移動到數據倉庫指向的路徑;若創建外部表,僅記錄數據所在的路徑,不對數據的位置做任何改變。在刪除表的時候,內部表的元數據和數據會被一起刪除,而外部表只刪除元數據,不刪除數據。
  l LIKE 允許用戶複製現有的表結構,但是不復制數據。
  l 用戶在建表的時候可以自定義 SerDe 或者使用自帶的 SerDe。如果沒有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,將會使用自帶的 SerDe。在建表的時候,用戶還需要爲表指定列,用戶在指定表的列的同時也會指定自定義的SerDe,Hive 通過 SerDe 確定表的具體的列的數據。
  l 如果文件數據是純文本,可以使用 STORED AS TEXTFILE。如果數據需要壓縮,使用 STORED ASSEQUENCE 。
  l 有分區的表可以在創建的時候使用 PARTITIONED BY 語句。一個表可以擁有一個或者多個分區,每一個分區單獨存在一個目錄下。而且,表和分區都可以對某個列進行 CLUSTERED BY 操作,將若干個列放入一個桶(bucket)中。也可以利用SORT BY 對數據進行排序。這樣可以爲特定應用提高性能。
  l 表名和列名不區分大小寫,SerDe 和屬性名區分大小寫。表和列的註釋是字符串。

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中常用的數據類型有:
  BIGINT – 主要用於狀態,類別,數量的字段, 如status/option/type/quantity
  DOUBLE – 主要用於金額的字段, 如fee/price/bid
  STRING – 除上述之外的字段基本都使用String, 尤其是id和日期時間這樣的字段

2.1.3 基本例子 
    1、如果一個表已經存在,可以使用if not exists
  2、 create table xiaojun(id int,cont string) row format delimitedfields terminated by ‘\005′ stored as textfile;
  terminated by:關於來源的文本數據的字段間隔符
  如果要將自定義間隔符的文件讀入一個表,需要通過創建表的語句來指明輸入文件間隔符,然後load data到這個表。
  4、Alibaba數據庫常用間隔符的讀取
  我們的常用間隔符一般是Ascii碼5,Ascii碼7等。在hive中Ascii碼5用’\005’表示, Ascii碼7用’\007’表示,依此類推。
  5、裝載數據
  查看一下:Hadoop fs -ls
  LOAD DATA INPATH’/user/admin/xiaojun/a.txt’ OVERWRITE INTO TABLE xiaojun;
  6、如果使用external建表和普通建表區別
  A、指定一個位置,而不使用默認的位置。如:
  create EXTERNAL table xiaojun(id int,cont string) row format delimited fields terminatedby ‘\005′ stored as textfile location ‘/user/admin/xiaojun/’;
  ————–check結果
  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、對於使用create table external建表完成後,再drop掉表,表中的數據還在文件系統中。
  如:
  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 創建分區  

      HIVE的分區通過在創建表時啓用partitionby實現,用來partition的維度並不是實際數據的某一列,具體分區的標誌是由插入內容時給定的。當要查詢某一分區的內容時可以採用where語句,形似where tablename.partition_key >a來實現。
  創建含分區的表。
  命令原型:
  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;
  裝載數據:
  LOAD DATA INPATH’/user/admin/SqlldrDat/CnClickstat/20101101/19/clickstat_gp_fatdt0/0′ OVERWRITEINTO TABLE c02_clickstat_fatdt1
  PARTITION(dt=’20101101′);
  訪問某一個分區
  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、 複製一個空表
  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
  這個命令可以讓用戶爲表更名。數據所在的位置和分區名並不改變。換而言之,老的表名並未“釋放”,對老表的更改會改變新表的數據。

2.2.4 ChangeColumn  
ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_namecolumn_type [COMMENT col_comment] [FIRST|AFTER column_name]
  這個命令可以允許改變列名、數據類型、註釋、列位置或者它們的任意組合
  Eg:

2.2.5 Add/ReplaceColumns  

ALTER TABLE table_name ADD|REPLACE COLUMNS (col_namedata_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,如果沒有就報錯:
  SHOWPARTITIONS page_view;
  查看某表結構:
  DESCRIBE invites;
  查看分區內容
  SELECTa.foo FROM invites a WHERE a.ds[王黎1] =’2008-08-15′;
  查看有限行內容,同Greenplum,用limit關鍵詞
  SELECTa.foo FROM invites a limit 3;
  查看錶分區定義
  DESCRIBE 
EXTENDED[王黎2] page_view PARTITION (ds=’2008-08-08′);
2.5 Load  
       HIVE裝載數據沒有做任何轉換加載到表中的數據只是進入相應的配置單元表的位置移動數據文件。純加載操作複製/移動操作。


  3.1 語法  LOAD DATA [LOCAL] INPATH ‘filepath’ [OVERWRITE] INTOTABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
  Load 操作只是單純的複製/移動操作,將數據文件移動到 Hive 表對應的位置。

filepath 可以是: 
相對路徑,例如:project/data1 
絕對路徑,例如: /user/hive/project/data1 
包含模式的完整 URI,例如:hdfs://namenode:9000/user/hive/project/data1 
加載的目標可以是一個表或者分區。如果表包含分區,必須指定每一個分區的分區名。 
filepath 可以引用一個文件(這種情況下,Hive 會將文件移動到表所對應的目錄中)或者是一個目錄(在這種情況下,Hive 會將目錄中的所有文件移動至表所對應的目錄中)。 
如果指定了 LOCAL,那麼: 
load 命令會去查找本地文件系統中的 filepath。如果發現是相對路徑,則路徑會被解釋爲相對於當前用戶的當前路徑。用戶也可以爲本地文件指定一個完整的 URI,比如:file:///user/hive/project/data1. 
load 命令會將 filepath 中的文件複製到目標文件系統中。目標文件系統由表的位置屬性決定。被複制的數據文件移動到表的數據對應的位置。 
如果沒有指定 LOCAL 關鍵字,如果 filepath 指向的是一個完整的 URI,hive 會直接使用這個 URI。 否則: 
如果沒有指定 schema 或者 authority,Hive 會使用在 Hadoop 配置文件中定義的 schema 和 authority,fs.default.name 指定了 Namenode 的 URI。 
如果路徑不是絕對的,Hive 相對於 /user/ 進行解釋。 
Hive 會將 filepath 中指定的文件內容移動到 table (或者 partition)所指定的路徑中。 
如果使用了 OVERWRITE 關鍵字,則目標表(或者分區)中的內容(如果有)會被刪除,然後再將 filepath 指向的文件/目錄中的內容添加到表/分區中。 
如果目標表(分區)已經有一個文件,並且文件名和 filepath 中的文件名衝突,那麼現有的文件會被新文件所替代。  從本地導入數據到表格並追加原表
  LOAD DATALOCAL INPATH /tmp/pv_2008-06-08_us.txt INTO TABLE c02PARTITION(date=’2008-06-08′, country=’US’)
  從本地導入數據到表格並追加記錄
  LOAD DATALOCAL INPATH ‘./examples/files/kv1.txt’ INTO TABLE pokes;

  從hdfs導入數據到表格並覆蓋原表
  LOAD DATAINPATH ‘/user/admin/SqlldrDat/CnClickstat/20101101/18/clickstat_gp_fatdt0/0′INTO table c02_clickstat_fatdt1 OVERWRITE PARTITION (dt=’20101201′);
  關於來源的文本數據的字段間隔符
  如果要將自定義間隔符的文件讀入一個表,需要通過創建表的語句來指明輸入文件間隔符,然後load data到這個表就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時,from子句既可以放在select子句後,也可以放在insert子句前,下面兩句是等價的
  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沒有直接插入一條數據的sql,不過可以通過其他方法實現:
  假設有一張表B至少有一條數據,我們想向表A(int,string)中插入一條數據,可以用下面的方法實現:
  from B
  insert table A select 1,‘abc’ limit 1;
  我覺得hive好像不能夠插入一個記錄,因爲每次你寫insert語句的時候都是要將整個表的值overwrite。我想這個應該是與hive的storage layer是有關係的,因爲它的存儲層是HDFS,插入一個數據要全表掃描,還不如用整個表的替換來的快些。
  Hive不支持一條一條的用insert語句進行插入操作,也不支持update的操作。數據是以load的方式,加載到建立好的表中。數據一旦導入,則不可修改。要麼drop掉整個表,要麼建立新的表,導入新的數據。

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] …
  導出文件到本地
  INSERTOVERWRITE LOCAL DIRECTORY ‘/tmp/local_out’ SELECT a.* FROM pokes a;
  導出文件到HDFS
  INSERTOVERWRITE DIRECTORY’/user/admin/SqlldrDat/CnClickstat/20101101/19/clickstat_gp_fatdt0/0′ SELECTa.* FROM c02_clickstat_fatdt1 a WHERE dt=’20101201’;
  一個源可以同時插入到多個目標表或目標文件,多目標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是一個shell工具,它可以用來運行於交互或批處理方式配置單元查詢。
  語法:
  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
  運行一個查詢:
  $HIVE_HOME/bin/ hive -e ‘select count(*) fromc02_clickstat_fatdt1′
  Example of setting hive configurationvariables

  $HIVE_HOME/bin/hive -e ‘select l from tab1 a’-hiveconf
hive.exec.scratchdir=/home/my/hive_scratch -hiveconf mapred.reduce.tasks=32[王黎4]
  將查詢結果導出到一個文件
  HIVE_HOME/bin/hive -S -e ‘
select count(*) from c02_clickstat_fatdt1′> a.txt
  運行一個腳本
  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>
使用這個方式來設置特定的配置變量的值。有一點需要注意的是,如果你拼錯了變量名,CLI將不會顯示錯誤。
set
這將打印的配置變量,如果沒有指定變量則由顯示HIVE和用戶變量。如set I 則顯示i的值,set則顯示hive內部變量值
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 workid 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 workid USING ‘wc -l’ …: here wc is an executable available on all machines 
… MAP workid 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 調用python、shell等語言  

如下面這句sql就是借用了weekday_mapper.py對數據進行了處理
  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內容如下
  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命令來處理數據
  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  
刪除一個內部表的同時會同時刪除表的元數據和數據。刪除一個外部表,只刪除元數據而保留數據。

2.9 其它 
2.9.1 Limit  
Limit可以限制查詢的記錄數。查詢的結果是隨機選擇的。下面的查詢語句從 t1 表中隨機查詢5條記錄:
  SELECT* FROM t1 LIMIT 5

2.9.2 Top k  
下面的查詢語句查詢銷售記錄最大的 5 個銷售代表。
  SETmapred.reduce.tasks = 1
  SELECT * FROM sales SORT BY amount DESC LIMIT5

2.9.3 REGEX Column Specification  
SELECT 語句可以使用正則表達式做列選擇,下面的語句查詢除了 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?
  高級特性:
  l 聚合可進一步分爲多個表,甚至發送到Hadoop的DFS的文件(可以進行操作,然後使用HDFS的utilitites)。例如我們可以根據性別劃分,需要找到獨特的頁面瀏覽量按年齡劃分。如下面的例子:
  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可以控制怎麼進行彙總。默認爲爲true,配置單元會做的第一級聚合直接在MAP上的任務。這通常提供更好的效率,但可能需要更多的內存來運行成功。
  sethive.map.aggr=true;
  SELECT COUNT(*) FROM table2;
  PS:在要特定的場合使用可能會加效率。不過我試了一下,比直接使用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順序將根據列類型而定。如果數字類型的列,則排序順序也以數字順序。如果字符串類型的列,則排序順序將字典順序。
  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_referenceLEFT 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 不支持所有非等值的連接,因爲非等值連接非常難轉化到 map/reduce 任務。另外,Hive 支持多於 2 個表的連接。
  寫 join 查詢時,需要注意幾個關鍵點:
  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)
  是錯誤的。
  1. 可以 join 多於 2 個表。
  例如
  SELECT a.val,b.val, c.val FROM a JOIN b
  ON (a.key =b.key1) JOIN c ON (c.key = b.key2)
  如果join中多個表的join key 是同一個,則 join 會被轉化爲單個map/reduce 任務,例如:
  SELECT a.val,b.val, c.val FROM a JOIN b
  ON (a.key =b.key1) JOIN c
  ON (c.key =b.key1)
  被轉化爲單個 map/reduce 任務,因爲 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 被轉化爲2 個 map/reduce 任務。因爲 b.key1 用於第一次 join 條件,而 b.key2 用於第二次 join。
  3.join 時,每次map/reduce 任務的邏輯:
  reducer 會緩存 join 序列中除了最後一個表的所有表的記錄,再通過最後一個表將結果序列化到文件系統。這一實現有助於在 reduce 端減少內存的使用量。實踐中,應該把最大的那個表寫在最後(否則會因爲緩存浪費大量內存)。例如:
  SELECT a.val, b.val, c.val FROM a
  JOIN b ON (a.key = b.key1)JOIN c ON (c.key = b.key1)
  所有表都使用同一個 join key(使用 1 次map/reduce 任務計算)。Reduce 端會緩存 a 表和 b 表的記錄,然後每次取得一個 c 表的記錄就計算一次 join 結果,類似的還有:
  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 任務。第一次緩存 a 表,用 b 表序列化[王黎11] ;第二次緩存第一次 map/reduce 任務的結果,然後用 c 表序列化。
  [王黎12]
  4.LEFT,RIGHT 和 FULLOUTER 關鍵字用於處理 join 中空記錄 ?情況。
  例如:
  SELECT a.val,b.val FROM a LEFT OUTER
  JOIN b ON(a.key=b.key)
  對應所有 a 表中的記錄都有一條記錄輸出。輸出的結果應該是 a.val, b.val,當 a.key=b.key 時,而當 b.key 中找不到等值的 a.key 記錄時也會輸出 a.val, NULL。“FROM a LEFT OUTER JOIN b”這句一定要寫在同一行——意思是 a 表在 b 表的左邊,所以 a 表中的所有記錄都被保留了;“a RIGHT OUTER JOIN b”會保留所有 b 表的記錄。OUTER JOIN 語義應該是遵循標準 SQL spec的。
  Join 發生在 WHERE 子句之前。如果你想限制 join 的輸出,應該在 WHERE 子句中寫過濾條件——或是在join 子句中寫。這裏面一個容易混淆的問題是表分區的情況:
  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′
  會 join a 表到 b 表(OUTER JOIN),列出 a.val 和 b.val 的記錄。WHERE 從句中可以使用其他列作爲過濾條件。但是,如前所述,如果 b 表中找不到對應 a 表的記錄,b 表的所有列都會列出 NULL,包括 ds 列。也就是說,join 會過濾 b 表中不能找到匹配a 表 join key 的所有記錄。這樣的話,LEFTOUTER 就使得查詢結果與 WHERE 子句無關了。解決的辦法是在 OUTER JOIN 時使用以下語法:
  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′)
  這一查詢的結果是預先在 join 階段過濾過的,所以不會存在上述問題。這一邏輯也可以應用於 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 中不匹配的記錄,然後用這一中間結果和 c 表做 join。這一表述有一個不太明顯的問題,就是當一個 key 在 a 表和 c 表都存在,但是 b 表中不存在的時候:整個記錄在第一次 join,即 a JOIN b 的時候都被丟掉了(包括a.val1,a.val2和a.key),然後我們再和 c 表 join 的時候,如果c.key 與 a.key 或 b.key 相等,就會得到這樣的結果:NULL, NULL, NULL, c.val。

  5.LEFT SEMI JOIN

是 IN/EXISTS 子查詢的一種更高效的實現。Hive 當前沒有實現 IN/EXISTS 子查詢,所以你可以用 LEFT SEMI JOIN 重寫你的子查詢語句。LEFT SEMI JOIN 的限制是, JOIN 子句中右邊的表只能在 ON 子句中設置過濾條件,在
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參數設置  

開發Hive應用時,不可避免地需要設定Hive的參數。設定Hive的參數可以調優HQL代碼的執行效率,或幫助定位問題。然而實踐中經常遇到的一個問題是,爲什麼設定的參數沒有起作用?
  這通常是錯誤的設定方式導致的。
  對於一般參數,有以下三種設定方式:

配置文件 
命令行參數 
參數聲明  配置文件:Hive的配置文件包括

用戶自定義配置文件:$HIVE_CONF_DIR/hive-site.xml 
默認配置文件:$HIVE_CONF_DIR/hive-default.xml  用戶自定義配置會覆蓋默認配置。另外,Hive也會讀入Hadoop的配置,因爲Hive是作爲Hadoop的客戶端啓動的,Hadoop的配置文件包括

$HADOOP_CONF_DIR/hive-site.xml 
$HADOOP_CONF_DIR/hive-default.xml  Hive的配置會覆蓋Hadoop的配置。
  配置文件的設定對本機啓動的所有Hive進程都有效。
  命令行參數:啓動Hive(客戶端或Server方式)時,可以在命令行添加-hiveconf param=value來設定參數,例如:
  bin/hive -hiveconf hive.root.logger=INFO,console
  這一設定對本次啓動的Session(對於Server方式啓動,則是所有請求的Sessions)有效。
  參數聲明:可以在HQL中使用SET關鍵字設定參數,例如:
  set mapred.reduce.tasks=100;
  這一設定的作用域也是Session級的。
  上述三種設定方式的優先級依次遞增。即參數聲明覆蓋命令行參數,命令行參數覆蓋配置文件設定。注意某些系統級的參數,例如log4j相關的設定,必須用前兩種方式設定,因爲那些參數的讀取在Session建立以前已經完成了。
  另外,SerDe參數[王黎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這樣的參數,必須和某個表或分區關聯。在DDL外部聲明將不起作用。

6. HIVE UDF
6.1 基本函數

SHOW FUNCTIONS;
  DESCRIBE FUNCTION <function_name>;

6.1.1 關係操作符
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 代數操作符  
返回數字類型,如果任意一個操作符爲NULL,則結果爲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 複雜類型操作符

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 內建函數 
6.1.6 數學函數 
6.1.7 集合函數 
6.1.8 類型轉換
6.1.9 日期函數


返回值類型 名稱 描述
string from_unixtime(int unixtime) 將時間戳(unix epoch秒數)轉換爲日期時間字符串,例如from_unixtime(0)=”1970-01-01 00:00:00″
bigint unix_timestamp() 獲得當前時間戳
bigint unix_timestamp(string date) 獲得date表示的時間戳
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的天數的差,例如datediff(’2009-03-01′, ’2009-02-27′)
= 2
int date_add(string startdate, int days) 加days天數到startdate: date_add(’2008-12-31′, 1) = ’2009-01-01′
int date_sub(string startdate, int days) 減days天數到startdate: date_sub(’2008-12-31′, 1) = ’2008-12-30′


6.1.10 條件函數

返回值類型 名稱 描述
- if(boolean testCondition, T valueTrue, T valueFalseOrNull)
當testCondition爲真時返回valueTrue,testCondition爲假或NULL時返回valueFalseOrNull
- COALESCE(T v1, T v2, …) 返回列表中的第一個非空元素,如果列表元素都爲空則返回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 字符串函數  

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

返回值類型 名稱 描述
Int length(string A) 返回字符串長度
String reverse(string A) 反轉字符串
String concat(string A, string B…) 合併字符串,例如concat(‘foo’, ‘bar’)=’foobar’。注意這一函數可以接受任意個數的參數
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) 返回限定長度的子串,例如substr(‘foobar’, 4, 1)=’b’
String upper(string A) ucase(string A) 轉換爲大寫
String lower(string A) lcase(string A) 轉換爲小寫
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) 返回使用正則表達式提取的子字串。例如,regexp_extract(‘foothebar’, ‘foo(.*?)(bar)’, 2)=’bar’。注意使用特殊字符的規則:使用’\s’代表的是字符’s';空白字符需要使用’\\s’,以此類推。
String parse_url(string urlString, string partToExtract) 解析URL字符串,partToExtract的可選項有:HOST, PATH, QUERY, REF, PROTOCOL, FILE, AUTHORITY, USERINFO。
例如,
parse_url(‘;, ‘HOST’)=’’
parse_url(‘;, ‘PATH’)=’/path/p1.php’
parse_url(‘;, ‘QUERY’)=’query=1′,可以指定key來返回特定參數,key的格式是QUERY:<KEY_NAME>,例如QUERY:k1
parse_url(‘;field=2′,’QUERY’,'query’)=’1′可以用來取出外部渲染參數key對應的value值
parse_url(‘;field=2′,’QUERY’,'field’)=’2′
parse_url(‘;, ‘REF’)=’Ref’
parse_url(‘;, ‘PROTOCOL’)=’http’
String get_json_object(string json_string, string path) 解析json字符串。若源json字符串非法則返回NULL。path參數支持JSONPath的一個子集,包括以下標記:
$: Root object
[]: Subscript operator for array
&: Wildcard for []
.: Child operator
String space(int n) 返回一個包含n個空格的字符串
String repeat(string str, int n) 重複str字符串n遍
String ascii(string str) 返回str中第一個字符的ascii碼
String lpad(string str, int len, string pad) 左端補齊str到長度爲len。補齊的字符串由pad指定。
String rpad(string str, int len, string pad) 右端補齊str到長度爲len。補齊的字符串由pad指定。
Array split(string str, string pat) 返回使用pat作爲正則表達式分割str字符串的列表。例如,split(‘foobar’,
‘o’)[2] = ‘bar’。?不是很明白這個結果
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函數有一些限制:

  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  

將數組進行轉置
  例如:
  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  

對於 JOIN 操作:
INSERT OVERWRITE TABLE pv_users  SELECT pv.pageid, u.age FROM page_view pv JOIN user u ON (pv.userid = u.userid);
 

Map: 
以 JOIN ON 條件中的列作爲 Key,如果有多個列,則 Key 是這些列的組合 
以 JOIN 之後所關心的列作爲 Value,當有多個列時,Value 是這些列的組合。在 Value 中還會包含表的 Tag 信息,用於標明此 Value 對應於哪個表。 
按照 Key 進行排序。 
Shuffle: 
根據 Key 的值進行 Hash,並將 Key/Value 對按照 Hash 值推至不同對 Reduce 中。 
Reduce: 
Reducer 根據 Key 值進行 Join 操作,並且通過 Tag 來識別不同的表中的數據。 

7.2
GROUPBY
SELECT pageid, age, count(1) FROM pv_users GROUP BY pageid, age;
  
7.3
DISTINCT
SELECT age, count(distinct pageid) FROM pv_users GROUP BY age;
 

8. 使用HIVE注意點

8.1 字符集  
Hadoop和Hive都是用UTF-8編碼的,所以, 所有中文必須是UTF-8編碼, 才能正常使用
  備註:中文數據load到表裏面, 如果字符集不同,很有可能全是亂碼需要做轉碼的, 但是hive本身沒有函數來做這個

8.2 壓縮  
hivpress.output 這個參數, 默認是 false,但是很多時候貌似要單獨顯式設置一遍
  否則會對結果做壓縮的,如果你的這個文件後面還要在hadoop下直接操作, 那麼就不能壓縮了

8.3 count(distinct)  
當前的 Hive 不支持在一條查詢語句中有多 Distinct。如果要在 Hive 查詢語句中實現多Distinct,需要使用至少n+1 條查詢語句(n爲distinct的數目),前n 條查詢分 別對 n 個列去重,最後一條查詢語句對 n 個去重之後的列做 Join 操作,得到最終結果。

8.4 JOIN  
只支持等值連接

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

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

8.7 子查詢  
Hive不支持where子句中的子查詢
  子查詢,只允許子查詢在from中出現
  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值的語義區別  
SQL標準中,任何對null的操作(數值比較,字符串操作等)結果都爲null。Hive對null值處理的邏輯和標準基本一致,除了Join時的特殊邏輯。
  這裏的特殊邏輯指的是,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成立。
  如果需要與標準一致的語義,我們需要改寫查詢手動過濾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;
  實踐中,這一語義區別也是經常導致數據傾斜的原因之一。

8.9 分號字符  
分號是SQL語句結束標記,在HiveQL中也是,但是在HiveQL中,對分號的識別沒有那麼智慧,例如:
  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解析語句的時候,只要遇到分號就認爲語句結束,而無論是否用引號包含起來。
  解決的辦法是,使用分號的八進制的ASCII碼進行轉義,那麼上述語句應寫成:
  selectconcat(cookie_id,concat(‘\073′,’zoo’)) from c02_clickstat_fatdt1 limit 2;
  爲什麼是八進制ASCII碼?
  我嘗試用十六進制的ASCII碼,但Hive會將其視爲字符串處理並未轉義,好像僅支持八進制,原因不詳。這個規則也適用於其他非SELECT語句,如CREATE TABLE中需要定義分隔符,那麼對不可見字符做分隔符就需要用八進制的ASCII碼來轉義。

8.10 Insert

8.10.1 新增數據  
根據語法Insert必須加“OVERWRITE”關鍵字,也就是說每一次插入都是一次重寫。那如何實現表中新增數據呢?
  假設Hive中有表xiaojun1,
  hive> DESCRIBE xiaojun1;
  OK
  id int
  value int
  hive> SELECT * FROM xiaojun1;
  OK
  3 4
  1 2
  2 3
  現增加一條記錄:
  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;
  結果是:
  hive>SELECT * FROM p1;
  OK
  3 4
  4 5
  2 3
  1 2
  其中的關鍵在於, 關鍵字UNION ALL的應用, 即將原有數據集和新增數據集進行結合, 然後重寫表.

8.10.2 插入次序  
INSERT OVERWRITE TABLE在插入數據時,是按照後面的SELECT語句中的字段順序插入的. 也就說, 當id 和value 的位置互換, 那麼value將被寫入id, 同id被寫入value.

8.10.3 初始值  
INSERT OVERWRITE TABLE在插入數據時, 後面的字段的初始值應注意與表定義中的一致性. 例如, 當爲一個STRING類型字段初始爲NULL時:
  NULL AS field_name // 這可能會被提示定義類型爲STRING, 但這裏是void
  CAST(NULL AS STRING) AS field_name // 這樣是正確的
  又如, 爲一個BIGINT類型的字段初始爲0時:
  CAST(0 AS BIGINT) AS field_name

9. 優化
9.1 Hadoop計算框架特性 

數據量大不是問題,數據傾斜是個問題。 
jobs數比較多的作業運行效率相對比較低,比如即使有幾百行的表,如果多次關聯多次彙總,產生十幾個jobs,耗時很長。原因是map reduce作業初始化的時間是比較長的。 
sum,count,max,min等UDAF,不怕數據傾斜問題,hadoop在map端的彙總合併優化,使數據傾斜不成問題。 
count(distinct ),在數據量大的情況下,效率較低,如果是多count(distinct )效率更低,因爲count(distinct)是按group by 字段分組,按distinct字段排序,一般這種分佈方式是很傾斜的,比如男uv,女uv,淘寶一天30億的pv,如果按性別分組,分配2個reduce,每個reduce處理15億數據。

9.2 優化的常用手段 
好的模型設計事半功倍。 
解決數據傾斜問題。 
減少job數。 
設置合理的map reduce的task數,能有效提升性能。(比如,10w+級別的計算,用160個reduce,那是相當的浪費,1個足夠)。 
瞭解數據分佈,自己動手解決數據傾斜問題是個不錯的選擇。set hive.groupby.skewindata=true;這是通用的算法優化,但算法優化有時不能適應特定業務背景,開發人員瞭解業務,瞭解數據,可以通過業務邏輯精確有效的解決數據傾斜問題。
數據量較大的情況下,慎用count(distinct),count(distinct)容易產生傾斜問題。 
對小文件進行合併,是行至有效的提高調度效率的方法,假如所有的作業設置合理的文件數,對雲梯的整體調度效率也會產生積極的正向影響。 
優化時把握整體,單個作業最優不如整體最優。

9.3 全排序  
Hive的排序關鍵字是SORT BY,它有意區別於傳統數據庫的ORDER BY也是爲了強調兩者的區別–SORT BY只能在單機範圍內排序。

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個reduce進行數據分發(各自進行排序)。結果不一樣的主要原因是上述查詢沒有reduce key,hive會生成隨機數作爲reduce key。這樣的話輸入記錄也隨機地被分發到不同reducer機器上去了。爲了保證reducer之間沒有重複的cookie_id記錄,可以使用DISTRIBUTE BY關鍵字指定分發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, — 訂單編號
  sale_id int, — 銷售ID
  customer_id int, — 客戶ID
  product _id int, — 產品ID
  amount int — 數量
  ) PARTITIONED BY (ds STRING);
  在表中查詢所有銷售記錄,並按照銷售ID和數量排序:
  set mapred.reduce.tasks=2;
  Select sale_id, amount from t_order
  Sort by sale_id, amount;
  這一查詢可能得到非期望的排序。指定的2個reducer分發到的數據可能是(各自排序):
  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關鍵字指定分發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對應的數量是正確排序的,但是銷售ID不能正確排序,原因是hive使用hadoop默認的HashPartitioner分發數據。
  這就涉及到一個全排序的問題。解決的辦法無外乎兩種:
  1.) 不分發數據,使用單個reducer:
  set mapred.reduce.tasks=1;
  這一方法的缺陷在於reduce端成爲了性能瓶頸,而且在數據量大的情況下一般都無法得到結果。但是實踐中這仍然是最常用的方法,原因是通常排序的查詢是爲了得到排名靠前的若干結果,因此可以用limit子句大大減少數據量。使用limit n後,傳輸到reduce端(單機)的數據記錄數就減少到n* (map個數)。
  2.) 修改Partitioner,這種方法可以做到全排序。這裏可以使用Hadoop自帶的TotalOrderPartitioner(來自於Yahoo!的TeraSort項目),這是一個爲了支持跨reducer分發有序數據開發的Partitioner,它需要一個SequenceFile格式的文件指定分發的數據區間。如果我們已經生成了這一文件(存儲在/tmp/range_key_list 分成100個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;
  有很多種方法生成這一區間文件(例如hadoop自帶的o.a.h.mapreduce.lib.partition.InputSampler工具)。這裏介紹用Hive生成的方法,例如有一個按id有序的t_sale表:
  CREATE TABLE if not exists t_sale (
  id int,
  name string,
  loc string
  );
  則生成按sale_id分發的區間文件的方法是:
  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有序地分發reduce處理的數據。區間文件需要考慮的主要問題是數據分發的均衡性,這有賴於對數據深入的理解。

9.4 怎樣做笛卡爾積  
當Hive設定爲嚴格模式(hive.mapred.mode=strict)時,不允許在HQL語句中出現笛卡爾積,這實際說明了Hive對笛卡爾積支持較弱。因爲找不到Join key,Hive只能使用1個reducer來完成笛卡爾積。
  當然也可以用上面說的limit的辦法來減少某個表參與join的數據量,但對於需要笛卡爾積語義的需求來說,經常是一個大表和一個小表的Join操作,結果仍然很大(以至於無法用單機處理),這時MapJoin纔是最好的解決辦法。
  MapJoin,顧名思義,會在Map端完成Join操作。這需要將Join操作的一個或多個表完全讀入內存。
  MapJoin的用法是在查詢/子查詢的SELECT關鍵字後面添加/*+ MAPJOIN(tablelist) */提示優化器轉化爲MapJoin(目前Hive的優化器不能自動優化MapJoin)。其中tablelist可以是一個表,或以逗號連接的表的列表。tablelist中的表將會讀入內存,應該將小表寫在這裏。
  PS:有用戶說MapJoin在子查詢中可能出現未知BUG。在大表和小表做笛卡爾積時,規避笛卡爾積的方法是,給Join添加一個Join key,原理很簡單:將小表擴充一列join key,並將小表的條目複製數倍,join key各不相同;將大表擴充一列join key爲隨機數。

9.5 怎樣寫exist/in子句  
Hive不支持where子句中的子查詢,SQL常用的exist in子句需要改寫。這一改寫相對簡單。考慮以下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;
  一個更高效的實現是利用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個數  
Hadoop MapReduce程序中,reducer個數的設定極大影響執行效率,這使得Hive怎樣決定reducer個數成爲一個關鍵問題。遺憾的是Hive的估計機制很弱,不指定reducer個數的情況下,Hive會猜測確定一個reducer個數,基於以下兩個設定:
  1. hive.exec.reducers.bytes.per.reducer(默認爲1000^3)
  2. hive.exec.reducers.max(默認爲999)
  計算reducer數的公式很簡單:
  N=min(參數2,總輸入數據量/參數1)
  通常情況下,有必要手動指定reducer個數。考慮到map階段的輸出數據量通常會比輸入有大幅減少,因此即使不設定reducer個數,重設參數2還是必要的。依據Hadoop的經驗,可以將參數2設定爲0.95*(集羣中TaskTracker個數)。

9.7 合併MapReduce操作  
Multi-group by
  Multi-group by是Hive的一個非常好的特性,它使得Hive中利用中間結果變得非常方便。例如,
  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特性連續group by了2次數據,使用不同的groupby key。這一特性可以減少一次MapReduce操作。
  Multi-distinct
  Multi-distinct是淘寶開發的另一個multi-xxx特性,使用Multi-distinct可以在同一查詢/子查詢中使用多個distinct,這同樣減少了多次MapReduce操作

9.8 Bucket 
與sampling  Bucket是指將數據以指定列的值爲key進行hash,hash到指定數目的桶中。這樣就可以支持高效採樣了。
  如下例就是以userid這一列爲bucket的依據,共設置32個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可以在全體數據上進行採樣,這樣效率自然就低,它還是要去訪問所有數據。而如果一個表已經對某一列製作了bucket,就可以採樣所有桶中指定序號的某個桶,這就減少了訪問量。
  如下例所示就是採樣了page_view中32個桶中的第三個桶。
  SELECT *FROM page_view 
TABLESAMPLE(BUCKET 3 OUT OF 32);

9.9 Partition  
Partition就是分區。分區通過在創建表時啓用partition by實現,用來partition的維度並不是實際數據的某一列,具體分區的標誌是由插入內容時給定的。當要查詢某一分區的內容時可以採用where語句,形似where tablename.partition_key >a來實現。
  創建含分區的表
  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]
  載入內容,並指定分區標誌
  LOAD DATALOCAL INPATH /tmp/pv_2008-06-08_us.txt INTO TABLE page_view
PARTITION(date=’2008-06-08′,country=’US’);
  查詢指定標誌的分區內容
  SELECTpage_views.*
  FROM page_views
  WHERE 
page_views.date >=’2008-03-01′ AND page_views.date <= ’2008-03-31′ AND page_views.referrer_urllike ‘%’;
9.10 JOIN
9.10.1 JOIN原則  

在使用寫有 Join 操作的查詢語句時有一條原則:應該將條目少的表/子查詢放在 Join 操作符的左邊。原因是在 Join 操作的 Reduce 階段,位於 Join 操作符左邊的表的內容會被加載進內存,將條目少的表放在左邊,可以有效減少發生OOM 錯誤的機率。對於一條語句中有多個 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 相同,不管有多少個表,都會則會合併爲一個 Map-Reduce 
一個 Map-Reduce 任務,而不是 ‘n’ 個 
在做 OUTER 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.age = x.age);
  Map-Reduce 的任務數目和Join 操作的數目是對應的,上述查詢和以下查詢是等價的:
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,前提條件是需要的數據在 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,如圖所示:
  相關的參數爲:

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 數據傾斜 9.11.1 空值數據傾斜  場景:如日誌中,常會有信息丟失的問題,比如全網日誌中的user_id,如果取其中的user_id和bmw_users關聯,會碰到數據傾斜的問題。
  解決方法1: user_id爲空的不參與關聯
  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;
  結論:方法2比方法效率更好,不但io少了,而且作業數也少了。方法1 log讀取兩次,jobs是2。方法2 job數是1 。這個優化適合無效id(比如-99,’’,null等)產生的傾斜問題。把空值的key變成一個字符串加上隨機數,就能把傾斜的數據分到不同的reduce上 ,解決數據傾斜問題。附上Hadoop通用關聯的實現方法(關聯通過二次排序實現的,關聯的列爲parition key,關聯的列c1和表的tag組成排序的group key,根據parition key分配reduce。同一reduce內根據group
key排序)

9.11.2 不同數據類型關聯產生數據傾斜  
場景:一張表s8的日誌,每個商品一條記錄,要和商品表關聯。但關聯卻碰到傾斜的問題。s8的日誌中有字符串商品id,也有數字的商品id,類型是string的,但商品中的數字id是bigint的。猜測問題的原因是把s8的商品id轉成數字id做hash來分配reduce,所以字符串id的s8日誌,都到一個reduce上了,解決的方法驗證了這個猜測。
  解決方法:把數字類型轉換成字符串類型
  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的數據偏斜  

MapReduce編程模型下開發代碼需要考慮數據偏斜的問題,Hive代碼也是一樣。數據偏斜的原因包括以下兩點:
  1. Map輸出key數量極少,導致reduce端退化爲單機作業。
  2. Map輸出key分佈不均,少量key對應大量value,導致reduce端單機瓶頸。
  Hive中我們使用MapJoin解決數據偏斜的問題,即將其中的某個表(全量)分發到所有Map端進行Join,從而避免了reduce。這要求分發的表可以被全量載入內存。
  極限情況下,Join兩邊的表都是大表,就無法使用MapJoin。
  這種問題最爲棘手,目前已知的解決思路有兩種:
  1. 如果是上述情況1,考慮先對Join中的一個表去重,以此結果過濾無用信息。這樣一般會將其中一個大表轉化爲小表,再使用MapJoin 。
  一個實例是廣告投放效果分析,例如將廣告投放者信息表i中的信息填充到廣告曝光日誌表w中,使用投放者id關聯。因爲實際廣告投放者數量很少(但是投放者信息表i很大),因此可以考慮先在w表中去重查詢所有實際廣告投放者id列表,以此Join過濾表i,這一結果必然是一個小表,就可以使用MapJoin。
  2. 如果是上述情況2,考慮切分Join中的一個表爲多片,以便將切片全部載入內存,然後採用多次MapJoin得到結果。
  一個實例是商品瀏覽日誌分析,例如將商品信息表i中的信息填充到商品瀏覽日誌表w中,使用商品id關聯。但是某些熱賣商品瀏覽量很大,造成數據偏斜。例如,以下語句實現了一個inner join邏輯,將商品信息表拆分成2個表:
  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
  )
  );
  以下語句實現了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特性對錶做切分。

9.12 合併小文件  
文件數目過多,會給 HDFS 帶來壓力,並且會影響處理效率,可以通過合併 Map 和 Reduce 的結果文件來消除這樣的影響:
  rge.mapfiles = true 是否和並 Map 輸出文件,默認爲 True
  rge.mapredfiles = false 是否合併 Reduce 輸出文件,默認爲 False
  rge.size.per.task = 256*1000*1000 合併文件的大小

9.13 GroupBy  · 

Map 端部分聚合:
  並不是所有的聚合操作都需要在 Reduce 端完成,很多聚合操作都可以先在Map 端進行部分聚合,最後在 Reduce 端得出最終結果。
  基於 Hash
  參數包括:
  § hive.map.aggr = true 是否在 Map 端進行聚合,默認爲 True
  § hive.groupby.mapaggr.checkinterval= 100000 在 Map 端進行聚合操作的條目數目
  · 有數據傾斜的時候進行負載均衡
  hive.groupby.skewindata= false
  當選項設定爲 true,生成的查詢計劃會有兩個 MR Job。第一個 MR Job 中,Map 的輸出結果集合會隨機分佈到 Reduce 中,每個 Reduce 做部分聚合操作,並輸出結果,這樣處理的結果是相同的 Group By Key 有可能被分發到不同的Reduce 中,從而達到負載均衡的目的;第二個 MR Job再根據預處理的數據結果按照 Group By Key 分佈到 Reduce 中(這個過程可以保證相同的Group By Key 被分佈到同一個 Reduce
中),最後完成最終的聚合操作。

10. HIVE FAQ  
      1、 [admin@Hadoop1 ~]$ hive
  Cannot find hadoop installation: $HADOOP_HOME must be set orhadoop must be in the path
  原因:HADOOP路徑沒有在環境變量中定義
  解決方法: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的元數據庫derby服務沒有啓動
  進入到hive的安裝目錄
  /home/admin/caona/hive/build/dist/db-derby-10.4.1.3-bin/bin
  運行startNetworkServer -h 0.0.0.0
  3、[admin@hadoop1 conf]$ hive
  Unable to createlog directory ${build.dir}/tmp
  原因:存放日誌文件的目錄被人刪除了。
  解決方法:進行到${build.dir}下面,創建一個tmp目錄。
  如:[admin@hadoop1build]$ pwd
  /home/admin/caona/hive/build
  [admin@hadoop1build]$ mkdir tmp
發佈了29 篇原創文章 · 獲贊 3 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章