1. 程式人生 > >Hive資料倉庫你瞭解了嗎

Hive資料倉庫你瞭解了嗎

在工作中我們經常使用的資料庫,資料庫一般存放的我們系統中常用的資料,一般為百萬級別。如果資料量龐大,達到千萬級、億級又需要對他們進行關聯運算,該怎麼辦呢?
前面我們已經介紹了HDFS和MapReduce了,它倆結合起來能夠進行各種運算,可是MapReduce的學習成本太高了,如果有一種工具可以直接使用sql將hdfs中的資料查出來,並自動編寫mapreduce進行運算,這就需要使用到我們的hive資料倉庫。

Hive基本概念

什麼是Hive

Hive是基於Hadoop的一個數據倉庫工具,可以將結構化的資料檔案對映為一張資料庫表,並提供類SQL查詢功能。

為什麼使用Hive

  • 直接使用hadoop所面臨的問題
    人員學習成本太高
    專案週期要求太短
    MapReduce實現複雜查詢邏輯開發難度太大
  • 為什麼要使用Hive
    操作介面採用類SQL語句,提供快速開發的能力。
    避免了去寫MapReduce,減少開發人員的學習成本。
    擴充套件功能很方便

Hive的特點

  • 可擴充套件
    Hive可以自由的擴充套件叢集的規模,一般情況下不需要重啟服務。
  • 延展性
    Hive支援使用者自定義函式,使用者可以根據自己的需求來實現自己的函式。注意:這裡說的函式可不是儲存過程噢。
  • 容錯
    良好的容錯行,節點出現問題SQL仍可以完成執行

基本組成

  • 使用者介面:包括CLI、JDBC/ODBC、WebGUI
  • 元資料儲存:通常是儲存在關係資料庫如 mysql,derby中。
  • 直譯器、編譯器、優化器、執行器

各元件的基本功能

  • 使用者介面主要有三個:CLI、JDBC/ODBC和WebGUI。其中,CLI為shell命令列;JDBC/ODBC是Hive的JAVA實現,與傳統資料庫JDBC類似;WebGUI是通過瀏覽器訪問Hive
  • 元資料儲存:Hive將元資料儲存在資料庫中。Hive中的元資料包括表的名字,表的列和分割槽及其屬性,是否為外部表,表的資料所在的目錄等等。
  • 直譯器、編譯器、優化器完成HQL查詢語句從此法分析、語法分析、編譯、優化以及查詢計劃的生成。生成的查詢計劃儲存在HDFS中,並且隨後使用MapReduce執行。

Hive與Hadoop的關係

sequenceDiagram
客戶端->>Hive處理轉換成MapReduce: 傳送HSQL語句
Hive處理轉換成MapReduce->>MapReduce執行: 提交任務到Hadoop
MapReduce執行->>執行結果檔案放到HDFS或本地: 執行結果

Hive與傳統資料庫對比

--- Hive RDBMS
查詢語言 HQL SQL
資料儲存 HDFS Raw Device or Local FS
執行 MapReduce Excutor
執行延遲
處理資料規模
索引 0.8版本後加入點陣圖索引 有複雜的索引

==hive中具有sql資料庫,用來儲存元資料資訊(如:表的屬性,資料的位置)。hive只適合用來做批量資料統計分析。讀多寫少==

Hive的資料儲存

  1. Hive中所有的資料都儲存在HDFS中,沒有專門的資料儲存格式(可支援Text,SequenceFile,ParqueFile,RCFile等)
  2. 只需要在建立表的時候告訴Hive資料中的列分隔符和行分隔符。預設列分隔符為ascii碼的控制符\001,行分隔符為換行符。
  3. Hive中包含以下資料模型:DB、Table、External Table、Partition、Bucket。
  • db:在hdfs中表現為hive.metastore.warehouse.dir目錄下的一個資料夾
  • table:在hdfs中表現為所屬db目錄下的一個資料夾
  • external table:與table類似,不過其資料存放位置可以在任意指定路徑。刪除表時只會刪除元資料,不會刪除實際資料
  • partition:在hdfs中表現為table目錄下的子目錄
  • bucket: 在hdfs中表現為同一個表目錄下根據hash雜湊之後的多個檔案

