Elasticsearch+Hbase實現海量數據秒回查詢


---------------------------------------------------------------------------------------------
[版權申明:本文系作者原創,轉載請注明出處] 
文章出處: http://blog.csdn.net/sdksdk0/article/details/53966430
作者:朱培      ID:sdksdk0     

--------------------------------------------------------------------------------------------


首先祝大家2017新年快樂,我今天分享的是通過ElasticSearch與hbase進行整合的一個搜索案例,這個案例涉及的技術面比較廣,首先你得有JAVAEE的基礎,要會SSM,而且還要會大數據中的hdfs、zookeeper、hbase以及ElasticSearch和kibana。環境部署在4台centos7上。主機名為node1-node4。這里假設你已經安裝好了zookeeper、hadoop、hbase和ElasticSearch還有kibana,我這里使用的是hadoop2.5.2,ElasticSearch用的你是2.2,kibana是4.4.1。我這里的環境是 hadoop是4台在node1-node4, zookeeper是3台再node1-node3,,ElasticSearch是3台在node1-node3,kibana是一台在node1上。該系統可以對億萬數據查詢進行秒回,是一般的關系型數據庫很難做到的。在IntelliJ IDEA 中進行代碼編寫。環境搭建我這里就不啰嗦,相信大家作為一名由經驗的開發人員來說都是小事一樁。文末提供源碼下載鏈接。



一、ElasticSearch和Hbase

ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分布式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並作為Apache許可條款下的開放源碼發布,是當前流行的企業級搜索引擎。設計用於雲計算中,能夠達到實時搜索,穩定,可靠,快速,安裝使用方便。 Elasticsearch的性能是solr的50倍。


HBase – Hadoop Database,是一個高可靠性、高性能、面向列、可伸縮、
實時讀寫的分布式數據庫
– 利用Hadoop HDFS作為其文件存儲系統,利用Hadoop MapReduce來處理
HBase中的海量數據,利用Zookeeper作為其分布式協同服務
– 主要用來存儲非結構化和半結構化的松散數據(列存 NoSQL 數據庫)



二、需求分析&服務器環境設置

主要是做一個文章的搜索。有文章標題、作者、摘要、內容四個主要信息。效果圖如下:這里樣式我就沒怎么設置了。。。。想要好看一點的可以自己加css。



服務器:

在3台centos7中部署,主機名為node1-node3.安裝好ElasticSearch並配置好集群,

1.     解壓

2.     修改config/elasticsearch.yml    (注意要頂格寫,冒號后面要加一個空格)

a)      Cluster.name: tf   (同一集群要一樣)

b)      Node.name: node-1  (同一集群要不一樣)

c)       Network.Host: 192.168.44.137  這里不能寫127.0.0.1

3.     解壓安裝kibana

4.     再congfig目錄下的kibana.yml中修改elasticsearch.url

5.     安裝插件

Step 1: Install Marvel into Elasticsearch:

bin/plugin install license
bin/plugin install marvel-agent

Step 2: Install Marvel into Kibana

bin/kibana plugin --install elasticsearch/marvel/latest

Step 3: Start Elasticsearch and Kibana

bin/elasticsearch
bin/kibana

 


啟動好elasticsearch集群后,

然后啟動zookeeper、hdfs、hbase。zkService.sh start  、start-all.sh、start-hbase.sh。

接下來就是剩下編碼步驟了。




三、編碼開發

