大資料架構-使用HBase和Solr配置儲存與索引

wulantian發表於2015-01-23

大資料架構-使用HBase和Solr配置儲存與索引

2014-08-22 11:04 王安琪 部落格園 字號:T | T
一鍵收藏,隨時檢視,分享好友!

HBase可以通過協處理器Coprocessor的方式向Solr發出請求,Solr對於接收到的資料可以做相關的同步:增、刪、改索引的操作,這樣就可以同時使用HBase儲存量大和Solr檢索效能高的優點了,更何況HBase和Solr都可以叢集。這對海量資料儲存、檢索提供了一種方式,將儲存與索引放在不同的機器上,是大資料架構的必須品。

AD:WOT2015 網際網路運維與開發者大會 熱銷搶票

HBase和Solr可以通過協處理器Coprocessor的方式向Solr發出請求,Solr對於接收到的資料可以做相關的同步:增、刪、改索引的操作。將儲存與索引放在不同的機器上,這是大資料架構的必須品,但目前還有很多不懂得此道的同學,他們對於這種思想感到很新奇,不過,這絕對是好的方向,所以不懂得抓緊學習吧。

有個朋友給我的那篇部落格留言,說CDH也可以做這樣的事情,我還沒有試過,他還問我要與此相關的程式碼,於是我就稍微整理了一下,作為本篇文章的主要內容。關於CDH的事,我會盡快嘗試,有知道的同學可以給我留言。

下面我主要講述一下,我測試對HBase和Solr的效能時,使用HBase協處理器向HBase新增資料所編寫的相關程式碼,及解釋說明。

一、編寫HBase協處理器Coprocessor