Hive的安裝部署

安裝

單機版(內建關係型資料庫derby)
元資料庫mysql版

這裡使用常用的mysql版,使用derby的話不太方便,因為derby會將檔案儲存在你當前啟動的目錄。如果下次你換個目錄啟動,會發現之前儲存的資料不見了。

元資料庫mysql版安裝

安裝mysql資料庫

mysql安裝僅供參考,不同版本mysql有各自的安裝流程。
# 刪除原有的mysql
rpm -qa | grep mysql
rpm -e mysql-libs-5.1.66-2.el6_3.i686 --nodeps
rpm -ivh MySQL-server-5.1.73-1.glibc23.i386.rpm 
rpm -ivh MySQL-client-5.1.73-1.glibc23.i386.rpm 

# 修改mysql的密碼,並記得設定允許使用者遠端連線
/usr/bin/mysql_secure_installation

# 登入mysql
mysql -u root -p

配置hive

配置HIVE_HOME環境變數

vi conf/hive-env.sh
#配置其中的$hadoop_home

配置元資料庫資訊

vi hive-site.xml

#新增如下內容


<configuration>
<!--配置mysql的連線地址-->
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://localhost:3306/hive?createDatabaseIfNotExist=true</value>
<description>JDBC connect string for a JDBC metastore</description>
</property>

<!--配置mysql的驅動-->
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
<description>Driver class name for a JDBC metastore</description>
</property>

<!--配置登入使用者名稱-->
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
<description>username to use against metastore database</description>
</property>

<!--配置登入密碼-->
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>root</value>
<description>password to use against metastore database</description>
</property>
</configuration>

放驅動包

安裝hive和mysql完成後,將mysql的連線jar包拷貝到$HIVE_HOME/lib目錄下
如果出現沒有許可權的問題,在mysql授權
mysql -uroot -p

#執行下面的語句 *.*:表示所有庫下的所有表    %:任何ip地址或主機都可以連線
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENDIFIED BY 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES;

Jline包版本不一致問題

到這一步其實已經安裝好了,但是由於hadoop中的jline包版本和我們安裝hive的jline包版本不一致,會導致hql無法被執行。
因此我們還要把hive的lib目錄中的jline.2.12.jar替換掉$HADOOP_HOME/share/hadoop/yarn/lib/jline.0.9.94.jar

啟動hive

bin/hive

登入hive

1.bin/hive

2.bin/beeline
!connect jdbc:hive2://server1:10000

3.bin/beeline -u jdbc:hive2://server1:10000 -n hadoop

建立表

建立外部表

create table tb_external(id int,name string) row format delimited fields terminated by',' location 'hdfs://kris/myhiveexternal';

在hdfs中已在對應路徑存在檔案

現在試試直接查詢

==為了保證資料的安全,我們一般把源資料表設定為外部表。資料只能通過外部載入匯入==

建立帶桶的表

hive> create table student(id INT,age INT,name STRING)
    > partitioned by(stat_date STRING)
    > clustered by(id) sorted by(age) into 2 buckets
    > row format delimited fields terminated by ',';

修改表

增加分割槽

alter table student add partition(stat_date='20190613') partition(stat_date='20190614');

alter table student add partition(stat_date='20190615') location '/user/hive/warehouse/student';

刪除分割槽

alter table student drop partition(stat_date='20190613');

建立的分割槽會在hdfs對應的路徑上建立資料夾

==如果增加的分割槽帶了路徑,那麼不會在hdfs的路徑上顯示對應的資料夾==

顯示錶分割槽

show partitions student;

重命名錶

alter table student rename to students;

增加列

alter table students add columns(name1 string);

==增加的列會在所有列後面,在partition列前面==

替換所有列

alter table students replace columns(id int,age int,name string);

顯示命令

#查看錶
show tables 
#檢視資料庫
show databases
#檢視分割槽
show partitions table_name
#檢視方法
show functions
#顯示錶詳細資訊
desc extended table_name
#格式話表資訊
desc formatted table_name

