基於solr實現hbase的二級索引
[X] 目的:
由於hbase基於行健有序存儲,在查詢時使用行健十分高效,然後想要實現關係型數據庫那樣可以隨意組合的多條件查詢
、查詢總記錄數
、分頁
等就比較麻煩了。想要實現這樣的功能,我們可以採用兩種方法:
- 使用hbase提供的filter,
- 自己實現二級索引,通過二級索引 查詢多符合條件的行健,然後再查詢hbase.
第一種方法不多說了,使用起來很方便,但是侷限性也很大,hbase的filter是直接掃記錄的,如果數據範圍很大,會導致查詢速度很慢. 所以如果能先使 用行健把記錄縮小到一個較小範圍,那麼就比較適合,否則就不適用了.此外該方法不能解決獲取總數的爲.
第二種是適用範圍就比較廣泛了,不過根據實現二級索引的方式解決的問題也不同.這裏我們選擇solr主要是因爲solr可以很輕鬆實現各種查詢(本來就是全文檢索引擎).
[X] 實現思路:
其實hbase結合solr實現方法還是比較簡單的,重點在於一些實現細節上.
將hbase記錄寫入solr的關鍵就在於hbase提供的Coprocessor
, Coprocessor
提供了兩個實現:endpoint
和observer
,
endpoint
相當於關係型數據庫的存儲過程,而observer則相當於 觸 發器.說到這相信大家應該就明白了,我們要利用的就是observer
.
observer
允許我們在記錄put前後做一些處理,而我們就是通過postPut
將記錄同步寫入solr(關於Coprocessor具體內容請自行查資料).
而寫入solr這塊就比較簡單了,主要是要考慮性能!默認情況下hbase每寫一條數據就會向出發一次postPut
,
如果直接提交個solr,速度會非常慢,而且如果有異常處理起來也會非常的麻煩.因此要自己實現一個本地可持久化的隊列,通過後臺線程異步向向solr提交.
[X] 實現代碼:
[X] 部署:
在Solr的schema.xml文件裏必須有如下動態字段:
<dynamicField name="*_i" type="int" indexed="true" stored="true"/>
<dynamicField name="*_l" type="long" indexed="true" stored="true"/>
<dynamicField name="*_f" type="float" indexed="true" stored="true"/>
<dynamicField name="*_d" type="double" indexed="true" stored="true"/>
<dynamicField name="*_b" type="boolean" indexed="true" stored="true"/>
<dynamicField name="*_s" type="string" indexed="true" stored="true" />
<dynamicField name="*_t" type="text_general" indexed="true" stored="true"/>
<dynamicField name="*_dt" type="date" indexed="true" stored="true"/>
說明:
solr裏的每一條Dcoument對應HBase表裏的一條記錄
每一條Dcoument裏缺省都會有4個字段:
id
格式是:${TableName}#${RowKey}
t_s
格式是:${TableName}
r_s
格式是:${RowKey}
u_dt
格式是:${d當前更新時的日期和時間}
其他字段格式是:${Family}#${Qualifier}
如果HBase表裏的字段需要在solr裏索引,那麼Qualifier
設計爲已_(i|l|f|d|b|s|t|dt)
結尾的solr動態字段!
停止HBase:
在master hbase server上執行:
${HBASE_HOME}/bin/stop-hbase.sh
修改所有Region Servers
的$(HBASE_HOME}/conf/hbase-site.xml
配置文件
在最後添加:
<!-- 調試時,將hbase的hbase.coprocessor.abortonerror設置成true,待確定Coprocessor運行正常後在改爲false.
此步驟非必要,但是如果Coprocessor有問題會導致所有Region Server無法啓動!
-->
<property>
<name>hbase.coprocessor.abortonerror</name>
<value>true</value>
</property>
<!-- Solr Coprocessor -->
<property>
<name>hbase.coprocessor.region.classes</name>
<value>wjw.hbase.solr.SolrRegionObserver</value>
</property>
<!-- 本地保存Queue的目錄名,沒有時使用:System.getProperty("java.io.tmpdir")得來的值 -->
<property>
<name>hbase.solr.queueDir</name>
<value>/tmp</value>
</property>
<!-- Solr的URL,多個以逗號分隔 -->
<property>
<name>hbase.solr.solrUrl</name>
<value>http://${solrHost1}:8983/solr/,http://${solrHost2}:8983/solr/</value>
</property>
<!-- core名字 -->
<property>
<name>hbase.solr.coreName</name>
<value>hbase</value>
</property>
<!-- 連接超時(秒) -->
<property>
<name>hbase.solr.connectTimeout</name>
<value>60</value>
</property>
<!-- 讀超時(秒) -->
<property>
<name>hbase.solr.readTimeout</name>
<value>60</value>
</property>
複製SolrCoprocessor_X.X.X.jar
文件
把SolrCoprocessor_X.X.X.jar
複製到所有的Region Servers
的$(HBASE_HOME}/lib/
目錄下
啓動HBase:
在master hbase server上執行:
${HBASE_HOME}/bin/start-hbase.sh
測試:
/opt/hbase/bin/hbase shell
>status
>create 'demotable','col'
>describe 'demotable'
>list 'demotable'
>put 'demotable','myrow-1','col:q1','value-1'
>put 'demotable','myrow-1','col:q2_s','value-2-測試'
>put 'demotable','myrow-1','col:name_t','張三 李四 王五'
>put 'demotable','myrow-1','col:q3_s','value-3-測試'
>scan 'demotable'