3. Framework Clients
---
在更直接的網關客戶端之後,現在要討論第二類客戶端,將它們統稱爲框架(framework)。這類客戶端提供了更高級的抽象,一般使用 domain specific
language (DSL) 的形式。包括,例如 SQL, 關係數據庫系統與外部客戶端的混合用語(lingua franca),以及 MapReduce, 原始的處理框架,用於編寫和執行
長時間運行的批處理作業。
3.1 MapReduce
-----------------------------------------------------------------------------------------------------------------------------------------
Hadoop MapReduce framework 構建用於處理 PB 級的數據,以穩定的,確定性的,容易編程的方式處理數據。有很多種方式將 HBase 作爲 MapReduce 作業
的源和目標(as a source and target for MapReduce jobs)。
■ Native Java
-----------------------------------------------------------------------------------------------------------------------------------------
HBase 基於 Java 的 MapReduce API 在單獨的章節中論述。
3.2 Hive
-----------------------------------------------------------------------------------------------------------------------------------------
Apache Hive 項目是在 Hadoop 之上提供的數據倉庫基礎設施。最初由 Facebook 開發,但現在作爲開源 Hadoop 生態系統的一部分。Hive 可以用於運行對
HBase 表的結構化查詢。
■ 介紹 (Introduction)
-----------------------------------------------------------------------------------------------------------------------------------------
Hive 提供了類 SQL 的查詢語言(SQL-like query language), 稱爲 HiveQL, 允許查詢存儲在 Hadoop 中的半結構化數據。查詢最終轉換成一個處理作業,
傳統上爲 MapReduce 作業,在本地執行或者在分佈式的集羣上執行。數據在作業執行的時候解析,並且 Hive 還利用了一個存儲處理器抽象層(storage
handler abstraction layer), 這樣數據不僅僅可以存在於 HDFS, 也可以爲其它數據源。存儲處理器透明地使任意存儲信息對基於 HiveQL 的用戶查詢可用。
從 0.6.0 版,Hive 提供了 HBase 的處理器。用戶可以定義將 Hive 表存儲爲 HBase 表或快照,在兩者之間映射列。
安裝完 Hive 之後,需要編輯配置文件以使 Hive 能夠訪問 HBase 的 JAR 文件,以及相關配置。修改 $HIVE_CONF_DIR/hive-env.sh 文件來包含如下行,使
用適用於自己的安裝路徑:
# Set HADOOP_HOME to point to a specific hadoop install directory
HADOOP_HOME=/opt/hadoop
HBASE_HOME=/opt/hbase
# Hive Configuration Directory can be controlled by:
# export HIVE_CONF_DIR=
export HIVE_CONF_DIR=/etc/opt/hive/conf
export HIVE_LOG_DIR=/var/opt/hive/log
# Folder containing extra libraries required for hive compilation/execution
# can be controlled by:
export HIVE_AUX_JARS_PATH=/usr/share/java/mysql-connectorjava.jar: $HBASE_HOME/lib/hbase-client-1.1.0.jar
Hive 安裝的一個重要部分是配置元數據數據庫,由 hive-site.xml 配置文件設置:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<configuration>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://master-2.internal.larsgeorge.com/metastore_db</value>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>dbuser</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>dbuser</value>
</property>
<property>
<name>datanucleus.autoCreateSchema</name>
<value>false</value>
</property>
<property>
<name>hive.mapred.reduce.tasks.speculative.execution</name>
<value>false</value>
</property>
</configuration>
還需要一些工作 Hive 纔可以工作,包括倉庫的創建,HDFS 中臨時工作目錄創建等等。外部客戶端訪問Hive 只需要Hive Metastore 服務器和 Hive 服務器
■ 映射託管的表 (Mapping Managed Tables)
-----------------------------------------------------------------------------------------------------------------------------------------
一旦 Hive 安裝完並可以使用了,就可以使用 HBase 處理器(handler). 首先,啓動 Hive 命令行接口,創建一個原生 Hive table, 然後插入數據:
$ hive
...
hive> CREATE TABLE pokes (foo INT, bar STRING);
OK
Time taken: 1.835 seconds
hive> LOAD DATA LOCAL INPATH '/opt/hive/examples/files/kv1.txt' OVERWRITE INTO TABLE pokes;
Loading data to table default.pokes
Table default.pokes stats: [numFiles=1, numRows=0, totalSize=5812, rawDataSize=0]
OK
Time taken: 2.695 seconds
例子中使用了 pokes 示例表,其中有兩個列 foo 和 bar. 載入的數據作爲 Hive 安裝包的一部分提供,每行包含一個 key 和 value 字段,由 Ctrl-A ASCII
控制代碼(十六進制數字 0x01)分隔,這是 Hive 的默認分隔符:
$ head /opt/hive/examples/files/kv1.txt | cat -v
238^Aval_238
86^Aval_86
311^Aval_311
27^Aval_27
165^Aval_165
409^Aval_409
255^Aval_255
278^Aval_278
98^Aval_98
484^Aval_484
下一步創建一個 HBase-backed 的表:
hive> CREATE TABLE hbase_table_1(key int, value string) \
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' \
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,cf1:val") \
TBLPROPERTIES ("hbase.table.name" = "hbase_table_1");
OK
Time taken: 2.369 seconds
上面的 DDL 語句創建並映射了一個 HBase 表,通過 TBLPROPERTIES 和 SERDEPROPERTIES 參數定義,使用提供的 HBase 處理器,Hive表爲 hbase_table_1
hbase.columns.mapping 屬性有一個特性,通過 ":key" 到 HBase row key 映射列。
在表屬性中的 hbase.table.name 是可選的,並且只有在 Hive 和 HBase 中使用不同的表的名稱時才需要。例子中使用了相同的名稱,因而可以忽略。例如
將 Hive 的 hbase_table_1 映射到一個 HBase 名爲 warehouse:table1 的表,即將表放到 warehouse 的名稱空間下。
從前面填充的 pokes Hive 表中裝載數據:根據映射,這會將 pokes.foo 的值保存爲行鍵,並且 pokes.bar 的數據保存到列 cf1:val 中:
hive> INSERT OVERWRITE TABLE hbase_table_1 SELECT * FROM pokes;
Query ID = larsgeorge_20150704102808_6172915c-2053-473b-9554-c9ea972e0634
Total jobs = 1
Launching Job 1 out of 1
Number of reduce tasks is set to 0 since there's no reduce operator
Starting Job = job_1433933860552_0036, Tracking URL = \
http://master-1.internal.larsgeorge.com:8088/ \
proxy/application_1433933860552_0036/
Kill Command = /opt/hadoop/bin/hadoop job -kill
job_1433933860552_0036
Hadoop job information for Stage-0: number of mappers: 1; \
number of reducers: 0
2015-07-04 10:28:23,743 Stage-0 map = 0%, reduce = 0%
2015-07-04 10:28:34,377 Stage-0 map = 100%, reduce = 0%, \
Cumulative CPU 3.43 sec
MapReduce Total cumulative CPU time: 3 seconds 430 msec
Ended Job = job_1433933860552_0036
MapReduce Jobs Launched:
Stage-Stage-0: Map: 1 Cumulative CPU: 3.43 sec \
HDFS Read: 15942 HDFS Write: 0 SUCCESS
Total MapReduce CPU Time Spent: 3 seconds 430 msec
OK
Time taken: 27.153 seconds
示例中啓動了 MapReduce 作業,將數據從基於 HDFS 的 Hive table 拷貝到 HBase-backed 的表中。
下面的命令獲取 pokes 和 hbase_table_1 表中數據的行數:
hive> SELECT COUNT(*) FROM pokes;
Query ID =larsgeorge_20150705121407_ddc2ddfa-8cd6-4819-9460-5a88fdcf2639
Total jobs = 1
Launching Job 1 out of 1
Number of reduce tasks determined at compile time: 1
In order to change the average load for a reducer (in bytes):
set hive.exec.reducers.bytes.per.reducer=<number>
In order to limit the maximum number of reducers:
set hive.exec.reducers.max=<number>
In order to set a constant number of reducers:
set mapreduce.job.reduces=<number>
Starting Job = job_1433933860552_0045, Tracking URL = \
http://master-1.internal.larsgeorge.com:8088/proxy/ \
application_1433933860552_0045/
Kill Command = /opt/hadoop/bin/hadoop job -kill
job_1433933860552_0045
Hadoop job information for Stage-1: number of mappers: 1; \
number of reducers: 1
2015-07-05 12:14:21,938 Stage-1 map = 0%, reduce = 0%
2015-07-05 12:14:30,443 Stage-1 map = 100%, reduce = 0%, \
Cumulative CPU 2.08 sec
2015-07-05 12:14:40,017 Stage-1 map = 100%, reduce = 100%, \
Cumulative CPU 4.23 sec
MapReduce Total cumulative CPU time: 4 seconds 230 msec
Ended Job = job_1433933860552_0045
MapReduce Jobs Launched:
Stage-Stage-1: Map: 1 Reduce: 1 Cumulative CPU: 4.23 sec \
HDFS Read: 12376 HDFS Write: 4 SUCCESS
Total MapReduce CPU Time Spent: 4 seconds 230 msec
OK
500
Time taken: 33.268 seconds, Fetched: 1 row(s)
--------------------------------------------------------------
hive> SELECT COUNT(*) FROM hbase_table_1;
...
OK
309
Time taken: 46.218 seconds, Fetched: 1 row(s)
兩個表的行數實際上是不同的,差了 100 多行, HBase-backed 表比較短,這是因爲,在 HBase 中,不能有兩個相同的行鍵,因此在拷貝時,每一行,就是
在原表的 pokes.foo 列中相同值,保存到同一行。這與在原表中執行 SELECT DISTINCT 效果是一樣的。
hive> SELECT COUNT(DISTINCT foo) FROM pokes;
...
OK
309
Time taken: 30.512 seconds, Fetched: 1 row(s)
最後,刪除這兩個表,這也會刪除底層的 HBase 表:
hive> DROP TABLE pokes;
OK
Time taken: 0.85 seconds
hive> DROP TABLE hbase_table_1;
OK
Time taken: 3.132 seconds
hive> EXIT;
■ 映射已有的表 (Mapping Existing Tables)
-----------------------------------------------------------------------------------------------------------------------------------------
可以將已有的表映射到 Hive, 甚至可以將表映射爲多個 Hive 表。這在有非常不同的列族時,並進行分別查詢時非常有用。這會大幅度提高查詢性能,因其
內部使用 Scan, 只選擇映射的列族。如果有很稀疏的列族,會在磁盤上只掃描非常小的文件,相反,運行一個作業必須掃描所有的數據才能過濾出稀疏數據
另一個映射非託管的,已存在的 HBase 表到 Hive 的原因是調整表屬性的能力。例如,創建一個 Hive table 底層爲一個 託管的 HBase table, 使用一個
非直接的表名映射,並且後續使用 HBase shell 的 describe 命令來打印出表屬性:
hive> CREATE TABLE dwitems(key int, value string) \
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' \
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,cf1:val") \
TBLPROPERTIES ("hbase.table.name" = "warehouse:items");
OK
Time taken: 1.961 seconds
hbase(main):001:0> describe 'warehouse:items'
Table warehouse:items is ENABLED
warehouse:items
COLUMN FAMILIES DESCRIPTION
{NAME => 'cf1', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER =>
'ROW', \
REPLICATION_SCOPE => '0', VERSIONS => '1', COMPRESSION =>
'NONE', \
MIN_VERSIONS => '0', TTL => 'FOREVER', KEEP_DELETED_CELLS =>
'FALSE', \
BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}
1 row(s) in 0.2520 seconds
託管的表使用集羣範圍的配置提供的屬性,從 Hive 命令行沒有能力覆蓋任何屬性。這在實踐中時非常受限的,因此通常先在 HBase shell 上創建表,然後
作爲一個外部表映射到 Hive 中。這要求 Hive 的 EXTERNAL 關鍵字,它也被用在其他地方,用於訪問存儲在非託管的 Hive 表中的數據,也就是不在 Hive
控制之下的數據。
下面的示例在 HBase 中創建名稱空間和表,然後映射到 Hive 中:
hbase(main):002:0> create_namespace 'salesdw'
0 row(s) in 0.0700 seconds
hbase(main):003:0> create 'salesdw:itemdescs', { NAME => 'meta',
VERSIONS => 5, \
COMPRESSION => 'Snappy', BLOCKSIZE => 8192 }, { NAME => 'data', \
COMPRESSION => 'GZ', BLOCKSIZE => 262144, BLOCKCACHE => 'false' }
0 row(s) in 1.3590 seconds
=> Hbase::Table - salesdw:itemdescs
hbase(main):004:0> describe 'salesdw:itemdescs'
Table salesdw:itemdescs is ENABLED
salesdw:itemdescs
COLUMN FAMILIES DESCRIPTION
{NAME => 'data', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER =>
'ROW', \
REPLICATION_SCOPE => '0', VERSIONS => '1', COMPRESSION => 'GZ', \
MIN_VERSIONS => '0', TTL => 'FOREVER', KEEP_DELETED_CELLS =>
'FALSE', \
BLOCKSIZE => '262144', IN_MEMORY => 'false', BLOCKCACHE =>
'false'}
{NAME => 'meta', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER =>
'ROW', \
REPLICATION_SCOPE => '0', VERSIONS => '5', COMPRESSION => 'SNAPPY',
\
MIN_VERSIONS => '0', TTL => 'FOREVER', KEEP_DELETED_CELLS =>
'FALSE', \
BLOCKSIZE => '8192', IN_MEMORY => 'false', BLOCKCACHE => 'true'}
2 row(s) in 0.0440 seconds
-----------------------------------------------------------------------------------------
hive> CREATE EXTERNAL TABLE salesdwitemdescs(id string, title string, createdate string)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key, meta:title, meta:date")
TBLPROPERTIES("hbase.table.name" = "salesdw:itemdescs");
OK
Time taken: 0.33 seconds
示例中, HBase table 設置了幾個屬性,例如,壓縮類型和使用的塊大小,這基於這樣的假設,meta 列族要包含非常小的列,而 data 列族要保存比較大塊
的數據。
使用 HBase shell 插入一些隨機數據:
hbase(main):003:0> require 'date';
import java.lang.Long
import org.apache.hadoop.hbase.util.Bytes
def randomKey
rowKey = Long.new(rand * 100000).to_s
cdate = (Time.local(2011, 1,1) + rand * (Time.now.to_f - \
Time.local(2011, 1, 1).to_f)).to_i.to_s
recId = (rand * 10).to_i.to_s
rowKey + "|" + cdate + "|" + recId
end
1000.times do
put 'salesdw:itemdescs', randomKey, 'meta:title', \
('a'..'z').to_a.shuffle[0,16].join
end
0 row(s) in 0.0150 seconds
0 row(s) in 0.0070 seconds
...
0 row(s) in 0.0070 seconds
=> 1000
hbase(main):004:0> scan 'salesdw:itemdescs'
...
73240|1340109585|0 column=meta:title, timestamp=1436194770461,
value=owadqizytesfxjpk
7331|1320411151|5 column=meta:title, timestamp=1436194770291,
value=ygskbquxrhfpjdzl
73361|1333773850|1 column=meta:title, timestamp=1436194771546,
value=xvwpahoderlmkzyc
733|1322342049|7 column=meta:title, timestamp=1436194768921,
value=lxbewcargdkzhqnf
73504|1374527239|8 column=meta:title, timestamp=1436194773800,
value=knweopyzcfjmbxag
73562|1294318375|0 column=meta:title, timestamp=1436194770200,
value=cdhorqwgpatjvykx
73695|1415147780|1 column=meta:title, timestamp=1436194772545,
value=hjevgfwtscoiqxbm
73862|1358685650|7 column=meta:title, timestamp=1436194773488,
value=fephuajtyxsbcikn
73943|1324759091|0 column=meta:title, timestamp=1436194773597,
value=gvdentsxayhfrpoj
7400|1369244556|8 column=meta:title, timestamp=1436194774953,
value=hacgrvwbnfsieopy
74024|1363079462|3 column=meta:title, timestamp=1436194775155,
value=qsfjpabywuovmnrt...
現在可以在 Hive 端查詢這個表:
hive> SELECT * FROM salesdwitemdescs LIMIT 5;
hive> select * from salesdwitemdescs limit 5;
OK
10106|1415138651|1 wbnajpegdfiouzrk NULL
10169|1429568580|9 nwlujxsyvperhqac NULL
1023|1397904134|5 srcbzdyavlemoptq NULL
10512|1419127826|0 xnyctsefodmzgaju NULL
10625|1435864853|2 ysqovchlzwptibru NULL
Time taken: 0.239 seconds, Fetched: 5 row(s)
最後,在 Hive 中刪除該表,外部表不會被刪除。只是將有關表的元數據信息刪除。
高級列映射特性 (Advanced Column Mapping Features)
-----------------------------------------------------------------------------------------------------------------------------------------
可以將 HBase 列直接映射爲一個 Hive 列,或者將整個 HBase 列族映射爲一個Hive MAP 類型。如果事先不知道 HBase 列限定符,這是非常有用的方法:
映射整個列族,然後在 Hive 查詢(query)中迭代列族中的列。
Hive 存儲處理器(storage handlers) 對於高級應用層的工作是透明的,因此也可以使用任何 Hive 提供的用戶定義函數(user-defined function, UDF),
或者自己的自定義函數。
■ 映射已存在的快照 (Mapping Existing Snapshots)
-----------------------------------------------------------------------------------------------------------------------------------------
在映射已存在 HBase 表到 Hive 的基礎上,也可以使用 HBase 快照映射。和使用表映射做法相同,先定義一個 HBase 表的表模式(table schema). 通過
hbase.table.name 屬性設置表名稱。當執行一個查詢時,從命名的表中讀取。對於從快照上讀取,也必須在執行查詢之前設置其名稱,使用屬性:
hive.hbase.snapshot.name。 例如,首先爲之前創建的 warehouse:itemdescs 表創建快照,然後向其添加 1000 行,使其總行數爲 2000:
hbase(main):005:0> snapshot 'salesdw:itemdescs', 'itemdescs-snap1'
0 row(s) in 0.7180 seconds
hbase(main):006:0> 1000.times do
put 'salesdw:itemdescs', randomKey, 'meta:title', ('a'..'z').to_a.shuffle[0,16].join
end
...
0 row(s) in 0.0060 seconds
=> 1000
hbase(main):007:0> count 'salesdw:itemdescs'
Current count: 1000, row: 55291|1419780087|4
Current count: 2000, row: 999|1358386653|5
2000 row(s) in 0.6280 seconds
=> 2000
假定快照 itemdescs-snap1 有 1000 行,而活動的表有 2000 行,可以切換到 Hive CLI 確認表的行數:
hive> SELECT COUNT(*) FROM salesdwitemdescs;
...
OK
2000
Time taken: 41.224 seconds, Fetched: 1 row(s)
在能使用快照之前,必須切換到 HBase 超級用戶(super user, HDFS 中 HBase 文件的擁有者,這裏爲 hadoop), 才能讀取快照。必須退出 Hive CLI 並
設置 Hadoop 變量來指定用戶,類似如下:
$ export HADOOP_USER_NAME=hadoop
$ hive
要從一個 HBase 快照要求在 HDFS 的某個位置創建一個臨時的表結構,默認爲 /tmp, 可以在 Hive shell 中通過 hive.hbase.snapshot.restoredir 屬性
改變默認設置,以指定一個不同的位置。現在已準備好從快照而非表中查詢:
hive> SET hive.hbase.snapshot.name=itemdescs-snap1;
hive> SELECT COUNT(*) FROM salesdwitemdescs;
...
OK
1000
Time taken: 34.672 seconds, Fetched: 1 row(s)
正如所期望的,我們返回了 1000 行,與快照創建時相匹配。
3.3 Pig
-----------------------------------------------------------------------------------------------------------------------------------------
Apache Pig 項目提供了一個分析海量數據的平臺。它有自己的高級查詢語言,稱爲 Pig Latin, 使用命令式編程風格表示出涉及傳輸輸入數據到最終的輸出。
這與 Hive 的聲明式方法來模擬 SQL 語句相反。
Pig Latin 語言,與 HiveQL 相比,對於有過程式編程背景的開發者,天生具有吸引力,而且本身天生就具有強大的併發性。當它與強大的 Hadoop 和
MapReduce 框架配合使用時,可以在合理的時間幀內處理大規模的數據量。
Pig 0.7.0 版開始引入 LoadFunc/StoreFunc 類及其功能,可以使用戶從非 HDFS 的數據源載入並存儲數據,其中之一就是 HBase, 由 HBaseStorage 類實現
Pig 對 HBase 的支持包括讀取和寫入到現有的表。可以將表的列映射爲 Pig 的元組(tuple), 對於讀操作,可以將行鍵作爲第一個字段,對於寫操作,第一個
字段總是用作行鍵。
存儲也支持基本過濾,工作於行級別,並且提供了比較操作符。
Pig 安裝 (Pig Installation)
-------------------------------------------------------------------------------------------------------------------------------------
可以根據操作系統選擇安裝預編譯好的二進制包安裝。如果不可用,可以下載源碼編譯。
執行下載,解包:
$ wget http://www.apache.org/dist//pig/pig-0.8.1/pig-0.8.1.tar.gz
$ tar -xzvf pig-0.8.1.tar.gz -C /opt
$ rm pig-0.8.1.tar.gz
將 pig 腳本添加到 shell 搜索路徑,並設置 PIG_HOME 環境變量
$ export PATH=/opt/pig-0.8.1/bin:$PATH
$ export PIG_HOME=/opt/pig-0.8.1
完成後,驗證安裝是否正常工作:
$ pig -version
Apache Pig version 0.8.1
compiled May 27 2011, 14:58:51
可以使用提供的指南代碼和數據體驗 Pig 和 HBase. 必須先在 HBase shell 中創建要在 Pig 中工作的表:
hbase(main):001:0> create 'excite', 'colfam1'
啓動 Pig shell, 稱爲 Grunt, 要求 pig 腳本。對於本地測試,添加 -x local 切換開關:
$ pig -x local
grunt>
本地模式的 Pig 不使用單獨的 MapReduce 安裝,而是使用 Hadoop 自帶的 LocalJobRunner,它在與 Pig 同一進程中運行 MapReduce 作業。這種方式
適用於測試和搭建原型,但不應用於較大型的數據集。
可以選擇事先在編輯器上寫腳本,並在後續調用 pig 腳本時指定它。或者使用 Grunt, 即 Pig shell, 交互式地輸入 Pig Latin 語句。最終,語句會被解釋
爲一個或多個 MapReduce 作業,但不是所有語句都會觸發執行。另一方面,可以一行一行地定義步驟,然後調用 DUMP 或 STORE, 最終會按步驟設置作業。
Pig 指南自帶了一個由 Excite 發佈的小型數據集,其中包含了一個匿名的 user ID, 一個 timestamp, 及其站點的搜索項。首先,用戶需要將這些數據
加載到 HBase 中,通過一個簡單的轉換以生成一個組合鍵,這是強制每一個行鍵的唯一性所必須的。
grunt> raw = LOAD 'tutorial/data/excite-small.log' USING PigStorage('\t') AS (user, time, query);
T = FOREACH raw GENERATE CONCAT(CONCAT(user, '\u0000'), time), query;
grunt> STORE T INTO 'excite' USING org.apache.pig.backend.hadoop.hbase.HBaseStorage('colfam1:query');
...
2011-05-27 22:55:29,717 [main] INFO org.apache.pig.backend.hadoop.executionengine.mapReduceLayer.MapReduceLauncher - 100% complete
2011-05-27 22:55:29,717 [main] INFO org.apache.pig.tools.pigstats.
PigStats - Detected Local mode. Stats reported below may be incomplete
2011-05-27 22:55:29,718 [main] INFO org.apache.pig.tools.pigstats.
PigStats - Script Statistics:
HadoopVersion PigVersion UserId StartedAt FinishedAt
Features
0.20.2 0.8.1 larsgeorge 2011-05-27 22:55:22 2011-05-27
22:55:29 UNKNOWN
Success!
Job Stats (time in seconds):
JobId Alias Feature Outputs
job_local_0002 T,raw MAP_ONLY excite,
Input(s):
Successfully read records from: "file:///opt/pig-0.8.1/tutorial/
data/excite-small.log"
Output(s):
Successfully stored records in: "excite"
Job DAG:
job_local_0002
STORE 語句啓動一個 MapReduce 作業,從給定的日誌文件讀取數據,並將其拷貝到 HBase 表。生成複合行鍵的語句,用於之後的 STORE 語句的第一個字段,
由 user 和 time 字段組成,中間以 0 字節分隔。
訪問數據涉及到另外一個 LOAD 語句,這時使用 HBaseStorage 類:
grunt> R = LOAD 'excite' USING org.apache.pig.backend.hadoop.hbase.HBaseStorage('colfam1:query',
'-loadKey') AS (key: chararray, query: chararray);
括號中的參數定義了列到字段的映射,以及額外的選項以載入行鍵作爲在關係 R 中第一個字段。AS 部分很顯然地定義了行鍵和 colfam1:query 列轉換爲
字符數組,即 Pig 的字符串類型。默認情況下,以字節數組返回,這匹配 HBase 表的存儲方式。轉換數據類型,可用於之後對行鍵的切分。
通過轉儲 R 的內容來測試目前輸入的語句,看看前面那些語句的結果:
grunt> DUMP R;
...
Success!
...
(002BB5A52580A8ED970916150445,margaret laurence the stone angel)
(002BB5A52580A8ED970916150505,margaret laurence the stone angel)
...
行鍵,作爲元組中的第一個字段,在初始從文件中拷貝數據到 HBase 期間是連接創建的。現在可以將其切分爲兩個字段,重新創建爲原始的文本字段佈局:
grunt> S = foreach R generate FLATTEN(STRSPLIT(key, '\u0000', 2))
AS \
(user: chararray, time: long), query;
grunt> DESCRIBE S;
S: {user: chararray, time: long, query: chararray}
再次使用 DUMP, 這次使用關係 S, 顯示最終結果:
grunt> DUMP S;
(002BB5A52580A8ED,970916150445,margaret laurence the stone angel)
(002BB5A52580A8ED,970916150505,margaret laurence the stone angel)
...
到此爲止,可以通過之前代碼中替換 LOAD 和 STORE 語句,完成 Pig 指南的剩餘部分。
結束示例,輸入 QUIT 最終退出 Grunt shell:
grunt> QUIT;
3.4 Cascading
-----------------------------------------------------------------------------------------------------------------------------------------
Cascading 是 MapReduce 的替代 API, 一言以蔽之,它在執行期間使用 MapReduce, 但在開發時不必將它當做 MapReduce 來考慮創建在 Hadoop 上執行的
解決方案。
Cascading 使用的模型類似於現實世界中的管道裝置(pipe assembly), 數據源爲水龍頭(tap), 而輸出爲水槽(sink). 它們通過管道(pipe)連接在一起構成了
處理流,數據在管道中流動並在此進程中進行轉換。管道可以連接成爲更大的管道裝置,以從現有管道構成更復雜的處理管線(pipeline)。
數據流經管線(streams through the pipeline), 並且可以被切分,合併,組合,或者聯結(joined)。數據表示爲元組(tuple), 並在經由裝置時形成一個
元組流(tuple stream)。這種面向可視化的模型使得構建 MapReduce 作業更像是構建工作,抽象出實際工作的複雜性。
Cascading 從 1.0.1 版開始支持從 HBase 集羣讀寫數據,更多信息訪問 http://www.cascading.org/
下面示例展示如何將數據流入到(sink data into) HBase 集羣的過程:
示例: Using Cascading to insert data into HBase
// read data from the default filesystem
// emits two fields: "offset" and "line"
Tap source = new Hfs(new TextLine(), inputFileLhs);
// store data in a HBase cluster, accepts fields "num", "lower", and "upper"
// will automatically scope incoming fields to their proper familyname,
// "left" or "right"
Fields keyFields = new Fields("num");
String[] familyNames = {"left", "right"};
Fields[] valueFields = new Fields[] {new Fields("lower"), new Fields("upper") };
Tap hBaseTap = new HBaseTap("multitable", new HBaseScheme(keyFields, familyNames, valueFields), SinkMode.REPLACE);
// a simple pipe assembly to parse the input into fields
// a real app would likely chain multiple Pipes together for more complex
// processing
Pipe parsePipe = new Each("insert", new Fields("line"), new RegexSplitter(new Fields("num", "lower", "upper"), " "));
// "plan" a cluster executable Flow
// this connects the source Tap and hBaseTap (the sink Tap) to the parsePipe
Flow parseFlow = new FlowConnector(properties).connect(source, hBaseTap, parsePipe);
// start the flow, and block until complete
parseFlow.complete();
// open an iterator on the HBase table we stuffed data into
TupleEntryIterator iterator = parseFlow.openSink();
while(iterator.hasNext()) {
// print out each tuple from HBase
System.out.println( "iterator.next() = " + iterator.next() );
}
iterator.close();
3.5 其它客戶端 (Other Clients)
-----------------------------------------------------------------------------------------------------------------------------------------
還有其它的客戶端庫可以訪問 HBase 集羣。它們可以劃分爲直接運行在 JVM 上的,和通過網關服務器(gateway server) 與 HBase 集羣通信。下面是一些
項目:
● Clojure
-------------------------------------------------------------------------------------------------------------------------------------
HBase-Runner 項目,提供從函數式編程語言 Clojure 對 HBase 的支持。可以在 Clojure 中編寫 MapReduce 作業訪問 HBase 表。
● JRuby
-------------------------------------------------------------------------------------------------------------------------------------
HBase Shell 是使用基於 JVM 語言訪問基於 Java API 的例子。它自帶源代碼,因此可以用戶可以將相同的特性加入到自己的 JRuby 代碼中。
● HBql
-------------------------------------------------------------------------------------------------------------------------------------
HBql 在 HBase 上添加類 SQL 語法,對 HBase 唯有的特性增加了必要的擴展。
● HBase-DSL
-------------------------------------------------------------------------------------------------------------------------------------
這個項目給出了專用類用於幫助構造對 HBase 集羣的查詢。使用類構建器(builder-like)風格,可以快速組裝所有選項和必要參數。
● JPA/JPO
-------------------------------------------------------------------------------------------------------------------------------------
可以使用,比如 DataNucleus, 將一個 JPA/JPO 訪問層置於 HBase 之上。
● AsyncHBase
-------------------------------------------------------------------------------------------------------------------------------------
AsyncHBase 提供完全異步的,非阻塞的,線程安全的客戶端訪問 HBase 集羣。它使用純 RPC 協議直接與各種服務器對話。
參考:
參考:
《HBase - The Definitive Guide - 2nd Edition》Early release —— 2015.7 Lars George