關於hive的基礎

愛吃大抄手的黃大超發表於2021-07-19

Hive基礎

1、引入原因

對存在HDFS上的檔案或HBase中的表進行查詢時,是要手工寫一堆MapReduce程式碼

對於統計任務,只能由懂MapReduce的程式設計師才能搞定

事實上,許多底層細節實際上進行的是從一個任務到下一個任務的重複性工作

使用MapReduce的時候遇到複雜的統計邏輯,這種MapReduce任務需要等上一個任務跑完再接下一個任務,而判斷一個任務是否跑完,則是通過檢測HDFS上對應輸出檔案是否生成_SUCCESS檔案來判斷,然後利用shell指令碼去把它們串起來,整個流程就很費時費力,而使用hive的sql形式則會相對來說更簡單。

Hive不僅提供了一個熟悉SQL的使用者所能快速使用熟悉的程式設計模型,還消除了大量的通用程式碼, 讓開發者可以花費很少的精力就完成大量的工作

2、hive是什麼

  • Hive是一個SQL解析引擎,將SQL語句轉譯成MR Job,然後再在Hadoop平臺上執行,達到快速開發的目的。

  • Hive中的表是純邏輯表,就只是表的定義等,即表的後設資料。本質就是Hadoop的目錄/檔案, 達到了後設資料與資料儲存分離的目的

  • Hive本身不儲存資料,它完全依賴HDFS和MapReduce。

  • Hive的內容是讀多寫少,不支援對資料的改寫和刪除

Hive從0.14版本後已經可以修改更新了,不過這個功能一般預設關閉的,也都是針對與內部表資料

  • Hive中沒有定義專門的資料格式,由使用者指定,需要指定三個屬性:列分隔符行分隔符讀取檔案資料的方法

常見的行分隔符:空格、\t、\001

常見的列分隔符:\n

讀取檔案資料方法:TextFile、SequenceFile(二進位制)、RCFile

  • 注:SequenceFile(二進位制):是hadoop提供的一種二進位制檔案,以<k,v>形式序列化到檔案中,java Writeable 介面進行序列化和反序列化。
  • 注:RCFile是Hive專門推出的,一種面向列的資料格式。

通常都會先對要統計的資料提前做處理,將內容中可能會出現的分隔符先處理掉,防止處理資料的時候因為內容中包含對應分隔符而導致資料丟失,分隔符一般是需要打日誌的時候大家約定好,所以不同公司的分割符都各有區別。

總結:Hive是基於Hadoop的一個資料倉儲工具,可以將結構化的資料檔案對映為一張表,並提供類SQL查詢功能。本質是將HQL轉化成MapReduce程式:1、Hive處理的資料儲存在HDFS,2、Hive分析資料底層的實現是MapReduce,3、執行程式執行在YARN上。

Hive的優缺點

優點:

​ 1)操作介面採用類SQL語法,提供快速開發的能力(簡單、容易上手)

​ 2)避免了去寫MapReduce,減少開發人員的學習成本。

​ 3)Hive的執行延遲比較高,因此Hive常用於對實時性要求不高的場合的資料分析;

​ 4)Hive優勢在於處理大資料,對於處理小資料沒有優勢

​ 5)Hive支援使用者自定義函式,使用者可以根據自己的需求來實現自己的函式。

缺點:

​ 1)Hive的HQL表達能力有限

​ (1)迭代式演算法無法表達

​ (2)資料探勘方面不擅長

​ 2)Hive的效率比較低

​ (1)Hive自動生成的MapReduce作業,通常情況下不夠智慧化

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

3、Java和Hive:詞頻統計演算法

Java:

package org.myorg;

import java.io.IOException;
import java.util.*;

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.conf.*;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.*;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

public class WordCount {
    public static classMapextendsMapper<LongWritable, Text, Text,
            IntWritable>
    private final static IntWritable one = newIntWritable(1);
    private Text word = newText();

    public void map(LongWritable key, Text value, Context context)
            throws IOException, InterruptedException {
        String line = value.toString();
        StringTokenizer tokenizer = new String Tokenizer(line);.
        while (tokenizer.hasMoreTokens()) {
            word.set(tokenizer.nextToken());
            context.write(word, one);
        }
    }
}