載入資料

使用load data操作 hive會將檔案複製到表對應的hdfs資料夾下

載入本地資料

load data local inpath "students1.txt" [overwrite] into table students partition(stat_date="20190614");

加上overwrite會講原有對應分割槽的資料清除。
如果目標表(分割槽)已經有一個檔案,並且檔名和filepath中的檔名衝突,那麼現有的檔案會被新檔案所替代。

匯出資料

儲存select查詢結果的幾種方式:

1、將查詢結果儲存到一張新的hive表中

create table t_tmp
as
select * from t_p;

2、將查詢結果儲存到一張已經存在的hive表中

insert into  table t_tmp
select * from t_p;

3、將查詢結果儲存到指定的檔案目錄(可以是本地,也可以是hdfs)

insert overwrite local directory '/home/hadoop/test'
select * from t_p;

insert overwrite directory '/aaa/test'
select * from t_p;

分桶示例

插入分桶表的資料需要是已經分好桶的,建立分桶的表並不會自動幫我們進行分桶。

#設定變數,設定分桶為true, 設定reduce數量是分桶的數量個數
set mapreduce.job.reduces=2;
# 或者選擇以下方式
set hive.enforce.bucketing = true;

# 向分桶表中插入資料
insert into student partition(stat_date='20190614')
select id,age,name from tmp_stu where stat_date='20190614' cluster by(id);

可見在hdfs上根據id分成了兩個桶

讓我們看看其中一個桶的內容

注意:
==1.order by 會對輸入做全域性排序,因此只有一個reducer,會導致當輸入規模較大時,需要較長的計算時間。==

==2.sort by不是全域性排序,它是在資料進去reduce task時有序。因此,如果用sort by進行排序,並且設定mapreduce.job.reduces>1,則sort by只保證每個reduce task的輸出有序,不保證全域性有序。==

==3.distribute by根據distribute by指定的內容將資料分到同一個reducer==

==4.cluster by除了具有distribute by的功能外,還會對該欄位進行排序。因此我們可以這麼認為cluster by=distribute by + sort by==

==但是cluster by只能指定同一欄位,當我們要對某一欄位進行分桶,又要對另一欄位進行排序時,用distribute by + sort by更加靈活。==

==分桶表的作用:最大的作用是用來提高join操作的效率;==

思考:select a.id,a.name,b.addr from a join b on a.id=b.id;
如果a表和b表已經是分桶表,而且分桶的欄位是id欄位。做這個join操作時,還需要全表做笛卡爾積嗎?(文末給出答案)

分桶原理

資料分桶的原理:
跟MR中的HashPartitioner的原理一模一樣
MR中:按照key的hash值去模除以reductTask的個數
Hive中:按照分桶欄位的hash值去模除以分桶的個數
Hive也是 針對某一列進行桶的組織。Hive採用對列值雜湊,然後除以桶的個數求餘的方式決定該條記錄存放在哪個桶當中。

資料分桶的作用

好處:
1、方便抽樣
2、提高join查詢效率

如何將資料插入分桶表

將資料匯入分桶表主要通過以下步驟

第一步:

從hdfs或本地磁碟中load資料,匯入中間表(也就是上文用到的tmp_stu)

第二步:

通過從中間表查詢的方式的完成資料匯入

分桶的實質就是對 分桶的欄位做了hash 然後存放到對應檔案中,所以說如果原有資料沒有按key hash ,需要在插入分桶的時候hash, 也就是說向分桶表中插入資料的時候必然要執行一次MAPREDUCE,這也就是分桶表的資料基本只能通過從結果集查詢插入的方式進行匯入

==我們需要確保reduce 的數量與表中的bucket 數量一致,為此有兩種做法==

1.讓hive強制分桶,自動按照分桶表的bucket 進行分桶。(推薦)
set hive.enforce.bucketing = true;

2.手動指定reduce數量
set mapreduce.job.reduces = num;
/
set mapreduce.reduce.tasks = num;
並在 SELECT 後增加CLUSTER BY 語句
    
    覺得不錯記得給我點贊加關注喔~
    公眾號:喜訊XiCent