HBase 客戶端類型 (二)

繼  HBase 客戶端類型 (一)

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 客戶端類型 (一)

HBase 客戶端類型 (二)

HBase 客戶端類型 (三)

HBase 客戶端類型 (四)

 

參考:

    《HBase - The Definitive Guide - 2nd Edition》Early release —— 2015.7 Lars George

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章