2012年12月24日 星期一

Hbase 進階使用方式

HBase有兩個基本的key結構, 一個是row key另一個是column key, 以下來看看如何靈活的運用這兩套key來解決一些常見的實務問題.

重要觀念回顧

邏輯配置不同於實體配置, 由於人類的大腦辨識2維資料強過辨識多維資料, 因此, 在設計資料庫這種複雜的關係時, 就習慣用[表]來顯示. 所以不管是關聯式資料庫還是HBase這種欄導向的資料庫, 在設計時都會畫張表出來. 在設計資料庫系統時, 也都有表的概念. 但是雖然看起來都是表, 這兩種資料庫在實際儲存資料時其實是採用完全不同的方法.

在此我粗略的把以下幾個關鍵字視為邏輯配置的關鍵字

  • Table
  • Row
  • Column Family
  • Column Qualifier

把以下幾個字視為實體配置時的關鍵字

  • Region
  • Region Server
  • Cluster

請注意, 這裡的邏輯配置和實體配置的說法是為了方便理解, 並不嚴謹.

HBase的資料表邏輯配置 

      「HBase在邏輯配置上的主要切割單位是Column Family」,這句話是說, HBase在儲存資料時, 會以Column Family為單位儲存, 不同Column Family儲存在不同的檔案中.
以下圖為例, 這張資料表中有兩個 column family 1(cf1與cf2)之中各有兩個column qualify(c1與c2),
HBase在進行儲存時, 會把cf1:c1和cf1:c2合併成一個檔案, 把cf2:c1和cf2:c2合併成一個檔案, 這裡這個合併的動作稱為folded(中文書譯做「拌入」, 我覺得稱作「檔案化」比較貼切).
      上面提到的cf1:c1是由column family:column qualify的組合, 這個組合就是HBase中的Column key.

「列」是以實際儲存單元(actual cell)的線性集合(linear set)來儲存
引用自:HBase The Definitive Guide 



比較高窄型資料表與扁平型資料表

      在處理資料如何儲存與存到哪裡的問題時, 有兩種選擇. 高窄型(tall-narrow)平寬型(flat-wide).高窄型的資料表有少量的行, 但有許多的列, 平寬型則正好相反.
      由於HBase只可以在列的邊界上做分割, 因此強烈建議使用高窄型資料表.
      舉電子郵件為例, 我們可以這樣設計:一個列裡存放一位使用者的所有郵件(row key為user id). 這樣會發生, 少數的使用者有超級多的電子郵件, 而令單一列有可能超過region所限制的最大檔案空間, 且面臨region的分割處理工作.
      想像一下比較好的處理方式是, 每一個單獨的列上, 改成存單一電子郵件, 也就是將row key 換成user id與message id的組合. 這樣一來就可以輕巧的避免掉上述的問題.

局部Key掃描(partial key scans)

      HBase的掃描(scan)功能和HTable為主的用戶端API, 對於將資料表轉換成高窄型而不喪失查詢的細緻度上, 提供了partial key scans的重要功能.
在上一段提到的電子郵件例子裡, 當我們把資料表透過row key的組合轉換成高窄型資料表時, 我們會得到一串由許多key組合而成的row key, 例如 <userid>-<msgid>-<attachid>, 而局部Key掃描讓我們可以設定, 要掃描row key中的哪些Key. 透過局部key掃描一方面可以提昇查詢的精準度, 一方面又可以減少不必要的查詢時間, 非常方便使用.


輔助索引

雖然HBase原來沒有支援輔助索引, 但還是有一些狀況會需要用到. 這些狀況通常是這樣:row key, column family, column qualify...這些主要的資料定位資訊不夠用, 這時候就會需要用到輔助索引. 這時可能的解決方案入下:

讓客戶端來管理
將索引功能直接轉移到應用程式層來處理.

索引交易
使用開放原碼專案 ITHBase. 這個專案擴充了 HBase的功能, 在客戶端與主機端的類別上加了一些特殊的實作. 核心的擴充是加入了交易機制, 用於確保所有輔助索引的更新是一致的。並藉由提供一個客戶端的IndexdTableDescriptor來增加對索引的支援, 定義了一個資料表背後的輔助索引運作方式.

