Cassandra使用pycassa批量導入數據

本週接手了一個Cassandra系統的維護工作,有一項是需要將應用方的數據導入我們維護的Cassandra集羣,並且爲應用方提供HTTP的方式訪問服務。這是我第一次接觸KV系統,原來只是走馬觀花似的看過KV啊,NoSQL啊。但是實際上沒有實際的使用經驗。經過兩天的學習和接手,終於搞明白了在生產環境中的使用方式。在此簡要的筆記一下。本文主要包括的內容有:

Cassandra的簡介,

Cassandra的相關CLI

Cassandra的Python API,並且給出一個批量導入數據的例子。


1. Cassandra簡介

Cassandra的主要特點就是它不是一個數據庫,而是由一堆數據庫節點共同構成的一個分佈式網絡服務,對Cassandra 的一個寫操作,會被複制到其他節點上去,對Cassandra的讀操作,也會被路由到某個節點上面去讀取。對於一個Cassandra羣集來說,擴展性能 是比較簡單的事情,只管在羣集裏面添加節點就可以了。

Cassandra是一個混合型的非關係的數據庫,類似於Google的BigTable。其主要功能比 Dynomite(分佈式的Key-Value存 儲系統)更豐富,但支持度卻不如文檔存儲MongoDB(介於關係數據庫和非關係數據庫之間的開源產品,是非關係數據庫當中功能最豐富,最像關係數據庫 的。支持的數據結構非常鬆散,是類似json的bjson格式,因此可以存儲比較複雜的數據類型。)Cassandra最初由Facebook開發,後轉變成了開源項目。它是一個網絡社交雲計算方面理想的數據庫。以Amazon專有的完全分佈式的Dynamo爲基礎,結合了Google BigTable基於列族(Column Family)的數據模型。P2P去中心化的存儲。很多方面都可以稱之爲Dynamo 2.0。

和其他數據庫比較,有幾個突出特點:

  1. 模式靈活 :使用Cassandra,像文檔存儲,你不必提前解決記錄中的字段。你可以在系統運行時隨意的添加或移除字段。這是一個驚人的效率提升,特別是在大型部 署上。
  2. 真正的可擴展性 :Cassandra是純粹意義上的水平擴展。爲給集羣添加更多容量,可以指向另一臺電腦。你不必重啓任何進程,改變應用查詢,或手動遷移任何數據。
  3. 多數據中心識別 :你可以調整你的節點佈局來避免某一個數據中心起火,一個備用的數據中心將至少有每條記錄的完全複製。

一些使Cassandra提高競爭力的其他功能:

  1. 範圍查詢 :如果你不喜歡全部的鍵值查詢,則可以設置鍵的範圍來查詢。
  2. 列表數據結構 :在混合模式可以將超級列添加到5維。對於每個用戶的索引,這是非常方便的。
  3. 分佈式寫操作 :可以在任何地方任何時間集中讀或寫任何數據。並且不會有任何單點失敗。

2. 基礎命令

連接

./cassandra-cli-h 10.224.52.73 -port 9160

集羣式自動負載的,因此連接任意一個節點即可。

Check schema

show schema;

在創建了schema或者列族後,可以使用時命令確認是否成功

在運行改命令前,需要使用命令use keyspace_name; 否則會遇到以下錯誤:

Not authorized to a working keyspace

 

list

list column_family_name;

可以顯示列族的前100列。


3. 批量導入

實驗數據來自搜狗實驗室的中文詞語搭配庫,http://www.sogou.com/labs/dl/r.html

數據格式如下:

詞語1_詞語2 \t 兩個詞共同出現的次數

在這裏並不討論該數據的具體意義,只是以這個數據爲起點來說明如何嚮應用方提供服務。

部分實際數據:

  都要_打牌>--4                       

  等候_一次>--26 

   本刊_重要>--3                                                                                                                                                                  關係_全方位>14                                                                                                                                                                加熱_迅速>--107     

設計列族名爲 test_only, cli 如下:

create column family test_only

 with column_type = 'Standard'

  andcomparator = 'UTF8Type'

  anddefault_validation_class = 'BytesType'

  andkey_validation_class = 'UTF8Type'

  andread_repair_chance = 0.1

  anddclocal_read_repair_chance = 0.0

  andgc_grace = 864000

  andmin_compaction_threshold = 4

  andmax_compaction_threshold = 32

  andreplicate_on_write = true

  andcompaction_strategy = 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy'

  andcaching = 'KEYS_ONLY'

  and column_metadata = [

    {column_name : 'count',

    validation_class : UTF8Type}]

  andcompression_options = {'sstable_compression' :'org.apache.cassandra.io.compress.SnappyCompressor'};

 