​一旦有資料postPut,就立即對Solr裡相應的Core更新。這裡使用了ConcurrentUpdateSolrServer,它是Solr速率效能的保證,使用它不要忘記在Solr裡面配置autoCommit喲。

  1. /* 
  2.  
  3.  *版權:王安琪 
  4.  
  5.  *描述:監視HBase,一有資料postPut就向Solr傳送,本類要作為觸發器新增到HBase 
  6.  
  7.  *修改時間:2014-05-27 
  8.  
  9.  *修改內容:新增 
  10.  
  11.  */ 
  12.  
  13. package solrHbase.test; 
  14.  
  15.   
  16.  
  17. import java.io.UnsupportedEncodingException; 
  18.  
  19.   
  20.  
  21. import ***; 
  22.  
  23.   
  24.  
  25. public class SorlIndexCoprocessorObserver extends BaseRegionObserver { 
  26.  
  27.   
  28.  
  29.     private static final Logger LOG = LoggerFactory 
  30.  
  31.             .getLogger(SorlIndexCoprocessorObserver.class); 
  32.  
  33.     private static final String solrUrl = "http://192.1.11.108:80/solr/core1"
  34.  
  35.     private static final SolrServer solrServer = new ConcurrentUpdateSolrServer( 
  36.  
  37.             solrUrl, 10000, 20); 
  38.  
  39.   
  40.  
  41.     /** 
  42.  
  43.      * 建立solr索引 
  44.  
  45.      *  
  46.  
  47.      * @throws UnsupportedEncodingException 
  48.  
  49.      */ 
  50.  
  51.     @Override 
  52.  
  53.     public void postPut(final ObserverContext<RegionCoprocessorEnvironment> e, 
  54.  
  55.             final Put put, final WALEdit edit, final boolean writeToWAL) 
  56.  
  57.             throws UnsupportedEncodingException { 
  58.  
  59.         inputSolr(put); 
  60.  
  61.     } 
  62.  
  63.   
  64.  
  65.     public void inputSolr(Put put) { 
  66.  
  67.         try { 
  68.  
  69.             solrServer.add(TestSolrMain.getInputDoc(put)); 
  70.  
  71.         } catch (Exception ex) { 
  72.  
  73.             LOG.error(ex.getMessage()); 
  74.  
  75.         } 
  76.  
  77.     } 
  78.  

注意:getInputDoc是這個HBase協處理器Coprocessor的精髓所在,它可以把HBase內的Put裡的內容轉化成Solr需要的值。其中String fieldName = key.substring(key.indexOf(columnFamily) + 3, key.indexOf("我在這")).trim();這裡有一個亂碼字元,在這裡看不到,請大家注意一下。

  1. public static SolrInputDocument getInputDoc(Put put) { 
  2.  
  3.         SolrInputDocument doc = new SolrInputDocument(); 
  4.  
  5.         doc.addField("test_ID", Bytes.toString(put.getRow())); 
  6.  
  7.         for (KeyValue c : put.getFamilyMap().get(Bytes.toBytes(columnFamily))) { 
  8.  
  9.             String key = Bytes.toString(c.getKey()); 
  10.  
  11.             String value = Bytes.toString(c.getValue()); 
  12.  
  13.             if (value.isEmpty()) { 
  14.  
  15.                 continue; 
  16.  
  17.             } 
  18.  
  19.             String fieldName = key.substring(key.indexOf(columnFamily) + 3, 
  20.  
  21.                     key.indexOf("")).trim(); 
  22.  
  23.             doc.addField(fieldName, value); 
  24.  
  25.         } 
  26.  
  27.         return doc; 
  28.  
  29.     } 

二、編寫測試程式入口程式碼main

​這段程式碼向HBase請求建了一張表,並將模擬的資料,向HBase連續地提交資料內容,在HBase中不斷地插入資料,同時記錄時間,測試插入效能。

  1. /* 
  2.  
  3.  *版權:王安琪 
  4.  
  5.  *描述:測試HBaseInsert,HBase插入效能 
  6.  
  7.  *修改時間:2014-05-27 
  8.  
  9.  *修改內容:新增 
  10.  
  11.  */ 
  12.  
  13. package solrHbase.test; 
  14.  
  15.   
  16.  
  17. import hbaseInput.HbaseInsert; 
  18.  
  19.   
  20.  
  21. import ***; 
  22.  
  23.   
  24.  
  25. public class TestHBaseMain { 
  26.  
  27.   
  28.  
  29.     private static Configuration config; 
  30.  
  31.     private static String tableName = "angelHbase"
  32.  
  33.     private static HTable table = null
  34.  
  35.     private static final String columnFamily = "wanganqi"
  36.  
  37.   
  38.  
  39.     /** 
  40.  
  41.      * @param args 
  42.  
  43.      */ 
  44.  
  45.     public static void main(String[] args) { 
  46.  
  47.         config = HBaseConfiguration.create(); 
  48.  
  49.         config.set("hbase.zookeeper.quorum", "192.103.101.104"); 
  50.  
  51.         HbaseInsert.createTable(config, tableName, columnFamily); 
  52.  
  53.         try { 
  54.  
  55.             table = new HTable(config, Bytes.toBytes(tableName)); 
  56.  
  57.             for (int k = 0; k < 1; k++) { 
  58.  
  59.                 Thread t = new Thread() { 
  60.  
  61.                     public void run() { 
  62.  
  63.                         for (int i = 0; i < 100000; i++) { 
  64.  
  65.                             HbaseInsert.inputData(table, 
  66.  
  67.                                     PutCreater.createPuts(1000, columnFamily)); 
  68.  
  69.                             Calendar c = Calendar.getInstance(); 
  70.  
  71.                             String dateTime = c.get(Calendar.YEAR) + "-" 
  72.  
  73.                                     + c.get(Calendar.MONTH) + "-" 
  74.  
  75.                                     + c.get(Calendar.DATE) + "T" 
  76.  
  77.                                     + c.get(Calendar.HOUR) + ":" 
  78.  
  79.                                     + c.get(Calendar.MINUTE) + ":" 
  80.  
  81.                                     + c.get(Calendar.SECOND) + ":" 
  82.  
  83.                                     + c.get(Calendar.MILLISECOND) + "Z 寫入: " 
  84.  
  85.                                     + i * 1000; 
  86.  
  87.                             System.out.println(dateTime); 
  88.  
  89.                         } 
  90.  
  91.                     } 
  92.  
  93.                 }; 
  94.  
  95.                 t.start(); 
  96.  
  97.             } 
  98.  
  99.         } catch (IOException e1) { 
  100.  
  101.             e1.printStackTrace(); 
  102.  
  103.         } 
  104.  
  105.     } 
  106.  
  107.   
  108.  

​下面的是與HBase相關的操作,把它封裝到一個類中,這裡就只有建表與插入資料的相關程式碼。

  1. /* 
  2.  
  3.  *版權:王安琪 
  4.  
  5.  *描述:與HBase相關操作,建表與插入資料 
  6.  
  7.  *修改時間:2014-05-27 
  8.  
  9.  *修改內容:新增 
  10.  
  11.  */ 
  12.  
  13. package hbaseInput; 
  14.  
  15. import ***; 
  16.  
  17. import org.apache.hadoop.hbase.client.Put; 
  18.  
  19.   
  20.  
  21. public class HbaseInsert { 
  22.  
  23.   
  24.  
  25.     public static void createTable(Configuration config, String tableName, 
  26.  
  27.             String columnFamily) { 
  28.  
  29.         HBaseAdmin hBaseAdmin; 
  30.  
  31.         try { 
  32.  
  33.             hBaseAdmin = new HBaseAdmin(config); 
  34.  
  35.             if (hBaseAdmin.tableExists(tableName)) { 
  36.  
  37.                 return; 
  38.  
  39.             } 
  40.  
  41.             HTableDescriptor tableDescriptor = new HTableDescriptor(tableName); 
  42.  
  43.             tableDescriptor.addFamily(new HColumnDescriptor(columnFamily)); 
  44.  
  45.             hBaseAdmin.createTable(tableDescriptor); 
  46.  
  47.             hBaseAdmin.close(); 
  48.  
  49.         } catch (MasterNotRunningException e) { 
  50.  
  51.             e.printStackTrace(); 
  52.  
  53.         } catch (ZooKeeperConnectionException e) { 
  54.  
  55.             e.printStackTrace(); 
  56.  
  57.         } catch (IOException e) { 
  58.  
  59.             e.printStackTrace(); 
  60.  
  61.         } 
  62.  
  63.     } 
  64.  
  65.   
  66.  
  67.     public static void inputData(HTable table, ArrayList<Put> puts) { 
  68.  
  69.         try { 
  70.  
  71.             table.put(puts); 
  72.  
  73.             table.flushCommits(); 
  74.  
  75.             puts.clear(); 
  76.  
  77.         } catch (IOException e) { 
  78.  
  79.             e.printStackTrace(); 
  80.  
  81.         } 
  82.  
  83.     } 
  84.  

三、編寫模擬資料Put

向HBase中寫入資料需要構造Put,下面是我構造模擬資料Put的方式,有字串的生成,我是由mmseg提供的詞典words.dic中隨機讀取一些詞語連線起來,生成一句字串的,下面的程式碼沒有體現,不過很easy,你自己造你自己想要的資料就OK了。

  1. public static Put createPut(String columnFamily) { 
  2.  
  3.         String ss = getSentence(); 
  4.  
  5.         byte[] family = Bytes.toBytes(columnFamily); 
  6.  
  7.         byte[] rowKey = Bytes.toBytes("" + Math.abs(r.nextLong())); 
  8.  
  9.         Put put = new Put(rowKey); 
  10.  
  11.         put.add(family, Bytes.toBytes("DeviceID"), 
  12.  
  13.                 Bytes.toBytes("" + Math.abs(r.nextInt()))); 
  14.  
  15.         ****** 
  16.  
  17.         put.add(family, Bytes.toBytes("Company_mmsegsm"), Bytes.toBytes("ss")); 
  18.  
  19.   
  20.  
  21.         return put; 
  22.  
  23.     } 

當然在執行上面這個程式之前,需要先在Solr裡面配置好你需要的列資訊,HBase、Solr安裝與配置,它們的基礎使用方法將會在之後的文章中介紹。在這裡,Solr的列配置就跟你使用createPut生成的Put搞成一樣的列名就行了,當然也可以使用動態列的形式。

四、直接對Solr效能測試

如果你不想對HBase與Solr的相結合進行測試,只想單獨對Solr的效能進行測試,這就更簡單了,完全可以利用上面的程式碼段來測試,稍微組裝一下就可以了。

  1. private static void sendConcurrentUpdateSolrServer(final String url, 
  2.  
  3.             final int count) throws SolrServerException, IOException { 
  4.  
  5.         SolrServer solrServer = new ConcurrentUpdateSolrServer(url, 10000, 20); 
  6.         for (int i = 0; i < count; i++) {      solrServer.add(getInputDoc(PutCreater.createPut(columnFamily))); 
  7.         } 
  8.     } 

希望可以幫助到你規格嚴格-功夫到家。這次的文章程式碼又偏多了點,但程式碼是解釋思想的最好的語言,我的提倡就是儘可能的減少程式碼的註釋,盡力簡化你的程式碼,使你的程式碼足夠的清晰易懂,甚至於相似於虛擬碼了,這也是《重構》這本書裡所提倡的。

原文連結:http://www.cnblogs.com/wgp13x/p/3927979.html

相關文章