索引式 HBase
類似ITHBase專案, 這裡也以採用IHBase(Indexed HBase). 此解決方案不使用獨立的資料表來儲存每個索引, 而是直接在記憶體中維護他們.

2012年12月13日 星期四

在 Arch Linux 建構 python 自然語言處理環境

自然語言處理好像很有趣, 紀錄一下安裝過程。
如果還沒安裝python的話要先安裝起來, 目前nltk(Natural Language Toolkit)主要版本支援的是python2。

sudo pacman -S python2

已經安裝過python的話可以使用 python -V 查看運行的版本號。
確定python安裝無誤就可以開始安裝nltk(Natural Language Toolkit)

sudo pacman -S python2-nltk

因為我的主機裡面, 安裝了 pyhon3.3 和 python2.7, 所以我必須指定使用的python版本號.

python2.7

這樣就可以進入python的shell








要做接下來的範例, 首先要先下載測試的文件, 我們下載幾本書下來分析。
先在python shell中載入nltk模組
import nltk
然後進入nltk提供的下載界面,把其中的book下載下來。
nltk.download()



















下載完之後載入這包book資料
from nltk.book import *
















接下來就可以做一些簡單的測試,
text1是白鯨記, 我們來看看白鯨記總共有多少個字

len(text1)






再來跑一個有趣的練習, 用白鯨記的詞產生50字的隨機文章,

text1.generate(50)








先介紹到這邊, 有機會在深入研究。

延伸閱讀:
http://rritw.com/a/bianchengyuyan/Python/20101004/47354.html

2012年12月10日 星期一

在 Windows 環境下安裝 APC 教學


整個安裝過程分為兩個部份, 安裝php延伸, 安裝web圖形界面 
  1. 下載php延伸, php_apc.dll,
    php5.2請下載php_apc-3.1.5-5.2-vc9-x86.zip
    php5.3請下載php_apc-3.1.5-5.3-vc9-x86.zip
    載點,http://downloads.php.net/pierre/
  2. 下載後解壓縮到appserv/php5/ext,
    注意, 請使用ts這個資料夾中的php_apc.dll, 在78.33用nts的過不了, 我還不知道原因
  1. 設定php.ini, 將以下code貼到php.ini最後
    [PECL]
    extension=php_apc.dll
    [apc]
    apc.shm_segments = 1
    apc.shm_size = 128M
    apc.ttl = 7200
    apc.user_ttl = 7200
    apc.num_files_hint = 1024
    apc.enable_cli = 1
    apc.rfc1867 = 1
  2. 重開apache
  3. 開瀏覽器到<主機網址>/phpinfo,去確認apc是否安裝成功,
    直接用ctrl+f搜尋, 只要搜不到apc關鍵字, 就是安裝失敗, 請回頭檢查每個步驟
  1. 安裝圖形界面(安裝方式類似drupal, 而且不用設定資料庫)
  2. 下載圖形界面專案
    載點http://pecl.php.net/package/APC
  3. 解壓縮之後放在www裡面, 將資料夾改名, apc.x.xx.xx --> APC (或任何想要的名字, 以下以命名為apc為例)
  4. 以瀏覽器開啟<主機網址>/apc/install, 就會自動開始安裝
  5. 設定apc管理密碼
    1. 開啟apc.php, 找到設定帳號密碼的地方把帳號密碼改掉.
    2. 沒有改掉帳密的話, 會無法登入apc圖形界面,(登入圖形化界面才能用圖協界面清除apc快取)
  6. 安裝完畢後, 就可以在<主機網址>/apc/apc.php看到圖形界面並開始使用.

清空apc快取的方式
  1. 登入apc-->  <網址>apc/apc.php, 例, http://<你的網址>/apc/apc.php
  2. 按右上角的login登入, 不知道帳號密碼的話, 帳密在apc.php這個檔案裡
  3. 登入後在畫面logout的下方會看到clear opcode chache的按鈕, 按下去就可以清空快取(如下圖)

2012年12月9日 星期日