public static class Reduce extends Reducer<Text, IntWritable, Text,
        IntWritable> {
    public void reduce(Text key, Iterable<IntWritable> values, Context
            context)
            throws IOException, InterruptedException {
        int sum = 0;
        for (IntWritable val
             values) {
            sum += val.get();
            context.write(key, new IntWritable(sum));
            public static void main (String[]args)throws Exception {
                Configuration conf = new Configuration();
                Job job = new Job(conf, "wordcount");
                job.setOutputKeyClass(Text.class);
                job.setOutputValueClass(IntWritable.class);
                job.setMapperClass(Map.class);
                job.setReducerClass(Reduce.class);
                job.setInputFormatClass(TextInputFormat.class);
                job.setOutputFormatClass(TextOutputFormat.class);
                FileInputFo rmat.addInputPath(job, new Path(args[0]));
                File0utputFormat.setOutputPath(job, new Path(args[1]));
                job.waitForCompletion(true);
            }
        }
    }
}

hive:

create table docs(line String);
load data inpath 'docs' overwrite into table docs;
create table word_counts as 
select word,count(1) as cnt 
from (select explode(split(line,'\s')) as word from docs) w
group by word
order by word;

上述兩個例子都是儘可能簡單的方法將檔案中的內容分割成單詞,也就是按照空格進行劃分的。藉助java API可以定製和調整一個演算法實現的每個細節,不過大多數情況下,使用者都不需要這個級別的控制,而hive則可以更容易快速的實現大多數情況的需求。

4、Hive中的SQL與傳統SQL區 別

HQL SQL
資料儲存 HDFS、Hbase Local FS
資料格式 使用者自定義 系統決定
資料更新 不支援(把之前的資料覆蓋) 支援
索引 有(0.8版之後增加)
執行 MapReduce(select * from table) Executor
執行延遲
可擴充套件性 高(UDF、UDAF,UDTF)
資料規模 大(資料大於TB)
資料檢查 讀時模式 寫時模式
  • hive和關聯式資料庫儲存檔案的系統不同,hive使用的是hadoop的HDFS(hadoop的分散式檔案系統),關聯式資料庫則是伺服器本地的檔案系統;

  • hive使用的計算模型是mapreduce,而關聯式資料庫則是自己設計的計算模型;

  • 關聯式資料庫都是為實時查詢的業務進行設計的,而hive則是為海量資料做資料探勘設計的,實時性很差

  • Hive很容易擴充套件自己的儲存能力和計算能力,這個是繼承hadoop的,而關聯式資料庫在這個方面要比Hive差很多

UDF:直接應用於select語句,通常查詢的時候,需要對欄位做一些格式化處理(如:大小寫轉換)《特點:一進一出,一比一的關係。》

UDAF:多對一的場景,如聚合時

UDTF:一對多的場景

以上都是使用者自定義函式

讀時模式:只有在讀的時候才會檢查、解析欄位和schema(資料結構表達)優點:載入資料的時候非常迅速,因為在寫的過程中是不需要解析資料

寫時模式:則是在寫入的時候就會檢查解析等,缺點:寫的慢,需要建立索引、壓縮、資料一致性、欄位檢查等等 優點:讀的時候會得到優化

5、Hive體系架構

1)使用者介面:Client

CLI(hive shell)、JDBC/ODBC(Hive的客戶端,使用者通過java連線至Hive Server)、WEBUI(瀏覽器訪問hive,在公司一般通過遊覽器的方式操作)

2)後設資料:Metastore

後設資料包括:表名、表所屬的資料庫(預設是default)、表的擁有者、列/分割槽欄位、表的型別(是否是外部表)、表的資料所在目錄等;

預設儲存在自帶的derby資料庫中,推薦使用MySQL儲存Metastore

3)Hadoop

使用HDFS進行儲存,使用MapReduce進行計算。

Hive資料以檔案形式儲存在HDFS的指定目錄下

Hive語句生成查詢計劃,由MapReduce呼叫執行

4)驅動器:Driver