1、首先在IntelliJ IDEA中新建一個maven工程,加入如下依賴。


   
   
  
  
          
  1. <dependencies>
  2. <dependency>
  3. <groupId>junit </groupId>
  4. <artifactId>junit </artifactId>
  5. <version>4.9 </version>
  6. </dependency>
  7. <!-- spring 3.2 -->
  8. <dependency>
  9. <groupId>org.springframework </groupId>
  10. <artifactId>spring-context </artifactId>
  11. <version>3.2.0.RELEASE </version>
  12. </dependency>
  13. <dependency>
  14. <groupId>org.springframework </groupId>
  15. <artifactId>spring-orm </artifactId>
  16. <version>3.2.0.RELEASE </version>
  17. </dependency>
  18. <dependency>
  19. <groupId>org.springframework </groupId>
  20. <artifactId>spring-aspects </artifactId>
  21. <version>3.2.0.RELEASE </version>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.springframework </groupId>
  25. <artifactId>spring-web </artifactId>
  26. <version>3.2.0.RELEASE </version>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.springframework </groupId>
  30. <artifactId>spring-webmvc </artifactId>
  31. <version>3.2.0.RELEASE </version>
  32. </dependency>
  33. <dependency>
  34. <groupId>org.springframework </groupId>
  35. <artifactId>spring-test </artifactId>
  36. <version>3.2.0.RELEASE </version>
  37. </dependency>
  38. <!-- JSTL -->
  39. <dependency>
  40. <groupId>jstl </groupId>
  41. <artifactId>jstl </artifactId>
  42. <version>1.2 </version>
  43. </dependency>
  44. <dependency>
  45. <groupId>taglibs </groupId>
  46. <artifactId>standard </artifactId>
  47. <version>1.1.2 </version>
  48. </dependency>
  49. <!-- slf4j -->
  50. <dependency>
  51. <groupId>org.slf4j </groupId>
  52. <artifactId>slf4j-api </artifactId>
  53. <version>1.7.10 </version>
  54. </dependency>
  55. <dependency>
  56. <groupId>org.slf4j </groupId>
  57. <artifactId>slf4j-log4j12 </artifactId>
  58. <version>1.7.10 </version>
  59. </dependency>
  60. <!-- elasticsearch -->
  61. <dependency>
  62. <groupId>org.elasticsearch </groupId>
  63. <artifactId>elasticsearch </artifactId>
  64. <version>2.2.0 </version>
  65. </dependency>
  66. <!-- habse -->
  67. <dependency>
  68. <groupId>org.apache.hbase </groupId>
  69. <artifactId>hbase-client </artifactId>
  70. <version>1.1.3 </version>
  71. <exclusions>
  72. <exclusion>
  73. <groupId>com.google.guava </groupId>
  74. <artifactId>guava </artifactId>
  75. </exclusion>
  76. </exclusions>
  77. </dependency>
  78. </dependencies>

2、Dao層


   
   
  
  
          
  1. private Integer id;
  2. private String title;
  3. private String describe;
  4. private String content;
  5. private String author;

實現其getter/setter方法。


3、數據准備

在桌面新建一個doc1.txt文檔,用於把我們需要查詢的數據寫入到里面,這里我只准備了5條數據。中間用tab鍵隔開。




4、在hbase中建立表。表名師doc,列族是cf。


public static void main(String[] args) throws Exception {
      HbaseUtils hbase = new HbaseUtils();
      //創建一張表 
	hbase.createTable("doc","cf");
}


/**  * 創建一張表  * @param tableName  * @param column  * @throws Exception  */ public void createTable(String tableName, String column) throws Exception {
   if(admin.tableExists(TableName.valueOf(tableName))){
      System.out.println(tableName+"表已經存在!");
   }else{
      HTableDescriptor tableDesc = new HTableDescriptor(TableName.valueOf(tableName));
      tableDesc.addFamily(new HColumnDescriptor(column.getBytes()));
      admin.createTable(tableDesc);
      System.out.println(tableName+"表創建成功!");
   }
}


