大數(shù)據(jù)架構(gòu)-使用HBase和Solr配置存儲與索引
HBase和Solr可以通過協(xié)處理器Coprocessor的方式向Solr發(fā)出請求,Solr對于接收到的數(shù)據(jù)可以做相關(guān)的同步:增、刪、改索引的操作。將存儲與索引放在不同的機(jī)器上,這是大數(shù)據(jù)架構(gòu)的必須品,但目前還有很多不懂得此道的同學(xué),他們對于這種思想感到很新奇,不過,這絕對是好的方向,所以不懂得抓緊學(xué)習(xí)吧。
有個朋友給我的那篇博客留言,說CDH也可以做這樣的事情,我還沒有試過,他還問我要與此相關(guān)的代碼,于是我就稍微整理了一下,作為本篇文章的主要內(nèi)容。關(guān)于CDH的事,我會盡快嘗試,有知道的同學(xué)可以給我留言。
下面我主要講述一下,我測試對HBase和Solr的性能時,使用HBase協(xié)處理器向HBase添加數(shù)據(jù)所編寫的相關(guān)代碼,及解釋說明。
一、編寫HBase協(xié)處理器Coprocessor
一旦有數(shù)據(jù)postPut,就立即對Solr里相應(yīng)的Core更新。這里使用了ConcurrentUpdateSolrServer,它是Solr速率性能的保證,使用它不要忘記在Solr里面配置autoCommit喲。
- /*
 - *版權(quán):王安琪
 - *描述:監(jiān)視HBase,一有數(shù)據(jù)postPut就向Solr發(fā)送,本類要作為觸發(fā)器添加到HBase
 - *修改時間:2014-05-27
 - *修改內(nèi)容:新增
 - */
 - package solrHbase.test;
 - import java.io.UnsupportedEncodingException;
 - import ***;
 - public class SorlIndexCoprocessorObserver extends BaseRegionObserver {
 - private static final Logger LOG = LoggerFactory
 - .getLogger(SorlIndexCoprocessorObserver.class);
 - private static final String solrUrl = "http://192.1.11.108:80/solr/core1";
 - private static final SolrServer solrServer = new ConcurrentUpdateSolrServer(
 - solrUrl, 10000, 20);
 - /**
 - * 建立solr索引
 - *
 - * @throws UnsupportedEncodingException
 - */
 - @Override
 - public void postPut(final ObserverContext<RegionCoprocessorEnvironment> e,
 - final Put put, final WALEdit edit, final boolean writeToWAL)
 - throws UnsupportedEncodingException {
 - inputSolr(put);
 - }
 - public void inputSolr(Put put) {
 - try {
 - solrServer.add(TestSolrMain.getInputDoc(put));
 - } catch (Exception ex) {
 - LOG.error(ex.getMessage());
 - }
 - }
 - }
 
注意:getInputDoc是這個HBase協(xié)處理器Coprocessor的精髓所在,它可以把HBase內(nèi)的Put里的內(nèi)容轉(zhuǎn)化成Solr需要的值。其中String fieldName = key.substring(key.indexOf(columnFamily) + 3, key.indexOf("我在這")).trim();這里有一個亂碼字符,在這里看不到,請大家注意一下。
- public static SolrInputDocument getInputDoc(Put put) {
 - SolrInputDocument doc = new SolrInputDocument();
 - doc.addField("test_ID", Bytes.toString(put.getRow()));
 - for (KeyValue c : put.getFamilyMap().get(Bytes.toBytes(columnFamily))) {
 - String key = Bytes.toString(c.getKey());
 - String value = Bytes.toString(c.getValue());
 - if (value.isEmpty()) {
 - continue;
 - }
 - String fieldName = key.substring(key.indexOf(columnFamily) + 3,
 - key.indexOf("")).trim();
 - doc.addField(fieldName, value);
 - }
 - return doc;
 - }
 
二、編寫測試程序入口代碼main
這段代碼向HBase請求建了一張表,并將模擬的數(shù)據(jù),向HBase連續(xù)地提交數(shù)據(jù)內(nèi)容,在HBase中不斷地插入數(shù)據(jù),同時記錄時間,測試插入性能。
- /*
 - *版權(quán):王安琪
 - *描述:測試HBaseInsert,HBase插入性能
 - *修改時間:2014-05-27
 - *修改內(nèi)容:新增
 - */
 - package solrHbase.test;
 - import hbaseInput.HbaseInsert;
 - import ***;
 - public class TestHBaseMain {
 - private static Configuration config;
 - private static String tableName = "angelHbase";
 - private static HTable table = null;
 - private static final String columnFamily = "wanganqi";
 - /**
 - * @param args
 - */
 - public static void main(String[] args) {
 - config = HBaseConfiguration.create();
 - config.set("hbase.zookeeper.quorum", "192.103.101.104");
 - HbaseInsert.createTable(config, tableName, columnFamily);
 - try {
 - table = new HTable(config, Bytes.toBytes(tableName));
 - for (int k = 0; k < 1; k++) {
 - Thread t = new Thread() {
 - public void run() {
 - for (int i = 0; i < 100000; i++) {
 - HbaseInsert.inputData(table,
 - PutCreater.createPuts(1000, columnFamily));
 - Calendar c = Calendar.getInstance();
 - String dateTime = c.get(Calendar.YEAR) + "-"
 - + c.get(Calendar.MONTH) + "-"
 - + c.get(Calendar.DATE) + "T"
 - + c.get(Calendar.HOUR) + ":"
 - + c.get(Calendar.MINUTE) + ":"
 - + c.get(Calendar.SECOND) + ":"
 - + c.get(Calendar.MILLISECOND) + "Z 寫入: "
 - + i * 1000;
 - System.out.println(dateTime);
 - }
 - }
 - };
 - t.start();
 - }
 - } catch (IOException e1) {
 - e1.printStackTrace();
 - }
 - }
 - }
 