(1)解析器(SQL Parser):將SQL字串轉換成抽象語法樹AST,這一步一般都用第三方工具庫完成,比如antlr;對AST進行語法分析,比如表是否存在、欄位是否存在、SQL語義是否有誤。

(2)編譯器(Physical Plan):將AST編譯生成邏輯執行計劃。

(3)優化器(Query Optimizer):對邏輯執行計劃進行優化。

(4)執行器(Execution):把邏輯執行計劃轉換成可以執行的物理計劃。對於Hive來說,就是MR/Spark。

6、Hive執行流程

1)流程概述

完整流程:通過UI或者Client的形式提交任務(使用JDBC的形式,只是多了一層Thrift Server,它們三種形式本質上都是一樣的),首先使用者的executeQuery(查詢命令),會由driver進行解析(解析過程為:driver會將執行的語句先交給compiler(解析器)生成抽象語法樹,檢查SQL語法是否正確即getPlan,然後通過metastore(後設資料儲存,一般儲存在mysql裡面)getMetaData(獲取後設資料資訊),用來檢查語句中的表是否存在,再將檢查資訊sendMetaData(傳送後設資料資訊)到compiler,compiler會綜合檢查資訊,sendPlan到driver。)如果語句解析都沒問題,driver則通過將語句整理為executePlan(執行計劃)到executionEngine(執行引擎),由executionEngine提交MR任務到Hadoop的JobTracker,同時也會通過metastore獲取對應的後設資料資訊,再由Hadoop來執行相應的MR任務後再將結果返回到executionEngine,executionEngine再將結果sendResults(傳送結果)到driver,driver最後整理結果fetchResults(獲取結果)到任務提交端。

簡述:Hive通過給使用者提供的一系列互動介面,接收到使用者的指令(SQL),使用自己的Driver,結合後設資料(MetaStore),將這些指令翻譯成MapReduce,提交到Hadoop中執行,最後,將執行返回的結果輸出到使用者互動介面。

Hive 在執行一條 HQL 的時候,會經過以下步驟:

1、語法解析:Antlr 定義 SQL 的語法規則,完成 SQL 詞法,語法解析,將 SQL 轉化為抽象語法樹 AST Tree;

2、語義解析:遍歷 AST Tree,抽象出查詢的基本組成單元 QueryBlock;

3、生成邏輯執行計劃:遍歷 QueryBlock,翻譯為執行操作樹 OperatorTree,其中是一個個操作符Operator;

操作符 Operator 是 Hive 的最小處理單元,每個操作符代表一個 HDFS 操作或者 MapReduce 作業

4、優化邏輯執行計劃:邏輯層優化器進行 OperatorTree 變換,合併不必要的 ReduceSinkOperator,減少 shuffle 資料量;

5、生成物理執行計劃:遍歷 OperatorTree,翻譯為 MapReduce 任務;

6、優化物理執行計劃:物理層優化器進行 MapReduce 任務的變換,生成最終的執行計劃。

最後Hive 通過 ExecMapper 和 ExecReducer 執行 MapReduce 程式,執行模式有本地模式和分散式兩種模式

2)Hive操作符列表
操作符 描述
TableScanOperator 掃描hive表資料
ReduceSinkOperator 建立將傳送到Reducer端的<Key,Value>對
JoinOperator Join兩份資料
SelectOperator 選擇輸出列
FileSinkOperator 建立結果資料,輸出至檔案
FilterOperator 過濾輸入資料
GroupByOperator Group By語句
MapJoinOperator /* + mapjoin(t) */
LimitOperator Limit語句
UnionOperator Union語句
3)Hive 編譯器的工作職責

(1)Parser:將 HQL 語句轉換成抽象語法樹(AST:Abstract Syntax Tree)

(2)Semantic Analyzer:將抽象語法樹轉換成查詢塊

(3)Logic Plan Generator:將查詢塊轉換成邏輯查詢計劃

(4)Logic Optimizer:重寫邏輯查詢計劃,優化邏輯執行計劃

(5)Physical Plan Gernerator:將邏輯計劃轉化成物理計劃(MapReduce Jobs)