5、導入索引。這一步的時候確保你的hdfs和hbase以及elasticsearch是處於開啟狀態。


   
   
  
  
          
  1. @Test
  2. public void createIndex() throws Exception {
  3. List<Doc> arrayList = new ArrayList<Doc>();
  4. File file = new File( "C:\\Users\\asus\\Desktop\\doc1.txt");
  5. List<String> list = FileUtils.readLines(file, "UTF8");
  6. for(String line : list){
  7. Doc Doc = new Doc();
  8. String[] split = line.split( "\t");
  9. System.out.print(split[ 0]);
  10. int parseInt = Integer.parseInt(split[ 0].trim());
  11. Doc.setId(parseInt);
  12. Doc.setTitle(split[ 1]);
  13. Doc.setAuthor(split[ 2]);
  14. Doc.setDescribe(split[ 3]);
  15. Doc.setContent(split[ 3]);
  16. arrayList.add(Doc);
  17. }
  18. HbaseUtils hbaseUtils = new HbaseUtils();
  19. for (Doc Doc : arrayList) {
  20. try {
  21. //把數據插入hbase
  22. hbaseUtils.put(hbaseUtils.TABLE_NAME, Doc.getId()+ "", hbaseUtils.COLUMNFAMILY_1, hbaseUtils.COLUMNFAMILY_1_TITLE, Doc.getTitle());
  23. hbaseUtils.put(hbaseUtils.TABLE_NAME, Doc.getId()+ "", hbaseUtils.COLUMNFAMILY_1, hbaseUtils.COLUMNFAMILY_1_AUTHOR, Doc.getAuthor());
  24. hbaseUtils.put(hbaseUtils.TABLE_NAME, Doc.getId()+ "", hbaseUtils.COLUMNFAMILY_1, hbaseUtils.COLUMNFAMILY_1_DESCRIBE, Doc.getDescribe());
  25. hbaseUtils.put(hbaseUtils.TABLE_NAME, Doc.getId()+ "", hbaseUtils.COLUMNFAMILY_1, hbaseUtils.COLUMNFAMILY_1_CONTENT, Doc.getContent());
  26. //把數據插入es
  27. Esutil.addIndex( "tfjt", "doc", Doc);
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }

數據導入成功之后可以在服務器上通過命令查看一下:

curl -XGET http://node1:9200/tfjt/_search




7、搜索。

在這里新建了一個工具類Esutil.java,主要用於處理搜索的。注意,我們默認的elasticsearch是9200端口的,這里數據傳輸用的是9300,不要寫成9200了,然后就是集群名字為tf,也就是前面配置的集群名。還有就是主機名node1-node3,這里不能寫ip地址,如果是本地測試的話,你需要在你的window下面配置hosts文件。



   
   
  
  
          
  1. public class Esutil {
  2. public static Client client = null;
  3. /**
  4. * 獲取客戶端
  5. * @return
  6. */
  7. public static Client getClient() {
  8. if(client!= null){
  9. return client;
  10. }
  11. Settings settings = Settings.settingsBuilder().put( "cluster.name", "tf").build();
  12. try {
  13. client = TransportClient.builder().settings(settings).build()
  14. .addTransportAddress( new InetSocketTransportAddress(InetAddress.getByName( "node1"), 9300))
  15. .addTransportAddress( new InetSocketTransportAddress(InetAddress.getByName( "node2"), 9300))
  16. .addTransportAddress( new InetSocketTransportAddress(InetAddress.getByName( "node3"), 9300));
  17. } catch (UnknownHostException e) {
  18. e.printStackTrace();
  19. }
  20. return client;
  21. }
  22. public static String addIndex(String index,String type,Doc Doc){
  23. HashMap<String, Object> hashMap = new HashMap<String, Object>();
  24. hashMap.put( "id", Doc.getId());
  25. hashMap.put( "title", Doc.getTitle());
  26. hashMap.put( "describe", Doc.getDescribe());
  27. hashMap.put( "author", Doc.getAuthor());
  28. IndexResponse response = getClient().prepareIndex(index, type).setSource(hashMap).execute().actionGet();
  29. return response.getId();
  30. }
  31. public static Map<String, Object> search(String key,String index,String type,int start,int row){
  32. SearchRequestBuilder builder = getClient().prepareSearch(index);
  33. builder.setTypes(type);
  34. builder.setFrom(start);
  35. builder.setSize(row);
  36. //設置高亮字段名稱
  37. builder.addHighlightedField( "title");
  38. builder.addHighlightedField( "describe");
  39. //設置高亮前綴
  40. builder.setHighlighterPreTags( "<font color='red' >");
  41. //設置高亮后綴
  42. builder.setHighlighterPostTags( "</font>");
  43. builder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
  44. if(StringUtils.isNotBlank(key)){
  45. // builder.setQuery(QueryBuilders.termQuery("title",key));
  46. builder.setQuery(QueryBuilders.multiMatchQuery(key, "title", "describe"));
  47. }
  48. builder.setExplain( true);
  49. SearchResponse searchResponse = builder.get();
  50. SearchHits hits = searchResponse.getHits();
  51. long total = hits.getTotalHits();
  52. Map<String, Object> map = new HashMap<String,Object>();
  53. SearchHit[] hits2 = hits.getHits();
  54. map.put( "count", total);
  55. List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
  56. for (SearchHit searchHit : hits2) {
  57. Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
  58. HighlightField highlightField = highlightFields.get( "title");
  59. Map<String, Object> source = searchHit.getSource();
  60. if(highlightField!= null){
  61. Text[] fragments = highlightField.fragments();
  62. String name = "";
  63. for (Text text : fragments) {
  64. name+=text;
  65. }
  66. source.put( "title", name);
  67. }
  68. HighlightField highlightField2 = highlightFields.get( "describe");
  69. if(highlightField2!= null){
  70. Text[] fragments = highlightField2.fragments();
  71. String describe = "";
  72. for (Text text : fragments) {
  73. describe+=text;
  74. }
  75. source.put( "describe", describe);
  76. }
  77. list.add(source);
  78. }
  79. map.put( "dataList", list);
  80. return map;
  81. }
  82. // public static void main(String[] args) {
  83. // Map<String, Object> search = Esutil.search("hbase", "tfjt", "doc", 0, 10);
  84. // List<Map<String, Object>> list = (List<Map<String, Object>>) search.get("dataList");
  85. // }
  86. }


8、使用spring控制層處理

在里面的spring配置這里就不說了,代碼文末提供。


   
   
  
  
          
  1. @RequestMapping( "/search.do")
  2. public String serachArticle(Model model,
  3. @RequestParam(value="keyWords",required = false) String keyWords,
  4. @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
  5. @RequestParam(value = "pageSize", defaultValue = "3") Integer pageSize){
  6. try {
  7. keyWords = new String(keyWords.getBytes( "ISO-8859-1"), "UTF-8");
  8. } catch (UnsupportedEncodingException e) {
  9. e.printStackTrace();
  10. }
  11. Map<String,Object> map = new HashMap<String, Object>();
  12. int count = 0;
  13. try {
  14. map = Esutil.search(keyWords, "tfjt", "doc",(pageNum- 1)*pageSize, pageSize);
  15. count = Integer.parseInt(((Long) map.get( "count")).toString());
  16. } catch (Exception e) {
  17. logger.error( "查詢索引錯誤!{}",e);
  18. e.printStackTrace();
  19. }
  20. PageUtil<Map<String, Object>> page = new PageUtil<Map<String, Object>>(String.valueOf(pageNum),String.valueOf(pageSize),count);
  21. List<Map<String, Object>> articleList = (List<Map<String, Object>>)map.get( "dataList");
  22. page.setList(articleList);
  23. model.addAttribute( "total",count);
  24. model.addAttribute( "pageNum",pageNum);
  25. model.addAttribute( "page",page);
  26. model.addAttribute( "kw",keyWords);
  27. return "index.jsp";
  28. }


9、頁面



   
   
  
  
          
  1. <center>
  2. <form action= "search.do" method= "get">
  3. <input type= "text" name= "keyWords" />
  4. <input type= "submit" value= "百度一下">
  5. <input type= "hidden" value= "1" name= "pageNum">
  6. </form>
  7. <c: if test= "${! empty page.list }">
  8. <h3>百度為您找到相關結果約${total}個</h3>
  9. <c:forEach items= "${page.list}" var= "bean">
  10. <a href= "/es/detailDocById/${bean.id}.do">${bean.title}</a>
  11. <br/>
  12. <br/>
  13. <span>${bean.describe}</span>
  14. <br/>
  15. <br/>
  16. </c:forEach>
  17. <c: if test= "${page.hasPrevious }">
  18. <a href= "search.do?pageNum=${page.previousPageNum }&keyWords=${kw}"> 上一頁</a>
  19. </c: if>
  20. <c:forEach begin= "${page.everyPageStart }" end= "${page.everyPageEnd }" var= "n">
  21. <a href= "search.do?pageNum=${n }&keyWords=${kw}"> ${n }</a>   
  22. </c:forEach>
  23. <c: if test= "${page.hasNext }">
  24. <a href= "search.do?pageNum=${page.nextPageNum }&keyWords=${kw}"> 下一頁</a>
  25. </c: if>
  26. </c: if>
  27. </center>


10、項目發布

在IntelliJ IDEA 中配置好常用的項目,這里發布名Application context名字為es,當然你也可以自定義設置。






最終效果如下:搜索COS會得到結果,速度非常快。




總結:這個案例的操作流程還是挺多的,要有細心和耐心,特別是服務器配置,各種版本要匹配好,不然會出各種頭疼的問題,當然了,這個還是需要有一定基礎,不然搞不定這個事情。。。。。


源碼地址:https://github.com/sdksdk0/es






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM