什麼是Hive:
建立在Hadoop之上的數據倉庫解決方案
提供類似sql的查詢語言,命名爲Hive查詢語言HQL,它有最小的學習曲線
早期的Hive開發工作於2007年在Facebook開始
Hive讓更多的人使用Hadoop
今天Hive是Hadoop下的頂級Apache項目,網址是hive.apache.org
Hive可以看成是基於Hadoop的mysql
Hive把Hadoop中的大數據文件映射成SQL數據,並通過SQL語句進行操作
Hive的優勢和特點:
提供一個比MR編碼更少的簡單優化模型
HQL和SQL具有類似的語法和高生產率
Hive支持在不同的計算框架上運行
Hive支持在HDFS和HBase上特別查詢數
Hive支持用戶定義的函數、腳本和自定義格式
用於ETL和BI工具的成熟JDBC和ODBC驅動程序
穩定可靠(可生產)進行批量加工
Hive擁有一個龐大而活躍的社區
當Hive和MapReduce同時執行WordCount時,MapReduce執行速度更快,但是項目開發時要求開發速度要快,Hive很簡潔,在實際開發中不需要配置,也不會出現maven的問題運行更便利,Hive有一個優化器,會執行最有用的代碼。
Hive元數據管理:
爲了支持模式和數據分區等特性,Hive將其元數據保存在一個關係型數據庫中,不是在Hadoop裏
默認情況下,Hive是由輕量級內嵌SQL數據庫打包的
默認的基於Derby的方法適合於評估測試
模式不是在用戶之間共享的,因爲每個用戶都有自己的嵌入式Derby實例
存儲在.metastore_db目錄中,該目錄駐留在hive啓動時所在的目錄中
可以輕鬆切換另一個SQL裝置,如MySQL,Oracle
HCatalog將Hive元數據作爲Hive的一部分公開給其他生態系統
Hive 體系架構:
Hive借鑑了很多關係型數據庫,關係型數據庫和Hive可以通用,可以進行數據遷移,但是關係型數據庫更加細緻,但是Hive功能並不是很細緻,只是針對大型數據,Hive適合批量處理數據
Metastore:關係型數據庫
Driver:核心組件,包括編譯器,優化器,查詢執行器
Hive Server2:提供JDBC或者ODBC的連接方式
Hive接口 — 命令行模式
有兩種工具:Beeline和命令行(CLI)
有兩種模式:命令行模式和交互模式
目的 |
HiveServer2 Beeline |
HiveServer1 CLI(命令行) |
服務連接 |
beeline –u <jdbcurl> -n <username> -p <password> |
hive –h <hostname> -p <port> |
幫助 |
beeline -h or beeline --help |
hive -H |
執行查詢 |
beeline -e <query in quote> beeline -f <query file name> |
hive -e <query in quote> hive -f <query file name> |
定義變量 |
beeline --hivevar key=value |
hive --hivevar key=value |
交互模式:
目的 |
HiveServer2 Beeline |
HiveServer1 CLI |
輸入方式 |
beeline |
hive |
連接 |
!connect <jdbcurl> |
N/A(不適用) |
List Tables |
!table |
show tables; |
List Columns |
!column <table_name> |
desc table_name; |
運行查詢 |
<HQL>;(一定要有分號) |
<HQL>; |
保存結果 |
!record <file_name> !record |
N/A(不適用) |
Run Shell CMD |
!sh ls |
!ls; |
Run DFS CMD |
dfs -ls |
dfs -ls ; |
Run SQL File |
!run <file_name> |
source <file_name>; |
檢查版本 |
!dbinfo |
!hive --version; |
退出模式 |
!quit |
quit; |
如果hiveserver2服務沒有啓動,應該用命令行模式訪問hive
Hive JDBC URL:
URL語法:
jdbc:hive2://zookeeper_quorum|hs2_host:port/[db][;principal=<hs2_principal>/<hs2_host>|_HOST@<KDC_REALM>][;transportMode=binary|http][;httpPath=<http_path>][;serviceDiscoveryMode=zookeeper;zooKeeperNamespace=<zk_namespace>][;ssl=true|false][;sslKeyStore=<key_store_path>][;keyStorePassword=<key_store_password][;sslTrustStore=<trust_store_path>][;trustStorePassword=<trust_store_password>][;twoWay=true|false]
一個具體項目環境的例子:
jdbc:hive2://abcnf03.devfg.xxx.com:2181/dev_xxx_hive;serviceDiscoveryMode=zooKeeper;zooKeeper Namespace=hiveserver2;principal=hive/_HOST@REALM?tez.queue.name=D_NO_SLA; hive.exec.dynamic.partition.mode=nonstrict"
虛擬機裏的URL:
jdbc:hive2://localhost:10000/default
Hive的其他使用環境:
Hive Web Interface (As part of Apache Hive)
Hue (Cloudera)
Ambari Hive View (Hortonworks)
JDBC/ODBC(ETL 工具,商業智能工具, 集成開發環境)
Informatica,Talend等等
Tableau,QlikView,Zeppelin等等
Oracle SQL Developer,DB Visualizer等等
執行Hive:
命令行連接:
Hive
beeline連接:
hiveserver2
beeline
!connect jdbc:hive2://192.168.80.109:10000
bda
123mao=MAO
hive的HiveServer2/beeline配置及使用
第一:修改 hadoop 集羣的 hdfs-site.xml 配置文件:加入一條配置信息,表示啓用 webhdfs
cd /home/hadoop/apps/hadoop-2.7.5/etc/hadoop
<property>
<name>dfs.webhdfs.enabled</name>
<value>true</value>
</property>
第二:修改 hadoop 集羣的 core-site.xml 配置文件:加入兩條配置信息:表示設置 hadoop的代理用戶
<property>
<name>hadoop.proxyuser.bda.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.bda.groups</name>
<value>*</value>
</property>
CREATE TABLE IF NOT EXISTS flowrec(
idx int,
dttm timestamp,
phn string,
upflow int,
downflow int
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE;
查看錶:describe 表名;
查看當前的數據表:select current_database();
Like創建一個相同的表,但是照抄原來表的結構,並不複製表數據
Hive數據類型:
類型 |
例子 |
類型 |
例子 |
TINYINT |
10Y |
SMALLINT |
10S |
INT |
10 |
BIGINT |
100L |
FLOAT |
1.342 |
DOUBLE |
1.234 |
DECIMAL |
3.14 |
BINARY |
1010 |
BOOLEAN |
TRUE |
STRING |
Book’ or “Book” |
CHAR |
'YES’ or “YES” |
VARCHAR |
'Book’ or “Book” |
DATE |
'2013-01-31’ |
TIMESTAMP |
'2013-01-31 00:13:00.345’ |
數據類型表達補充:
十進制小數轉化成二進制小數
十進制的小數轉換爲二進制,主要是小數部分乘以2,取整數部分依次從左往右放在小數點後,直至小數點後爲0。例如十進制的0.125,要轉換爲二進制的小數:轉換爲二進制,將小數部分0.125乘以2,得0.25,然後取整數部分0,再將小數部分0.25乘以2,得0.5,然後取整數部分0,再將小數部分0.5乘以2,得1,然後取整數部分1,則得到的二進制的結果就是0.001
小數點是浮動的叫做浮點數
0.00000000018 表示爲:18e-12
190000000 表示爲:19e7
複雜數據類型:
類型 |
例子 |
定義 |
例子 |
ARRAY |
[‘Apple’,’Orange’,’Mongo’] |
ARRAY<string> |
a[0] = ‘Apple’ |
MAP |
{‘A’:’Apple’,’O’:’Orange’} |
MAP<string, string> |
b[‘A’] = ‘Apple’ |
STRUCT |
{‘Apple’, 2} |
STRUCT<fruit:string,weight:int> |
c.weight = 2 |
ARRAY對所有元素具有相同的類型等於MAP使用從0開始的序列作爲鍵
MAP具有相同類型的鍵值對
STRUCT就像table/records(表/記錄)
大數據數據建模與數據倉庫數據建模相比較在數據類型上不需要注意太多,使得數據建模更加簡單,更關注數據類型使用的場合和作用。
Hive的元數據結構:
數據結構 |
邏輯 |
物理(HDFS) |
Database |
表的集合 |
文件夾和文件 |
Table |
數據行的集合 |
文件夾和文件 |
Partition |
要分割數據的列 |
文件夾 |
Buckets |
用於分發數據的列 |
文件 |
Row |
行記錄 |
文件行 |
Columns |
片記錄 |
每一行中指定的位置 |
Views |
數據行的快捷方式 |
不適用 |
Index |
|
文件夾和文件 |
Hive數據庫:
數據庫是用於類似目的或屬於同一組的表的集合。
如果沒有指定數據庫(使用database_name),則默認使用默認數據庫。
Hive爲/user/ Hive /warehouse中的每個數據庫創建一個目錄,可以通過hive.metastore.warehouse.dir這個目錄進行定義,除了默認數據庫。(默認數據庫表直接建立在該目錄下)
創建表:
create database if not exists myhivebook;
使用表:
use myhivebook;
顯示錶:
show databases;
描述表:
describe database default;
改變表屬性:
alter database myhivebook set owner user dayongd;
刪除表:
drop database if exists myhivebook cascade;
select current_database(); 來知道和顯示當前所在數據庫
Hive Tables:
外部表:
數據保存在由LOCATION關鍵字指定的HDFS路徑中。Hive不完全管理數據,因爲刪除表(元數據)不會刪除數據,對數據進行引入,但是不對數據進行管理,對數據有保護作用
內部表/管理表:
數據保存在默認路徑中,例如/user/hive/warehouse/employee。數據完全由Hive管理,因爲刪除表(元數據)也會刪除數據
Hive的問題:
什麼是內部表和外部表?
外部表數據保存在由LOCATION關鍵字指定的HDFS路徑中。
內部表/管理表數據保存在默認路徑中,例如/user/hive/warehouse/employee。
內部表和外部表的關鍵區別是什麼?
刪除文件角度:刪除表(元數據)不會刪除數據,刪除表(元數據)也會刪除數據
從管理角度:data的完全管理是通過內部表,外部表Data不需要管理
內部表和外部表的最佳實踐是什麼?
一些數據來源是外部,比如客戶提供的數據,或者元數據不能因爲誤操作而刪除,就使用外部表;如果有共享數據的需求,想處理數據之後,分享給其他用戶,這時不想讓其他人查看自己核心數據庫,一般使用外部表。
當進行數據轉換的時候,做數據清洗的時候,一般建立內部表;
建表語法:
CREATE EXTERNAL TABLE IF NOT EXISTS employee_external (
// IF NOT EXISTS是個選項,TEMPORARY還支持臨時表
name string,
work_place ARRAY<string>,
sex_age STRUCT<sex:string,age:int>,
skills_score MAP<string,int>,
depart_title MAP<STRING,ARRAY<STRING>>
)
//具有數據類型的列的列表,沒有約束支持
COMMENT 'This is an external table'
//表註釋是可選的
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '|'
//如何分隔列
COLLECTION ITEMS TERMINATED BY ','
MAP KEYS TERMINATED BY ':'
//分割MAP和集合
STORED AS TEXTFILE
//設置文件格式
LOCATION '/user/dayongd/employee';
// HDFS中的數據文件路徑
分隔符:
Hive中的默認分隔符:
字段分隔符: 可以使用Ctrl + A或^A(創建表時使用 \001)
收集項目分隔符:可以使用Ctrl + B或^B(\002)
map主要分隔符:可以使用Ctrl + C或^C(\003)
問題:
如果在表創建過程中重寫了分隔符,那麼它只能在平面結構JIRA Hive-365中工作。對於嵌套類型,嵌套的級別決定分隔符。
示例:
數組的數組,外層數組是^B,內層數組是^C
Map的數組,外層Map是^C,內層數組是^D
存儲序列:
SERDE:序列化和反序列化類
Serialize,Deserialize
Hive支持使用不同類型的存儲serde,以正確的格式保存文件後,存儲爲語句。
LazySimpleSerDe:TEXTFILE
BinarySerializerDeserializer:SEQUENCEFILE
ColumnarSerDe:ORC,RCFILE
ParquetHiveSerDe:PARQUET
AvroSerDe:AVRO
OpenCSVSerDe:用在CST/TSV
示例:
CREATE TABLE my_table(a string, b string, ...)
ROW FORMAT
SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
"separatorChar" = "\t",
"quoteChar" = "'",
"escapeChar" = "\\"
)
STORED AS TEXTFILE;
JSONSerDe:
CREATE TABLE my_table(a string, b bigint, ...)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
STORED AS TEXTFILE;
RegExSerDe:
ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input.regex" = "<regex>"
)
STORED AS TEXTFILE;
HBaseSerDe:
CREATE TABLE test_serde_hb(
id string,
name string,
sex string,
age string
)
ROW FORMAT SERDE'org.apache.hadoop.hive.hbase.HBaseSerDe'
STORED BY'org.apache.hadoop.hive.hbase. HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping"=":key,info:name,info:sex,info:age")
TBLPROPERTIES("hbase.table.name" = "test_serde");
查找表命令練習:
show tables; show tables '*sam*'; show tables '*sam|lily*' ;
show table extended like 'o*';
desc [formatted|extended] table_name
show create table table_name;
show columns table_name;
show tblpropertiestblname;
Hive高階建表語句(CTAS and WITH)
CTAS — Create Table As Select
CREATE TABLE ctas_employee as SELECT * FROM employee
CTAS不能創建分區、外部表或桶表
CTAS和Common Table Expression(CTE)
CTE就是CTAS加上WITH,子查詢嵌套使用Common Table Expression,把每個臨時表提前定義好,比如說定義好r2,r1的定義裏就可以引用r2,最終通過一個查詢來建立新表。
Explain CREATE TABLE cte_employee AS WITH
r1 AS (SELECT name FROM r2 WHERE name = 'Michael'),
r2 AS (SELECT name FROM employee WHERE sex_age.sex= 'Male'),
r3 AS (SELECT name FROM employee WHERE sex_age.sex= 'Female')
SELECT * FROM r1 UNION ALL SELECT * FROM r3;
Union進行表連接,將r1中的所有元素和r3中的所有元素查詢連接到一起
複製一個和其他表一樣的表(快速建表)
CREATE TABLE employee_like LIKE employee
Hive臨時表:
應用程序自動管理在複雜查詢期間生成的中間數據的一種方便方法(類似於CTE,它只有一條語句)
僅會話,自動刪除,相同的名稱在不同的會話
表空間位於/tmp/hive-<user_name>(安全考慮)
當普通表和臨時表擁有相同的名稱時,臨時表會被優先調用
CREATE TEMPORARY TABLE tmp_table_name1 (c1 string);
CREATE TEMPORARY TABLE tmp_table_name2 AS..
CREATE TEMPORARY TABLE tmp_table_name3 LIKE..
查看錶所在的位置和空間以及建表語句就知道是不是臨時表
Hive表 — Drop/Truncate/Alter Table:
DROP TABLE IF EXISTS employee語句完全刪除元數據,並在配置後將數據移動到HDFS中用戶主目錄中的.garbage文件夾中。使用PERGE選項,數據將被完全刪除。當刪除外部表時,數據不會被刪除。
TRUNCATE TABLE employee語句刪除內部表(外部表會失敗)中的所有數據行。
ALTER TABLE employee RENAME TO new_employee語句重命名錶(經常用於數據修復前的暫時備份)
ALTER TABLE c_employee SET TBLPROPERTIES ('comment'='New name, comments')語句設置TABLE屬性
ALTER TABLE employee_internal SET SERDEPROPERTIES ('field.delim' = '$ ')語句設置SerDe(序列化和反序列化)屬性,設置字符分隔符
ALTER TABLE c_employee SET FILEFORMAT RCFILE語句設置文件格式。
(alter在元數據層面進行修改,並不改變真實的數據,只是修正)
ALTER TABLE employee_internal CHANGE old_name new_name STRING [BEFORE|AFTER] sex_age這個語句可以用於更改列名、位置或類型
ALTER TABLE c_employee ADD COLUMNS (work string) 該語句在最後向表中添加另一列和類型
ALTER TABLE c_employee REPLACE COLUMNS (name string) 此語句用指定的列和類型替換表中的所有列。在本例中的ALTER之後,表中只有一列
ALTER TABLE語句只修改Hive的元數據,而不是實際的數據。用戶應確保實際數據符合元數據定義。
Hive分區概述:
分區對應的是目錄,不能從文件中找數據分區
爲了提高性能,Hive可以對數據進行分區
分區列的值將表劃分爲段(文件夾)
可以在查詢時忽略整個分區
分區必須由用戶正確創建。插入數據時必須指定分區
在查詢中使用“分區”列和常規列在模式上沒有區別
在查詢時,Hive將自動過濾掉沒有用於提高性能的分區
分區的定義和操作:
CREATE TABLE employee_partitioned(
name string,
work_place ARRAY<string>,
sex_age STRUCT<sex:string,age:int>,
skills_score MAP<string,int>,
depart_title MAP<STRING,ARRAY<STRING>>
)
PARTITIONED BY (Year INT, Month INT)
(分區鍵不能和任何列重名)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '|'
COLLECTION ITEMS TERMINATED BY ','
MAP KEYS TERMINATED BY ':';
Hive建立靜態分區:
靜態分區不是自動啓用的。我們必須通過ALTER TABLE語句添加/刪除分區
alter table employee_p add
partition (year=2017, month=4)
partition (year=2017, month=5);
顯示分區信息:show partitions employee_p;
刪除分區:alter table employee_p drop partition (year=2107, month=4);
Hive建立動態分區:
Hive還支持動態地提供分區值。當數據量很大而我們不知道分區值是多少時,這是非常有用的。
默認情況下,用戶必須指定至少一個靜態分區列。這是爲了避免意外地覆蓋分區。要禁用此限制,可以將分區模式從默認嚴格模式設置爲nonstrict
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
insert into table employee_p partition(year, month)
select
name,
array('Toronto') as work_place,
named_struct("sex","male","age",30) as sex_age,
map("python",90) as skills_score,
map("r&d", array('developer')) as depart_title,
year(start_date) as year,
month(start_date) as month
from employee_hr eh
where eh.empployee_id = 102;
動態分區是動態寫入,通常用在數據轉換和重新組織數據時使用;靜態分區一般用在數據加載的時候,每次加載一個新數據就建立一個靜態分區,進行數據的重新組合
Hive分桶概述:
分桶需要語句寫入,分桶之後動態加載,不能靜態加載,只能加載數據之後分桶。
bucket對應於HDFS中的文件段
隨機採樣數據或加速連接的機制
基於哈希函數將數據分解爲一組桶的“桶列”
Hive不會自動執行嵌套。要求設置強制裝桶:SET hive.enforce.bucketing = true;
bucket列的選擇與業務邏輯密切相關
爲了定義桶的數量,應該避免每個桶中有太多或太少的數據。更好的選擇是接近兩個數據塊的地方。使用2N作爲桶的數量
(兩個數據塊的大小是Hadoop HDFS中的默認塊大小)
Hive分桶建表語句:
使用CLUSTERED BY語句來定義bucket
與分區不同,分桶列名出現在列定義
支持多個列
要將數據填充到桶中,我們必須使用INSERT語句而不是LOAD語句,因爲它不能根據元數據定義驗證數據(僅將文件複製到文件夾中)
bucket是文件段的列表
CREATE TABLE employee_id_buckets(
name string,
employee_id int,
work_place ARRAY<string>,
sex_age STRUCT<sex:string,age:int>,
skills_score MAP<string,int>,
depart_title MAP<STRING,ARRAY<STRING>> )
CLUSTERED BY (employee_id) INTO 2 BUCKETS
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '|'
COLLECTION ITEMS TERMINATED BY ','
MAP KEYS TERMINATED BY ':';
分桶抽樣:
隨機抽樣基於整行數據:
SELECT * FROM table_name TABLESAMPLE(BUCKET 3 OUT OF 32 ON rand()) s;
隨機抽樣基於指定列(使用分桶列更高效):
SELECT * FROM table_name TABLESAMPLE(BUCKET 3 OUT OF 32 ON id) s;
y必須是table總bucket數的倍數或者因子。hive根據y的大小,決定抽樣的比例。例如,table總共分了4份,當y=2時,抽取(4/2=)2個bucket的數據,當y=8時,抽取(4/8=)1/2個bucket的數據。
x表示從哪個bucket開始抽取,如果需要取多個分區,以後的分區號爲當前分區號加上y。例如,table總bucket數爲4,tablesample(bucket 1 out of 2),表示總共抽取(4/2=)2個bucket的數據,抽取第1(x)個和第3(x+y)個bucket的數據。
注意:x的值必須小於等於y的值,否則
FAILED: SemanticException [Error 10061]: Numerator should not be bigger than denominator in sample clause for table stu_buck
如果y不是table總bucket數的倍數或者因子。就會取出數據中y的倍數
隨機抽樣基於block size:
SELECT * FROM table_name TABLESAMPLE(10 PERCENT) s;
SELECT * FROM table_name TABLESAMPLE(1M) s;
SELECT * FROM table_name TABLESAMPLE(10 rows) s;
使用分桶可以提高數據關聯,提高join的性能,幫助抽樣