(6)Physical Optimizer:選擇最佳的 Join 策略,優化物理執行計劃

4)優化器型別
名稱 作用
② SimpleFetch0pt imizer 優化沒有GroupBy表示式的聚合查詢
② MapJoinProcessor MapJoin,需要SQL中提供hint, 0. 11版本已不用
② BucketMapJoinOptimizer BucketMapJoin
② GroupByOptimizer Map端聚合
① ReduceSinkDeDupl ication 合併線性的OperatorTree中partition/sort key 相同的reduce
① PredicatePushDown 謂詞前置
① CorrelationOptimizer 利用查詢中的相關性,合併有相關性的Job,HIVE- -2206
ColumnPruner 欄位剪枝

注:上表中帶①符號的,優化目的都是儘量將任務合併到一個 Job 中,以減少 Job 數量,帶②的優化目的是儘量減少 shuffle 資料量

5)Join實現過程
SELECT pv.pageid, u.age FROM page_view pv JOIN user u ON pv.userid = u.userid;

對於上述 join 操作實現過程:

Map

  1、以 JOIN ON 條件中的列作為 Key,如果有多個列,則 Key 是這些列的組合

  2、以 JOIN 之後所關心的列作為 Value,當有多個列時,Value 是這些列的組合。在 Value 中還會包含表的 Tag 資訊,用於標明此 Value 對應於哪個表

  3、按照 Key 進行排序

Shuffle

  1、根據 Key 的值進行 Hash,並將 Key/Value 對按照 Hash 值推至不同對 Reduce 中

Reduce

  1、 Reducer 根據 Key 值進行 Join 操作,並且通過 Tag 來識別不同的表中的資料

6)GroupBy實現過程
SELECT pageid, age, count(1) FROM pv_users GROUP BY pageid, age; 

對於上述 group by 操作實現過程:

7)Distinct實現過程

按照 age 分組,然後統計每個分組裡面的不重複的 pageid 有多少個

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

對於上述 distinct操作實現過程如下圖,該 SQL 語句會按照 age 和 pageid 預先分組,進行 distinct 操作。然後會再按 照 age 進行分組,再進行一次 distinct 操作

7、Hive資料管理

hive的表本質就是Hadoop的目錄/檔案

hive預設表存放路徑一般都是在你工作目錄的hive目錄裡面,按表名做資料夾分開,如果你有分割槽表的話,分割槽值是子資料夾,可以直接在其它的M/R job裡直接應用這部分資料

Name HDFS Directory
Table mobile_user /lbs/mobile_user
Partition action = insight, dt= 20131020 pc m app /lbs/mobile_user/action=insight/dt=20131020
Bucket clusted by user into 32 buckets /lbs/mobile_user/action=insight/dt=20131020/part-00031

1)Hive資料型別

Hive 表中的列支援以下基本資料型別:《數倉中最常用的是string和DECIMAL》

大類 型別
Integers(整型) TINYINT—1 位元組的有符號整數SMALLINT—2 位元組的有符號整數INT—4 位元組的有符號整數BIGINT—8 位元組的有符號整數
Boolean(布林型) BOOLEAN—TRUE/FALSE
Floating point numbers(浮點型) FLOAT— 單精度浮點型DOUBLE—雙精度浮點型
Fixed point numbers(定點數) DECIMAL—使用者自定義精度定點數,比如 DECIMAL(7,2)
String types(字串) STRING—指定字符集的字元序列VARCHAR—具有最大長度限制的字元序列CHAR—固定長度的字元序列
Date and time types(日期時間型別) TIMESTAMP — 時間戳TIMESTAMP WITH LOCAL TIME ZONE — 時間戳,納秒精度DATE—日期型別
Binary types(二進位制型別) BINARY—位元組序列
Hive 資料型別 Java 資料型別 長度 例子
TINYINT byte 1byte 有符號整數 20
SMALINT short 2byte 有符號整數 20
INT int 4byte 有符號整數 20
BIGINT long 8byte 有符號整數 20
BOOLEAN boolean 布林型別,true 或者 false TRUE FALSE
FLOAT float 單精度浮點數 3.14159
DOUBLE double 雙精度浮點數 3.14159
STRING string 字元系列。可以指定字符集。可以使用單引號或者雙引號。 ‘now is the time’ “for all good men”
TIMESTAMP 時間型別
BINARY 位元組陣列