HBase 新手常見問題與客戶端API


  1. Hbase 是甚麼
    Hbase 是 Apache Hadoop 的資料庫, 能夠對大型資料提供隨機、即時的讀寫存取. 目前已經是Apache眾多開放原始碼項目中的一個頂級專案.[HBase 實戰技術手冊]

    是用Java語言編寫的一個開源的、高可靠性、高性能、可伸縮、非關聯式的資料庫,用以存儲大規模結構化數據。
     
  2. HBase 用在哪裡
    HBase 的目標是儲存並處理大型的資料, 僅須使用普通的硬體, 就能夠處理成千上萬的行和列所組成的大型資料.[HBase 實戰技術手冊]
  3. HBase 的基本操作
  4. HBase 邏輯資料模型與實體資料模型
  5. HBase 用戶端管理功能 API
    HBase 提供了一系列定義資料的API, 這些API類似於關聯式資料庫中DDL(CREATE, ALTER, DROP...)和DML(SELECT, INSERT, UPDATE, DELETE...),
    1. Schema 的定義
      • Tables
      • 所有貯存在HBase上的Column最終會被群組到一個或多個Table裡, 主要的理由是讓Table可以控制Table裡面Column所共享的特殊設定. (舉例來說, 通常都會在Table中定義Column Families.)

        使用 Java 語言定義Table Descriptor的語法如下:

        HTableDescriptor();
        HTableDescriptor(String name);
        HTableDescriptor(byte[] name);
        HTableDescriptor(HTableDescriptor desc);


        在建立 Table 時, 可以指派一個name或使用現有的descriptor.
        不帶任何參數的建構方法僅供反序列化目的運用, 不能夠直接使用之.
        此外, Table的名字可使用Stringbyte[](位元組陣列)等兩種型別.
        這是因為byte[]是HBase唯一的資料型別, 因此, HBase的Java API大都提供Stringbyte[]兩種選擇. 使用String比較單純而方便, Hbase 會在內部自動將String轉成byte[]形式.

        透過Java的 Byte class 也可以自己把String轉成byte[]形式, 並運用其建構Table Descriptor:

        byte[] name = Bytes.toBytes("test");
        HTableDescriptor desc = new HTableDescriptor(name);

        Table的命名必須符合HBase的規範, 在透過HBase建立Table的時候, HBase會呼叫isLegalTableName來檢查命名是否符合規範, 具體的規範如下:不得為空不得以"."和"-"作為開頭命名只能包含英數字及".", "_", "-"
        http://www.oratea.net/?p=959

        直欄導向式資料庫(Column-oriented databases)可以在同一張資料表中貯存許多詳細資料, 同樣的資料在關聯式資料庫中則會被拆成好幾張表。
        因此HBase資料庫中的Table 數量通常會低於關聯式資料庫。

        過去在關聯式資料庫中所學的正規化原則在HBase中是不合適的。HBase資料庫適用反正規化原則

      出自 HBase: The Definitive Guide




      • Table 屬性(Table Properties)
        在上一個段落裡提到的Table Descriptor建構子提供了getters和setters讓我們可以針對Table的建構做更多設定。雖然不常用,但是在微調的時候會需要知道, 所以我們以下對這些屬性做一些簡單的介紹。

        Name
        在上一段落中我們已經提到在建構子的參數中可以自訂Table的Name, 然而API還提供了以下的Methods讓我們可以取得或變更Table的Name屬性。

        byte[] getName();
        String getNameAsString();
        void setName(byte[] name);

        另外要注意,Table的命名必須符合HBase的規範, 在透過HBase建立Table的時候, HBase會呼叫isLegalTableName來檢查命名是否符合規範,具體的規範如下:不得為空、不得以"."和"-"作為開頭、命名只能包含英數字及".", "_", "-"。

        Column families
        這是定義Table時最重要的設定, 必須定義Table中所要使用的Column Families。再次注意, Table中使用的Column Family 在設定之後是不能變動的。

        void addFamily(HColumnDescriptor family); //增加family
        boolean hasFamily(byte[] c);  //以name檢查family是否存在
        HColumnDescriptor[] getColumnFamilies();  //取得現有Column列表
        HColumnDescriptor getFamily(byte[]column);  //以name取得特定family
        HColumnDescriptor removeFamily(byte[] column);  //以name移除特定family

        Maximum file size

        這個參數可以定義Table中的Region最大可以成長到的大小。當Region成長到這個限制時系統就會對Region進行分割。其get與set方法如下:

        long getMaxFileSize();
        void setMaxFileSize(long maxFileSize);


        all the files belonging to each column family. If one single column family exceeds this maximum size, the region is split.


        Read-only
        所有的Table預設都是可寫入的(Writable), 但也可以依照需要, 將Table設定成為讀, 設定方式如下:

        boolean isReadOnly();
        void setReadOnly(boolean readOnly);


        Memstore flush size
        抵達 regionserver的寫入請求會先寫入到commit log中, 然後存放在記憶體中的memorystore。當memorystore滿了的時候, 才會將其中的內容真正寫入(flush)檔案系統。設定memstore flush的大小方式如下:

        long getMemStoreFlushSize();
        void setMemStoreFlushSize(long memstoreFlushSize);

        這個大小設定越大可以讓寫入檔案系統的次數減少, 藉此提昇效能, 但同時也會增加系統的風險。舉例來說, 若系統存了一堆資料在記憶體裡, 這時候卻死當, 存在記憶體裡還沒寫入檔案系統的資料就報銷了。

        Deferred log flush
        Java API提供設定是否使用deferred log的功能, 設定方式如下:
        (預設是不啟用)

        synchronized boolean isDeferredLogFlush();
        void setDeferredLogFlush(boolean isDeferredLogFlush);


        Miscellaneous options
        也可以在Table的定義裡儲存自己定義的Key/Value資料, 設定和存取的方式如下:

        byte[] getValue(byte[] key) {
        String getValue(String key)
        Map<ImmutableBytesWritable, ImmutableBytesWritable> getValues()
        void setValue(byte[] key, byte[] value)
        void setValue(String key, String value)
        void remove(byte[] key)
      • Column Families
        上面我們在介绍運用HTableDescriptor添加Column Family到Table裡面時,  約略談到了HColumnDescriptor, 其實HColumnDescriptor這個名字照理來講應該要取做HColumnFamilyDescriptor才能正確的表示是用來建構Column Family的功用, 這是在命名時的一個錯誤, 但是沒辦法, 軟體上太多這樣的將錯就錯。所以要記得, HColumnDescriptor是用來建構Column Family的喔。



        Name

        Maximum versions

        Compression

        Block size

        Block cache

        Time-to-live

        In-memory

        Bloom filter

        Replication scope
    2. HbaseAdmin
      • 基本操作 Basic Operations
      • 資料表操作 Table Operations
        範例:

        HBaseAdmin admin = new HBaseAdmin(conf);
        HTableDescriptor desc = new HTableDescriptor( Bytes.toBytes("testtable"));
        HColumnDescriptor coldef = new HColumnDescriptor(
        Bytes.toBytes("colfam1"));
        desc.addFamily(coldef);
        admin.createTable(desc);
        try {
                 admin.deleteTable(Bytes.toBytes("testtable"));
             }
        catch (IOException e) {
                 System.err.println("Error deleting table: " + e.getMessage());
        }
        admin.disableTable(Bytes.toBytes("testtable"));
        boolean isDisabled = admin.isTableDisabled(Bytes.toBytes("testtable"));
        System.out.println("Table is disabled: " + isDisabled);
        boolean avail1 = admin.isTableAvailable(Bytes.toBytes("testtable"));
        System.out.println("Table available: " + avail1);
        admin.deleteTable(Bytes.toBytes("testtable"));
        boolean avail2 = admin.isTableAvailable(Bytes.toBytes("testtable"));
        System.out.println("Table available: " + avail2);
        admin.createTable(desc);
        boolean isEnabled = admin.isTableEnabled(Bytes.toBytes("testtable"));
        System.out.println("Table is enabled: " + isEnabled);
      • Schema Operations
      • 叢集操作 Cluster Operations
      • 叢集狀態資訊 Cluster Status Information
  6. 結語
    API這種東西就是要用到的時候才會想要查, 參考書上在這個章節裡劈頭就說, 這張談到的參數很多都很少用到, 大概了解一下要用的時候在查就好。
  7. 參考資料