連接到Cassandra:pycassa.ConnectionPool(‘keyspace_name’, server_list)

具體到我們的例子就是:

con = pycassa.ConnectionPool('History',server_list=["server1:9160", "server2:9160","server3:9160"])

 
獲取列族:

cf = pycassa.ColumnFamily(con, cfName)


插入一條數據:

cf.insert('row_key', {'col_name': 'col_val'})  


批量插入:

cf.batch_insert({'row1': {'name1': 'val1', 'name2': 'val2'},                                           'row2': {'foo': 'bar'}})  


獲取一條數據:

cf.get(‘row_key’)


獲取某一列的值:

cf.get(‘row_key’)[‘column_name’]

下面是具體的代碼實現:

import pycassa                                                                                                                                                                                                                              
import time                                                                                                                                                                                                                                 
batch_size = 100                                                                                                                                                                                                                            
def pycassa_connect():                                                                                                                                                                                                                      
                                                                                                                                                                                                                                            
    #start = time.time()                                                                                                                                                                                                                    
    return pycassa.ConnectionPool('History', server_list=["192.168.1.20:9160"])                                                                                                                 
    #end = time.time()                                                                                                                                                                                                                      
    #print "Mola init time: ", (end - start)                                                                                                                                                                                                
                                                                                                                                                                                                                                            
def batch_insert(file_path, cf):                                                                                                                                                                                                            
    global batch_size                                                                                                                                                                                                                       
    f = open(file_path, "r")                                                                                                                                                                                                                
    count=0                                                                                                                                                                                                                                 
    error_count = 0                                                                                                                                                                                                                         
    kvmap = {}                                                                                                                                                                                                                              
    for line in f:--                                                                                                                                                                                                                        
        list = line.split("\t")                                                                                                                                                                                                             
        if len(list) != 2 :                                                                                                                                                                                                                 
            print "skip error data"                                                                                                                                                                                                         
            continue                                                                                                                                                                                                                        
        column = {}                                                                                                                                                                                                                         
        column['count'] = list[1].replace('\n', '')                                                                                                                                                                                         
        try:                                                                                                                                                                                                                                
            kvmap[list[0].decode('gb2312').encode('utf-8')] = column-                                                                                                                                                                       
            if len(kvmap) % batch_size == 0:                                                                                                                                                                                                
                cf.batch_insert(kvmap)                                                                                                                                                                                                      
                kvmap.clear()                                                                                                                                                                                                               
            count = count + 1                                                                                                                                                                                                               
        except Exception, ex:                                                                                                                                                                                                               
            print "found execption"                                                                                                                                                                                                         
            print ex                                                                                                                                                                                                                        
            error_count = error_count + 1                                                                                                                                                                                                   
    f.close()                                                                                                                                                                                                                               
    if len(kvmap) > 0 :                                                                                                                                                                                                                     
        cf.batch_insert(kvmap)                                                                                                                                                                                                              
----                                                                                                                                                                                                                                        
    for key in kvmap:                                                                                                                                                                                                                       
        print "key is %s, value is %s"%(key, kvmap[key])-                                                                                                                                                                                   
    print "total insert data is %d, error is %d"%(count, error_count)

如何測試數據是正確的?

def test_after_insert(file_path, cf):                                                                                                                                                                                                       
    f = open(file_path, "r")                                                                                                                                                                                                                
    error_count=0                                                                                                                                                                                                                           
    print "Test started"                                                                                                                                                                                                                    
    for line in f:--                                                                                                                                                                                                                        
        list = line.split("\t")                                                                                                                                                                                                             
        if len(list) != 2 :                                                                                                                                                                                                                 
            print "skip error data"                                                                                                                                                                                                         
            continue                                                                                                                                                                                                                        
        count = list[1].replace('\n', '')                                                                                                                                                                                                   
        if cf.get(list[0].decode('gb2312').encode('utf-8'))['count'] != count:                                                                                                                                                              
            print "Key %s doesn't match value %s"%(list[0].decode('gb2312').encode('utf-8'), count)                                                                                                                                         
            error_count = error_count + 1                                                                                                                                                                                                   
    print "Test completed, found %d error(s)."%error_count                                                                                                                                                                                  
    f.close()  


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