下面的是與HBase相關(guān)的操作,把它封裝到一個類中,這里就只有建表與插入數(shù)據(jù)的相關(guān)代碼。
- /*
 - *版權(quán):王安琪
 - *描述:與HBase相關(guān)操作,建表與插入數(shù)據(jù)
 - *修改時間:2014-05-27
 - *修改內(nèi)容:新增
 - */
 - package hbaseInput;
 - import ***;
 - import org.apache.hadoop.hbase.client.Put;
 - public class HbaseInsert {
 - public static void createTable(Configuration config, String tableName,
 - String columnFamily) {
 - HBaseAdmin hBaseAdmin;
 - try {
 - hBaseAdmin = new HBaseAdmin(config);
 - if (hBaseAdmin.tableExists(tableName)) {
 - return;
 - }
 - HTableDescriptor tableDescriptor = new HTableDescriptor(tableName);
 - tableDescriptor.addFamily(new HColumnDescriptor(columnFamily));
 - hBaseAdmin.createTable(tableDescriptor);
 - hBaseAdmin.close();
 - } catch (MasterNotRunningException e) {
 - e.printStackTrace();
 - } catch (ZooKeeperConnectionException e) {
 - e.printStackTrace();
 - } catch (IOException e) {
 - e.printStackTrace();
 - }
 - }
 - public static void inputData(HTable table, ArrayList<Put> puts) {
 - try {
 - table.put(puts);
 - table.flushCommits();
 - puts.clear();
 - } catch (IOException e) {
 - e.printStackTrace();
 - }
 - }
 - }
 
三、編寫模擬數(shù)據(jù)Put
向HBase中寫入數(shù)據(jù)需要構(gòu)造Put,下面是我構(gòu)造模擬數(shù)據(jù)Put的方式,有字符串的生成,我是由mmseg提供的詞典words.dic中隨機(jī)讀取一些詞語連接起來,生成一句字符串的,下面的代碼沒有體現(xiàn),不過很easy,你自己造你自己想要的數(shù)據(jù)就OK了。
- public static Put createPut(String columnFamily) {
 - String ss = getSentence();
 - byte[] family = Bytes.toBytes(columnFamily);
 - byte[] rowKey = Bytes.toBytes("" + Math.abs(r.nextLong()));
 - Put put = new Put(rowKey);
 - put.add(family, Bytes.toBytes("DeviceID"),
 - Bytes.toBytes("" + Math.abs(r.nextInt())));
 - ******
 - put.add(family, Bytes.toBytes("Company_mmsegsm"), Bytes.toBytes("ss"));
 - return put;
 - }
 
當(dāng)然在運(yùn)行上面這個程序之前,需要先在Solr里面配置好你需要的列信息,HBase、Solr安裝與配置,它們的基礎(chǔ)使用方法將會在之后的文章中介紹。在這里,Solr的列配置就跟你使用createPut生成的Put搞成一樣的列名就行了,當(dāng)然也可以使用動態(tài)列的形式。
四、直接對Solr性能測試
如果你不想對HBase與Solr的相結(jié)合進(jìn)行測試,只想單獨(dú)對Solr的性能進(jìn)行測試,這就更簡單了,完全可以利用上面的代碼段來測試,稍微組裝一下就可以了。
- private static void sendConcurrentUpdateSolrServer(final String url,
 - final int count) throws SolrServerException, IOException {
 - SolrServer solrServer = new ConcurrentUpdateSolrServer(url, 10000, 20);
 - for (int i = 0; i < count; i++) { solrServer.add(getInputDoc(PutCreater.createPut(columnFamily)));
 - }
 - }
 
希望可以幫助到你規(guī)格嚴(yán)格-功夫到家。這次的文章代碼又偏多了點(diǎn),但代碼是解釋思想的***的語言,我的提倡就是盡可能的減少代碼的注釋,盡力簡化你的代碼,使你的代碼足夠的清晰易懂,甚至于相似于偽代碼了,這也是《重構(gòu)》這本書里所提倡的。
原文鏈接:http://www.cnblogs.com/wgp13x/p/3927979.html















 
 
 












 
 
 
 