注:

​ 對於 Hive 的 String 型別相當於資料庫的 varchar 型別,該型別是一個可變的字串,不過它不能宣告其中最多能儲存多少個字元,理論上它可以儲存 2GB 的字元數。

​ TIMESTAMP 和 TIMESTAMP WITH LOCAL TIME ZONE 的區別如下:

1、TIMESTAMP WITH LOCAL TIME ZONE:使用者提交時間給資料庫時,會被轉換成資料庫所在的時區來儲存。查詢時則按照查詢客戶端的不同,轉換為查詢客戶端所在時區的時間。

2、TIMESTAMP :提交什麼時間就儲存什麼時間,查詢時也不做任何轉換。

複雜型別:

型別 描述 示例
STRUCT 類似於物件,是欄位的集合,欄位的型別可以不同,可以使用《名稱.欄位名》方式進行訪問 STRUCT ('xiaoming', 12 , '2018-12-12')
MAP 鍵值對的集合,可以使用《名稱[key]》的方式訪問對應的值 map('a', 1, 'b', 2)
ARRAY 陣列是一組具有相同型別和名稱的變數的集合,這些變數稱為陣列的元素,每個陣列元素都有一個編號,編號從零開始。可以使用《名稱[index]》訪問對應的值 ARRAY('a', 'b', 'c', 'd')

示例:

如下給出一個基本資料型別和複雜資料型別的使用示例:

1)建立本地測試檔案 test.txt

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

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

2)Hive 上建立測試表 test

create table test(

	name string, 

	friends array<string>, 

	children map<string, int>,

	address struct<street:string, city:string>)

row format delimited 

fields terminated by ',' 

collection items terminated by '_' 

map keys terminated by ':' 

lines terminated by '\n';

欄位解釋:

row format delimited fields terminated by ',' -- 列分隔符

collection items terminated by '_' --MAP STRUCT 和 ARRAY 的分隔符(資料分割符號)<這意味著map,struct,array等的分隔符必須保持一致>

map keys terminated by ':' -- MAP 中的 key 與 value 的分隔符

lines terminated by '\n'; -- 行分隔符<這個預設是/n,可以不寫>

3)匯入文字資料到測試表

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

4)訪問三種集合列裡的資料,以下分別是 ARRAY,MAP,STRUCT 的訪問方式

hive (default)>select friends[1],children['xiao song'],address.city from test where name="songsong";

OK

_c0   _c1   city lili  18   beijing

Time taken: 0.076 seconds, Fetched: 1 row(s)

2)Hive儲存格式

Hive資料以檔案形式儲存在HDFS的指定目錄下

Hive語句生成查詢計劃,由MR呼叫執行

檔案儲存的格式:
1.textfile

預設格式,建表時不指定預設為這個格式

儲存方式:行儲存

優點:可以直接讀取

缺點:磁碟開銷大 資料解析開銷大。壓縮的text檔案 hive無法進行合併和拆分

2.sequencefile

二進位制檔案,以<key,value>的形式序列化到檔案中

儲存方式:行儲存

缺點:儲存空間消耗最大

優點:可分割 壓縮,全表時查詢效率高

一般選擇block壓縮,檔案和Hadoop api中的mapfile是相互相容的。EQUENCEFILE將資料以<key,value>的形式序列化到檔案中。序列化和反序列化使用Hadoop 的標準的Writable 介面實現。key為空,用value 存放實際的值, 這樣可以避免map 階段的排序過程。三種壓縮選擇:NONE, RECORD, BLOCK。 Record壓縮率低,一般建議使用BLOCK壓縮。使用時設定引數,

SET hive.exec.compress.output=true;
SET io.seqfile.compression.type=BLOCK; -- NONE/RECORD/BLOCK

create table test2(str STRING)  
STORED AS SEQUENCEFILE; 
3.rcfile

一種行列儲存相結合的儲存方式。首先,其將資料按行分塊,保證同一個record在一個塊上,避免讀一個記錄需要讀取多個block。其次,塊資料列式儲存,有利於資料壓縮和快速的列存取。 理論上具有高查詢效率(但hive官方說效果不明顯,只有儲存上能省10%的空間,所以不好用,可以不用)。

RCFile結合行儲存查詢的快速和列儲存節省空間的特點

1)同一行的資料位於同一節點,因此元組重構的開銷很低;

  1. 塊內列儲存,可以進行列維度的資料壓縮,跳過不必要的列讀取。

查詢過程中,在IO上跳過不關心的列。實際過程是,在map階段從遠端拷貝仍然拷貝整個資料塊到本地目錄,也並不是真正直接跳過列,而是通過掃描每一個row group的頭部定義來實現的。但是在整個HDFS Block 級別的頭部並沒有定義每個列從哪個row group起始到哪個row group結束。所以在讀取所有列的情況下,RCFile的效能反而沒有SequenceFile高。

優點:壓縮快, 快速列存取, 讀記錄儘量涉及到的block最少 ,讀取需要的列只需要讀取每個row group 的頭部定義。

缺點:讀取全量資料的操作 效能可能比sequencefile沒有明顯的優勢。但是如果指定一列的話,效率最高

4.orc

儲存方式:資料按行分塊 每塊按照列儲存

壓縮快 快速列存取

效率比rcfile高,是rcfile的改良版本

5.自定義格式

使用者可以通過實現inputformat和 outputformat來自定義輸入輸出格式。

總結

textfile 儲存空間消耗比較大,並且壓縮的text 無法分割和合並 查詢的效率最低,可以直接儲存,載入資料的速度最高

sequencefile 儲存空間消耗最大,壓縮的檔案可以分割和合並 查詢效率高,需要通過text檔案轉化來載入

rcfile 儲存空間最小,查詢的效率最高 ,需要通過text檔案轉化來載入,載入的速度最低

注:hive預設本地資料庫(用來儲存後設資料):derby(單使用者模式常用),而一般開發是用mysql(多使用者模式、遠端服務模式)

指定儲存格式

通常在建立表的時候使用 stored as 引數指定:

create table 表名(欄位名 型別,欄位名 型別)
row format delimited 
    fields terminated by 欄位分隔符 
    lines terminated by 列分隔符
STORED AS 儲存格式;

2)型別轉換

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

隱式轉換

Hive 中基本資料型別遵循以下的層次結構,按照這個層次結構,子型別到祖先型別允許隱式轉換。例如 INT 型別的資料允許隱式轉換為 BIGINT 型別。額外注意的是:按照型別層次結構允許將 STRING 型別隱式轉換為 DOUBLE 型別。

隱式型別轉換規則如下

(1)任何整數型別都可以隱式地轉換為一個範圍更廣的型別,如 TINYINT 可以轉換成 INT,INT 可以轉換成 BIGINT。

(2)所有整數型別、FLOAT 和 STRING 型別<內容必須是數值>都可以隱式地轉換成 DOUBLE。

(3)TINYINT、SMALLINT、INT 都可以轉換為 FLOAT。

(4)BOOLEAN 型別不可以轉換為任何其它的型別。

CAST 操作

可以使用 CAST 操作顯示進行資料型別轉換

例如 CAST('1' AS INT)將把字串'1' 轉換成整數 1;

如果強制型別轉換失敗,如執行CAST('X' AS INT),表示式返回空值 NULL。

8、Hive的四種資料模型

1)資料表

Table(內部表)

一般說的hive表都是指內部表,預設建立的表都是所謂的內部表,有時也被稱為管理表。(因為這種表,Hive 會(或多或少地)控制著資料的生命週期。管理表不適合和其他工具共享資料。)Hive中的內部表在HDFS中都有相應的目錄用來儲存表的資料,目錄可以通過${HIVE_HOME}/conf/hive-site.xml配置檔案中的 hive.metastore.warehouse.dir屬性來配置,一般預設的值是/user/hive/warehouse(這個目錄在 HDFS上),如果我有一個表test,那麼在HDFS中會建立/user/hive/warehouse/test目錄(這裡假定hive.metastore.warehouse.dir配置為/user/hive/warehouse);test表所有的資料都存放在這個目錄中,當然,外部表可以配置其它hdfs來對映檔案。可以使用如下命令來檢視錶對應hdfs的檔案:dfs -ls /hive/warehouse/ods_uba.db/test;

External table(外部表)

Hive中的外部表和表很類似,只不過是建表時可以指定載入的hdfs目錄,也可以不指定後頭根據需要再進行載入。如果外部表使用hive命令刪除表,對應的hdfs檔案是不會被刪除。外部表比較靈活,不止可以關聯到hdfs檔案,也可以關聯到hbse表。其建表和內部表稍有不同,但是可用的資料型別都是一樣的。因為當表被設定是外部表, Hive就認為並非其完全擁有這份資料。刪除該表不會刪除掉這份資料,只會將描述表的後設資料資訊會被刪除掉。

內部表和外部表的區別

(1)、外部表建立時要新增EXTERNAL,外部表查詢是隻是去關聯hdfs檔案,並按照分割符號轉成對應的欄位

(2)、外部表刪除表後,hdfs檔案不會被刪除。同理,外部表刪除分割槽後,hdfs檔案也不會被刪除,針對誤操作提高了容錯。

(3)、內部表刪除時候,不僅表結構會被刪除,資料也會被刪除,沒法恢復,而外部表刪除後重新建立時,資料就自動恢復了,不會真的刪除掉資料,針對誤操作提高了容錯。

2)分割槽表

Partition(分割槽表)

在Hive中,Partition表中的一個Partition對應於表下的一個目錄,所有的Partition的資料都儲存在對應的目錄中。分割槽表主要是為了輔助查詢,縮小查詢範圍,加快資料的檢索速度和對資料按照一定的規格和條件進行管理。《工作中常見的是分割槽表,日期(date),按照天分割槽;來源(source),三端app,m(mobile手機端頁面,一般是分享頁面),pc》——什麼時候採用分割槽?主要是結合業務,經常要用到的分析條件(業內術語一般稱“口徑”)在where條件裡面經常要被用到的,可以按照條件進行設計分割槽。(設計表之後也要儘量根據資料來優化業務表,提高資料使用效率!)

分割槽表實際上就是對應一個HDFS檔案系統上的獨立的資料夾,該資料夾下是該分割槽所有的資料檔案。Hive中的分割槽就是分目錄,把一個大的資料集根據業務需要分割成小的資料集。在查詢時通過 WHERE 子句中的表示式選擇查詢所需要的指定的分割槽,這樣的查詢效率會提高很多。

Bucket(分桶表)

在Hive中,table可以拆分成partition,而table和partition還可以通過‘CLUSTERED BY’進一步拆分,即分桶,bucket中的資料可以通過SORT BY排序;

set hive.enforce.bucketing = true可以自動控制上一輪的reduce的數量從而適配bucket的個數,當然,使用者也可以自主設定mapred.reduce.tasks去適配bucket個數;分桶的原理就是對指定的列計算其hash,根據hash值切分資料,目的是為了並行,每一個桶對應一個檔案(注意和分割槽的區別)。

比如將lin_test表start_time列分散至16個桶中,首先對id列的值計算hash,

對應hash值為0和16的資料儲存的HDFS目錄為:/user/hive/warehouse/lin_test/start_date=20191218/part-00000;

而hash值為2的資料儲存的HDFS 目錄為:/user/hive/warehouse/start_date=20191218/part-00002。

bucket的重要作用是:資料sampling(取樣),提升某些查詢操作的效率,例如mapside join。不過一般情況下不建議將分桶設定太大,以免小檔案過多引起其它更多的問題,用好分桶才能真的有助於提高計算的效率。

hive>select * from student tablesample(bucket 1 out of 2 on id);

tablesample是抽樣語句,語法:tablesample(bucket x out of y)

y一般是table總bucket數的倍數或者因子。hive根據y的大小決定抽樣的比例,用總bucket數除y的值,即得到需要抽樣的個數,x則代表從第幾個bucket開始抽取,每次抽取間隔的bucket數就是y的值。

分割槽提供一一個隔離資料和優化查詢的便利的方式。不過,並非所有的資料集都可形成合理的分割槽,特別是之前所提到過的要確定合適的劃分大小這個疑慮。分桶是將資料集分解成更容易管理的若干部分的另一個技術。例如,假設有個表的一級分割槽是dt,代表日期,二級分割槽是user_ id, 那麼這種劃分方式可能會導致太多的小分割槽。回想下,如果使用者是使用動態分割槽來建立這些分割槽的話,那麼預設情況下,Hive會限制動態分割槽可以建立的最大分割槽數,用來避免由於建立太多的分割槽導致超過了檔案系統的處理能力以及其他一些問題。因此,如下命令可能會執行失敗:

hive> CREATE TABLE weblog (url STRING,source_ ip STRING)

hive> PARTITIONED BY (dt STRING, user_ id INT) ;

hive> FROM raw_ weblog

hive> INSERT OVERWRITE TABLE page_ view PARTITION(dt='2020-06-08', user_ id)

hive> SELECT server_ name, url, source_ ip, dt, user_ id;

不過,如果我們對錶weblog進行分桶,並使用user_ id 欄位作為分桶欄位,則欄位值會根據使用者指定的值進行雜湊分發到桶中。同一個user_ id下的記錄通常會儲存到同一個桶內。假設使用者數要比桶數多得多,那麼每個桶內就將會包含多個使用者的記錄:

hive> CREATE TABLE weblog (user_ id INT, url STRING, source_ ip STRING)

hvie> PARTITIONED BY (dt STRING)

hvie> CLUSTERED BY (user_ id) INTO 96 BUCKETS;

不過,將資料正確地插人到表的過程完全取決於使用者自己。CREATE TABLE語句中所規定的資訊僅僅定義了後設資料,而不影響實際填充表的命令。下面介紹如何在使用INSERT ... TABLE語句時,正確地填充表。首先,我們需要設定一個屬性來強制Hive 為目標表的分桶初始化過程設定-一個 正確的reducer 個數。然後我們再執行一個查詢來填充分割槽。例如:

hive> SET hive. enforce .bucketing = true;

hive> FROM raw_ logs

hive> INSERT OVERWRITE TABLE weblog

hive> PARTITION (dt='2009-02-25' )

hive> SELECT user_ id, url, source_ ip WHERE dt='2020-02-25';

如果我們沒有使用hive.enforce. bucketing屬性,那麼我們就需要自己設定和分桶個數相匹配的reducer個數,例如,使用set mapred.reduce.tasks=96,然後在INSERT語句中的SELECT語句後增加CLUSTER BY語句。

分桶優點

1、因為桶的數量是固定的,所以它沒有資料波動。桶對於抽樣再合適不過。如果兩個表都是按照user_ id 進行分桶的話,那麼Hive可以建立一個邏輯上正確的抽樣。

2、分桶有利於執行高效的map-side JOIN:如果所有表中的資料是分桶的,那麼對於大表,在特定的情況下同樣可以使用這個優化。簡單地說,表中的資料必須是按照ON語句中的鍵進行分桶的,而且其中一張表的分桶的個數必須是另一張表分桶個數的若干倍。當滿足這些條件時,那麼Hive可以在map階段按照分桶資料進行連線。因此這種情況下,不需要先獲取到表中所有的內容,之後才去和另一張表中每個分桶進行匹配連線。這個優化同樣預設是沒有開啟的。需要設定引數hive.optimize.bucketmapJOIN為true才可以開啟此優化:

set hive.opt imize.bucke tmapJOIN=true;

如果所涉及的分桶表都具有相同的分桶數,而且資料是按照連線鍵或桶的鍵進行排序的,那麼這時Hive可以執行一個更快的分類-合併連線(sort-merge JOIN)。同樣地,這個優化需要需要設定如下屬性才能開啟:

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

set hive.optimi ze.bucketmapj oin=true;

set hive.optimize.bucketmapj oin. sortedmerge=true;

相關文章