ElasticSearch(增put、刪delete、改(本質是先刪除後添加)post、查get、post)

1、ElasticSearch簡介

1.1 什麼是ElasticSearch

ElasticSearch,簡稱es,es是一個開源的高擴展的分佈式全文搜索引擎,能夠近乎實時的存儲、檢索數據;自己擴展性很好,能夠擴展到上百臺服務器,處理pb級別的數據。es也使用java開發並使用Lucene做爲其核心來實現全部索引和搜索的功能,可是他的目的是經過簡單的RESTful API來隱藏Lucene的複雜性,從而讓全文檢索變得簡單。html

1.2 ElasticSearch使用案例

1.3 ElasticSearch對比Solrjava

·Solr利用zookeeper進行分佈式管理,而ElasticSearch自身帶有分佈式協調管理功能;node

· solr支持更多格式的數據,而ElasticSearch只支持json文件格式git

· solr官方提供的功能更多,而ElasticSearch自己更注重核心功能,高級功能有第三方插件提供程序員

· solr在傳統的搜索應用這種表現好於ElasticSearch,可是在實時搜索應用時效率明顯低於ElasticSearch。實時:新往文檔庫添加一個文檔,立刻調出來就能查到github

2、ElasticSearch安裝與啓動

2.1 下載ES壓縮包web

ElasticSearch分爲linnux和windows版本,基於主要學習的是ElasticSearch的java客戶端使用,因此選擇安裝較爲簡單的windows版本。算法

ElasticSearch下載官網:https://www.elastic.co/cn/downloads/spring

ElasticSearch啓動:數據庫

ElasticSearch啓動時會啓動兩個端口。

9300:使用一下API對服務器進行管理的端口,TCP的端口(TransportService)

9200:httpRESTful形式的接口

測試:

安裝ElasticSearch圖形化界面插件:head

ElasticSearch 5.*版本以上安裝head須要安裝node和grunt

下載head插件:https://github.com/mobz/elasticsearch-head

下載壓縮包便可

下載nodejs:http://nodejs.cn/download/

安裝完成之後,打開cmd,輸入node -v

說明nodejs安裝完成

而後打開head文件夾,按住shift+右鍵

安裝grunt

將grunt安裝爲全局命令,grunt是基於NodeJs的項目構建工具

在cmd控制檯中輸入一下命令:

npm install -g grunt-cli

進入head的文件夾,啓動head,在命令行輸入

>npm install
安裝完成後,再輸入
>grunt server

在瀏覽器輸入http://localhost:9100/

而後修改ElasticSearch的配置文件:elasticsearch.yml.增長一下兩條命令,注意冒號後面的空格

http.cors.enabled: true
http.cors.allow-origin: "*"

重啓ElasticSearch,在head頁面點擊鏈接-》信息-》集羣節點信息

3、ElasticSearch相關概念(術語)

3.1 概述

ElasticSearch是面向文檔(document oriented)的,這就意味着他能夠存儲整個對象或文檔(document),然而它不只僅是存儲,還會索引(index)每一個文檔的內容使之能夠被搜索。在ElasticSearch中,能夠對文檔(而非成行成列的數據)進行索引、排序、過濾。ElasticSearch比傳統關係型數據庫以下:

Relational DB ——》Databases——》Tables——》Rows——》Columns
ElasticSearch——》Indices——》Types——》Documents——》Fields

3.2 ElasticSearch核心概念

3.2.1 索引 index

一個索引就是一個擁有幾分類似特徵的文檔的集合。例如,你能夠有一個客戶數據的索引,另外一個產品目錄的索引,還有一個訂單數據的索引。一個索引由一個名字來標識(必須所有是小寫字母的),而且當咱們要對對應於這個索引中的文檔進行索引、搜索、更新、刪除的時候,都要使用到這個名字,。在一個集羣中,能夠定義任意多的索引。

3.2.2 類型 type

在一個索引中,你能夠定義一種或多種類型。一個類型是你的索引的一個邏輯上的分類/分區,其語義徹底由你來定。一般,會爲具備一組共同字段的文檔定義一個類型。好比說,咱們假設你運營一個博客平臺而且將你全部的數據存儲到一個索引中。在作這個索引中,你能夠爲用戶數據定義一個類型,爲博客數據定義另外一個類型。固然,也能夠爲評論數據定義另外一個類型。

3.2.3 字段 Field

至關因而數據表的再短,對文檔數據根據不一樣屬性進行的分類標識

3.2.4 映射 mapping

mapping是處理數據的的方式和規則方面作一些限制,如某個字段的數據類型、默認值、分析器、是否被索引等等,在這些都是映射裏面能夠設置的,其餘就是處理es裏面數據的一些使用規則設置也叫做映射,按着最優規則處理數據對性能提升很大,所以才須要映射,而且須要思考如何創建映射才能對性能最好。

3.2.5 文檔document

一個文檔是一個可被索引的基礎信息單元。好比,你能夠擁有某一個客戶的文檔,某一個產品的一個文檔,固然,也能夠擁有某一個訂單的一個文檔。文檔以JSON格式來表示,而JSOn是一個處處存在的互聯網數據交互格式

在一個inex/type裏,你能夠存儲任意多的文檔。注意,儘管一個文檔,物理上存在於一個索引中,文檔必須被索引/賦予一個索引的type

3.2.6 接近實時 NRT

ElasticSearch是一個接近實時的搜索平臺。這意味着,從索引一個文檔知道這個文檔可以被搜索到有一個輕微的延遲(一般是1s之內)

3.2.7 集羣cluster

一個集羣就是由一個或多個節點組織在一塊兒,他們共同持有整個數據,並一塊兒提供索引和搜索功能。一個集羣由一個惟一的名字標識,這個名字默認是「elasticSearch」.這個名字是最重要的,由於一個節點只能經過指定某個集羣的名字,來計入這個集羣。

3.2.8 節點 node

一個節點是集羣中的一個服務器,做爲集羣的一部分,它存儲數據,參與集羣的索引和搜索功能。和集羣相似,一個節點也是由一個名字來標識,默認狀況下,這個名字是一個隨機的漫威漫畫角色的名字,這個名字會在啓動的時候賦予節點。這個名字對於管理工做來講很重要,由於在這個管理過程當中,你會去肯定網絡中哪些的哪些服務器對應於ElasticSearch集羣中的哪些節點

一個節點能夠經過配置集羣名稱的方式來加入一個指定的集羣。默認狀況下,每一個節點都會被安排加入到一個角作「ElasticSearch」的集羣中,也就是說,若是你在你的網絡中啓動了若干節點,並假定他們可以互相發現彼此,他們將會自動的造成並加入到一個叫作「ElasticSearch」的集羣。

3.2.9 分片和複製 shards&replicas

一個索引能夠存儲超出單個節點硬件限制的大量數據。好比,一個具備10億文檔的索引佔據1TB的磁盤空間,而任一節點都沒有這樣大的磁盤空間;或者單個節點處理搜索請求,響應太慢。爲了解決這個問題,ElasticSearch提供了將索引劃分紅多份的能力,這些份就叫作分片。當你建立一個索引的時候,你能夠指定你想要的分片數量。每一個分片自己也是一個功能完善而且獨立的「索引」,這個「索引」能夠被放置到集羣中的任何節點上。分片很重要,主要有兩方面緣由:1)容許你水平分割/擴展你的內容容量。2)容許你在分片(潛在地,位於多個節點上)之上進行分佈式的、並行的操做,進而提升西性能/吞吐量。

至於一個分片怎麼樣分佈,他的文檔怎樣聚合回搜索請求,是徹底由ElasticSearch管理的,對於用戶來講,這些都是透明的。

在一個網絡/雲的環境裏,失敗隨時均可能發生,在某個分片/節點不知怎麼得就處於離線狀態,或者因爲任何緣由消失了,這種狀況下,有一個故障轉移機制是很是有用而且強烈推薦的。爲此目的,ElasticSearch容許你建立分片的一份或多份拷貝,這些拷貝叫作複製分片,或者直接叫複製。

複製之因此重要,有兩個主要緣由:在分片/節點失敗的狀況下,提供了高可用性。由於這個緣由,注意到複製分片從不與原/主要分片置於同一節點上是很是重要的。擴展你的搜索量/吞吐量,由於搜索能夠在全部的複製上並行運行。總之,每一個索引能夠被分紅多個分片。一個索引也能夠被複制0次(沒有被複制)或屢次。一旦複製了,每一個索引就有了主分片(做爲複製源的原來的分片)和複製分片(主分片的拷貝)之別。分片和複製的數量能夠在索引建立的時候指定。在索引建立後,能夠在任什麼時候候動態的改變複製的數量,可是你過後不能改變分片的數量。

默認狀況下,ElasticSearch中的每一個索引被分片5個主分片和1個複製,這意味着,若是你的集羣中至少有兩個節點,你的索引將會有5個主分片和另外5個複製分片(1個徹底拷貝),這樣的話每一個索引總共就有10個分片

4、ElasticSearch的客戶端操做

實際開發中,主要有三種方式能夠做爲ElasticSearch服務的客戶端:

1.elasticsearch-head插件

2.使用ElasticSearch提供的RESTful接口直接訪問

3.使用ElasticSearch提供的api進行訪問

4.1 安裝postman工具

Postman中文版是posstman這款強大網頁調試工具的windows客戶端,提供功能強大的web ap&http請求調試。能夠發送任何類型的http請求(get、head、post、put。。),而且能夠附帶任何數量的參數

4.2 使用Postman工具進行Restful接口訪問

4.2.1 ElasticSearch的接口語法

curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'

其中:

參數 解釋
VERB 適當的 HTTP 方法謂詞 : GETPOSTPUTHEAD 或者 DELETE
PROTOCOL http 或者 https(若是你在 Elasticsearch 前面有一個 https 代理)
HOST Elasticsearch 集羣中任意節點的主機名,或者用 localhost 表明本地機器上的節點。
PORT 運行 Elasticsearch HTTP 服務的端口號,默認是 9200
PATH API 的終端路徑(例如 _count 將返回集羣中文檔數量)。Path 可能包含多個組件,例如:_cluster/stats_nodes/stats/jvm
QUERY_STRING 任意可選的查詢字符串參數 (例如 ?pretty 將格式化地輸出 JSON 返回值,使其更容易閱讀)
BODY 一個 JSON 格式的請求體 (若是請求須要的話)

4.2.2 建立索引index和映射mapping

請求url:

PUT		localhost:9200/blog1

請求體:

{
    "mappings": {
        "article": {
            "properties": {
                "id": {
                	"type": "long",
                    "store": true,
                    "index":"not_analyzed"
                },
                "title": {
                	"type": "text",
                    "store": true,
                    "index":"analyzed",
                    "analyzer":"standard"
                },
                "content": {
                	"type": "text",
                    "store": true,
                    "index":"analyzed",
                    "analyzer":"standard"
                }
            }
        }
    }
}

報錯:

{
    "error": {
        "root_cause": [
            {
                "type": "mapper_parsing_exception",
                "reason": "Root mapping definition has unsupported parameters:  [article : {properties={id={index=not_analyzed, store=true, type=long}, title={analyzer=standard, index=analyzed, store=true, type=text}, content={analyzer=standard, index=analyzed, store=true, type=text}}}]"
            }
        ],
        "type": "mapper_parsing_exception",
        "reason": "Failed to parse mapping [_doc]: Root mapping definition has unsupported parameters:  [article : {properties={id={index=not_analyzed, store=true, type=long}, title={analyzer=standard, index=analyzed, store=true, type=text}, content={analyzer=standard, index=analyzed, store=true, type=text}}}]",
        "caused_by": {
            "type": "mapper_parsing_exception",
            "reason": "Root mapping definition has unsupported parameters:  [article : {properties={id={index=not_analyzed, store=true, type=long}, title={analyzer=standard, index=analyzed, store=true, type=text}, content={analyzer=standard, index=analyzed, store=true, type=text}}}]"
        }
    },
    "status": 400
}

出現問題的緣由:在ES7中,不推薦使用映射類型,這會致使此問題的根源發生重大變化。ES團隊宣佈了棄用,路線圖和替代方案。

解決方式:

方式一:刪除對映射類型的全部引用(在此示例中爲「article」)

方式二:平滑過渡到ES7的另外一個臨時解決方案是包含?include_type_name=true在URL中。

運行繼續報錯:

{
    "error": {
        "root_cause": [
            {
                "type": "mapper_parsing_exception",
                "reason": "Failed to parse mapping [_doc]: Could not convert [id.index] to boolean"
            }
        ],
        "type": "mapper_parsing_exception",
        "reason": "Failed to parse mapping [_doc]: Could not convert [id.index] to boolean",
        "caused_by": {
            "type": "illegal_argument_exception",
            "reason": "Could not convert [id.index] to boolean",
            "caused_by": {
                "type": "illegal_argument_exception",
                "reason": "Failed to parse value [not_analyzed] as only [true] or [false] are allowed."
            }
        }
    },
    "status": 400
}

解決方式:把「index」的值所有改成true/false

{
    "mappings": {
        
            "properties": {
                "id": {
                	"type": "long",
                    "store": true,
                    "index":true
                },
                "title": {
                	"type": "text",
                    "store": true,
                    "index":true,
                    "analyzer":"standard"
                },
                "content": {
                	"type": "text",
                    "store": true,
                    "index":true,
                    "analyzer":"standard"
                }
            }
        
    }
}

運行成功!信息以下:

{
    "acknowledged": true,
    "shards_acknowledged": true,
    "index": "blog2"
}

方式二:在url後添加?include_type_name=true。運行結果如圖

elasticsearch-head查看:

4.2.3 建立索引後設置Mapping

咱們能夠在建立索引時設置mapping信息,固然也能夠先建立索引而後再設置mapping。

在上一個步驟中不設置maping信息,直接使用put方法建立一個索引,而後設置mapping信息。

請求的url:

POST	http://127.0.0.1:9200/blog2/hello/_mapping
blog2:索引名稱
hello:type名稱
_mapping:執行動做的字符串

請求體:

{
    "hello": {
            "properties": {
                "id":{
                	"type":"long",
                	"store":true
                },
                "title":{
                	"type":"text",
                	"store":true,
                	"index":true,
                	"analyzer":"standard"
                },
                "content":{
                	"type":"text",
                	"store":true,
                	"index":true,
                	"analyzer":"standard"
                }
            }
        }
  }

PostMan截圖

4.2.4 刪除索引index

請求url:

DELETE		localhost:9200/blog1

postman截圖:

elasticsearch-head查看:

4.2.5 建立文檔document

請求url:

POST	localhost:9200/blog1/article/1
blog1:索引庫名稱
article:type名稱
1:文檔ID,並非下面的id屬性值

請求體:

{
	"id":1,
	"title":"ElasticSearch是一個基於Lucene的搜索服務器",
	"content":"它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並做爲Apache許可條款下的開放源碼發佈,是當前流行的企業級搜索引擎。設計用於雲計算中,可以達到實時搜索,穩定,可靠,快速,安裝使用方便。"
}

postman截圖:

elasticsearch-head查看:

4.2.6 修改文檔document

本質是:先刪除,後添加。要保證ID一致,並非field裏的id,而是url中hello後面的1這個id

請求url:

POST	localhost:9200/blog1/article/1

請求體:

{
	"id":1,
	"title":"【修改】ElasticSearch是一個基於Lucene的搜索服務器",
	"content":"【修改】它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並做爲Apache許可條款下的開放源碼發佈,是當前流行的企業級搜索引擎。設計用於雲計算中,可以達到實時搜索,穩定,可靠,快速,安裝使用方便。"
}

postman截圖:

elasticsearch-head查看:

4.2.7 刪除文檔document

請求url:

http://localhost:9200/blog4/hello/1

只須要指定要刪除的ES索引ID便可

postman截圖:

elasticsearch-head查看:

4.2.8 查詢文檔-根據id查詢

請求url:

http://localhost:9200/blog4/hello/2

postman截圖:

4.2.9 查詢文檔-querystring查詢

帶分析器的查詢,會把字符串分詞

請求url:

POST	localhost:9200/blog1/article/_search

請求體:

{
    "query": {                            //查詢
        "query_string": {                 //表示使用字符串查詢
            "default_field": "title",     //默認搜索域
            "query": "搜索服務器"           //查詢條件,能夠任意寫,不必定是關鍵詞
        }
    }
}

postman截圖:

注意:

將搜索內容"搜索服務器"修改成"鋼索",一樣也能搜索到文檔,該緣由會在下面講解中獲得答案

{
    "query": {
        "query_string": {
            "default_field": "title",
            "query": "鋼索"
        }
    }
}

4.2.10 查詢文檔-term查詢

term查詢:也就是關鍵詞查詢

請求url:

POST	localhost:9200/blog1/article/_search

請求體:

{
    "query": {                        //查詢
        "term": {                     //根據term進行查詢
            "title": "搜索"            //指定要查詢的字段、關鍵詞
        }
    }
}

postman截圖:

第五章 IK 分詞器和ElasticSearch集成使用

5.1 上述查詢存在問題分析

在進行字符串查詢時,咱們發現去搜索"搜索服務器"和"鋼索"均可以搜索到數據;

而在進行詞條查詢時,咱們搜索"搜索"卻沒有搜索到數據;

究其緣由是ElasticSearch的標準分詞器致使的,當咱們建立索引時,字段使用的是標準分詞器:

{
    "mappings": {
        "article": {
            "properties": {
                "id": {
                	"type": "long",
                    "store": true,
                    "index":"not_analyzed"
                },
                "title": {
                	"type": "text",
                    "store": true,
                    "index":"analyzed",
                    "analyzer":"standard"	//標準分詞器
                },
                "content": {
                	"type": "text",
                    "store": true,
                    "index":"analyzed",
                    "analyzer":"standard"	//標準分詞器
                }
            }
        }
    }
}

例如對 "我是程序員" 進行分詞

標準分詞器分詞效果測試:

http://127.0.0.1:9200/_analyze?analyzer=standard&pretty=true&text=我是程序員

分詞結果:

{
  "tokens" : [
    {
      "token" : "我",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "<IDEOGRAPHIC>",
      "position" : 0
    },
    {
      "token" : "是",
      "start_offset" : 1,
      "end_offset" : 2,
      "type" : "<IDEOGRAPHIC>",
      "position" : 1
    },
    {
      "token" : "程",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "<IDEOGRAPHIC>",
      "position" : 2
    },
    {
      "token" : "序",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "<IDEOGRAPHIC>",
      "position" : 3
    },
    {
      "token" : "員",
      "start_offset" : 4,
      "end_offset" : 5,
      "type" : "<IDEOGRAPHIC>",
      "position" : 4
    }
  ]
}

而咱們須要的分詞效果是:我、是、程序、程序員

這樣的話就須要對中文支持良好的分析器的支持,支持中文分詞的分詞器有不少,word分詞器、庖丁解牛、盤古分詞、Ansj分詞等,但咱們經常使用的仍是下面要介紹的IK分詞器。

5.2 IK分詞器簡介

IKAnalyzer是一個開源的,基於java語言開發的輕量級的中文分詞工具包。從2006年12月推出1.0版開始,IKAnalyzer已經推出 了3個大版本。最初,它是以開源項目Lucene爲應用主體的,結合詞典分詞和文法分析算法的中文分詞組件。新版本的IKAnalyzer3.0則發展爲 面向Java的公用分詞組件,獨立於Lucene項目,同時提供了對Lucene的默認優化實現。

IK分詞器3.0的特性以下:

1)採用了特有的「正向迭代最細粒度切分算法「,具備60萬字/秒的高速處理能力。 2)採用了多子處理器分析模式,支持:英文字母(IP地址、Email、URL)、數字(日期,經常使用中文數量詞,羅馬數字,科學計數法),中文詞彙(姓名、地名處理)等分詞處理。 3)對中英聯合支持不是很好,在這方面的處理比較麻煩.需再作一次查詢,同時是支持我的詞條的優化的詞典存儲,更小的內存佔用。 4)支持用戶詞典擴展定義。 5)針對Lucene全文檢索優化的查詢分析器IKQueryParser;採用歧義分析算法優化查詢關鍵字的搜索排列組合,能極大的提升Lucene檢索的命中率。

5.3 ElasticSearch集成IK分詞器

5.3.1 IK分詞器的安裝

1)下載地址:https://github.com/medcl/elasticsearch-analysis-ik/releases

課程資料也提供了IK分詞器的壓縮包:

2)解壓,將解壓後的elasticsearch文件夾拷貝到elasticsearch-5.6.8\plugins下,並重命名文件夾爲analysis-ik

3)從新啓動ElasticSearch,便可加載IK分詞器

5.3.2 IK分詞器測試

IK提供了兩個分詞算法ik_smart 和 ik_max_word

其中 ik_smart 爲最少切分,ik_max_word爲最細粒度劃分

咱們分別來試一下

1)最小切分:在瀏覽器地址欄輸入地址

http://127.0.0.1:9200/_analyze?analyzer=ik_smart&pretty=true&text=我是程序員

輸出的結果爲:

{
  "tokens" : [
    {
      "token" : "我",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "CN_CHAR",
      "position" : 0
    },
    {
      "token" : "是",
      "start_offset" : 1,
      "end_offset" : 2,
      "type" : "CN_CHAR",
      "position" : 1
    },
    {
      "token" : "程序員",
      "start_offset" : 2,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 2
    }
  ]
}

2)最細切分:在瀏覽器地址欄輸入地址

http://127.0.0.1:9200/_analyze?analyzer=ik_max_word&pretty=true&text=我是程序員

輸出的結果爲:

{
  "tokens" : [
    {
      "token" : "我",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "CN_CHAR",
      "position" : 0
    },
    {
      "token" : "是",
      "start_offset" : 1,
      "end_offset" : 2,
      "type" : "CN_CHAR",
      "position" : 1
    },
    {
      "token" : "程序員",
      "start_offset" : 2,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "程序",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 3
    },
    {
      "token" : "員",
      "start_offset" : 4,
      "end_offset" : 5,
      "type" : "CN_CHAR",
      "position" : 4
    }
  ]
}

5.4 修改索引映射mapping

5.4.1 重建索引

刪除原有blog1索引

DELETE		localhost:9200/blog1

建立blog1索引,此時分詞器使用ik_max_word

PUT		localhost:9200/blog1
{
    "mappings": {
        "article": {
            "properties": {
                "id": {
                	"type": "long",
                    "store": true,
                    "index":"not_analyzed"
                },
                "title": {
                	"type": "text",
                    "store": true,
                    "index":"analyzed",
                    "analyzer":"ik_max_word"
                },
                "content": {
                	"type": "text",
                    "store": true,
                    "index":"analyzed",
                    "analyzer":"ik_max_word"
                }
            }
        }
    }
}

建立文檔

POST	localhost:9200/blog1/article/1
{
	"id":1,
	"title":"ElasticSearch是一個基於Lucene的搜索服務器",
	"content":"它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並做爲Apache許可條款下的開放源碼發佈,是當前流行的企業級搜索引擎。設計用於雲計算中,可以達到實時搜索,穩定,可靠,快速,安裝使用方便。"
}

5.4.2 再次測試queryString查詢

請求url:

POST	localhost:9200/blog1/article/_search

請求體:

{
    "query": {
        "query_string": {
            "default_field": "title",
            "query": "搜索服務器"
        }
    }
}

postman截圖:

將請求體搜索字符串修改成"鋼索",再次查詢:

{
    "query": {
        "query_string": {
            "default_field": "title",
            "query": "鋼索"
        }
    }
}

postman截圖:

5.4.3 再次測試term測試

請求url:

POST	localhost:9200/blog1/article/_search

請求體:

{
    "query": {
        "term": {
            "title": "搜索"
        }
    }
}

postman截圖:

第六章 ElasticSearch集羣

​ ES集羣是一個 P2P類型(使用 gossip 協議)的分佈式系統,除了集羣狀態管理之外,其餘全部的請求均可以發送到集羣內任意一臺節點上,這個節點能夠本身找到須要轉發給哪些節點,而且直接跟這些節點通訊。因此,從網絡架構及服務配置上來講,構建集羣所須要的配置極其簡單。在 Elasticsearch 2.0 以前,無阻礙的網絡下,全部配置了相同 cluster.name 的節點都自動歸屬到一個集羣中。2.0 版本以後,基於安全的考慮避免開發環境過於隨便形成的麻煩,從 2.0 版本開始,默認的自動發現方式改成了單播(unicast)方式。配置裏提供幾臺節點的地址,ES 將其視做 gossip router 角色,藉以完成集羣的發現。因爲這只是 ES 內一個很小的功能,因此 gossip router 角色並不須要單獨配置,每一個 ES 節點均可以擔任。因此,採用單播方式的集羣,各節點都配置相同的幾個節點列表做爲 router 便可。

​ 集羣中節點數量沒有限制,通常大於等於2個節點就能夠看作是集羣了。通常處於高性能及高可用方面來考慮通常集羣中的節點數量都是3個及3個以上。

6.1 集羣的相關概念

6.1.1 集羣 cluster

一個集羣就是由一個或多個節點組織在一塊兒,它們共同持有整個的數據,並一塊兒提供索引和搜索功能。一個集羣由一個惟一的名字標識,這個名字默認就是「elasticsearch」。這個名字是重要的,由於一個節點只能經過指定某個集羣的名字,來加入這個集羣

6.1.2 節點 node

一個節點是集羣中的一個服務器,做爲集羣的一部分,它存儲數據,參與集羣的索引和搜索功能。和集羣相似,一個節點也是由一個名字來標識的,默認狀況下,這個名字是一個隨機的漫威漫畫角色的名字,這個名字會在啓動的時候賦予節點。這個名字對於管理工做來講挺重要的,由於在這個管理過程當中,你會去肯定網絡中的哪些服務器對應於Elasticsearch集羣中的哪些節點。

一個節點能夠經過配置集羣名稱的方式來加入一個指定的集羣。默認狀況下,每一個節點都會被安排加入到一個叫作「elasticsearch」的集羣中,這意味着,若是你在你的網絡中啓動了若干個節點,並假定它們可以相互發現彼此,它們將會自動地造成並加入到一個叫作「elasticsearch」的集羣中。

在一個集羣裏,只要你想,能夠擁有任意多個節點。並且,若是當前你的網絡中沒有運行任何Elasticsearch節點,這時啓動一個節點,會默認建立並加入一個叫作「elasticsearch」的集羣。

6.1.3 分片和複製 shards&replicas

一個索引能夠存儲超出單個結點硬件限制的大量數據。好比,一個具備10億文檔的索引佔據1TB的磁盤空間,而任一節點都沒有這樣大的磁盤空間;或者單個節點處理搜索請求,響應太慢。爲了解決這個問題,Elasticsearch提供了將索引劃分紅多份的能力,這些份就叫作分片。當你建立一個索引的時候,你能夠指定你想要的分片的數量。每一個分片自己也是一個功能完善而且獨立的「索引」,這個「索引」能夠被放置到集羣中的任何節點上。分片很重要,主要有兩方面的緣由: 1)容許你水平分割/擴展你的內容容量。 2)容許你在分片(潛在地,位於多個節點上)之上進行分佈式的、並行的操做,進而提升性能/吞吐量。

至於一個分片怎樣分佈,它的文檔怎樣聚合回搜索請求,是徹底由Elasticsearch管理的,對於做爲用戶的你來講,這些都是透明的。

在一個網絡/雲的環境裏,失敗隨時均可能發生,在某個分片/節點不知怎麼的就處於離線狀態,或者因爲任何緣由消失了,這種狀況下,有一個故障轉移機制是很是有用而且是強烈推薦的。爲此目的,Elasticsearch容許你建立分片的一份或多份拷貝,這些拷貝叫作複製分片,或者直接叫複製。

複製之因此重要,有兩個主要緣由: 在分片/節點失敗的狀況下,提供了高可用性。由於這個緣由,注意到複製分片從不與原/主要(original/primary)分片置於同一節點上是很是重要的。擴展你的搜索量/吞吐量,由於搜索能夠在全部的複製上並行運行。總之,每一個索引能夠被分紅多個分片。一個索引也能夠被複制0次(意思是沒有複製)或屢次。一旦複製了,每一個索引就有了主分片(做爲複製源的原來的分片)和複製分片(主分片的拷貝)之別。分片和複製的數量能夠在索引建立的時候指定。在索引建立以後,你能夠在任什麼時候候動態地改變複製的數量,可是你過後不能改變分片的數量。

默認狀況下,Elasticsearch中的每一個索引被分片5個主分片和1個複製,這意味着,若是你的集羣中至少有兩個節點,你的索引將會有5個主分片和另外5個複製分片(1個徹底拷貝),這樣的話每一個索引總共就有10個分片。

6.2 集羣的搭建

6.2.1 準備三臺elasticsearch服務器

建立elasticsearch-cluster文件夾,在內部複製三個elasticsearch服務

注意:若是是複製的已經安裝好插件而且使用過的es服務,例如:

而且data文件夾中有數據,須要將複製後的es服務中data文件夾下的文件所有刪除。

6.2.2 修改每臺服務器配置

修改elasticsearch-cluster\node*\config\elasticsearch.yml配置文件

node1節點:

#節點1的配置信息:
#集羣名稱,保證惟一
cluster.name: my-elasticsearch
#節點名稱,必須不同
node.name: node-1
#必須爲本機的ip地址
network.host: 127.0.0.1
#服務端口號,在同一機器下必須不同
http.port: 9200
#集羣間通訊端口號,在同一機器下必須不同
transport.tcp.port: 9300
#設置集羣自動發現機器ip集合
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300","127.0.0.1:9301","127.0.0.1:9302"]

node2節點:

#節點2的配置信息:
#集羣名稱,保證惟一
cluster.name: my-elasticsearch
#節點名稱,必須不同
node.name: node-2
#必須爲本機的ip地址
network.host: 127.0.0.1
#服務端口號,在同一機器下必須不同
http.port: 9201
#集羣間通訊端口號,在同一機器下必須不同
transport.tcp.port: 9301
#設置集羣自動發現機器ip集合
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300","127.0.0.1:9301","127.0.0.1:9302"]

node3節點:

#節點3的配置信息:
#集羣名稱,保證惟一
cluster.name: my-elasticsearch
#節點名稱,必須不同
node.name: node-3
#必須爲本機的ip地址
network.host: 127.0.0.1
#服務端口號,在同一機器下必須不同
http.port: 9202
#集羣間通訊端口號,在同一機器下必須不同
transport.tcp.port: 9302
#設置集羣自動發現機器ip集合
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300","127.0.0.1:9301","127.0.0.1:9302"]

6.2.3 啓動各個節點服務器

雙擊elasticsearch-cluster\node*\bin\elasticsearch.bat

啓動節點1:

啓動節點2:

啓動節點3:

6.2.4 集羣測試

添加索引和映射

PUT		localhost:9200/blog1
{
    "mappings": {
        "article": {
            "properties": {
                "id": {
                	"type": "long",
                    "store": true,
                    "index":"not_analyzed"
                },
                "title": {
                	"type": "text",
                    "store": true,
                    "index":"analyzed",
                    "analyzer":"standard"
                },
                "content": {
                	"type": "text",
                    "store": true,
                    "index":"analyzed",
                    "analyzer":"standard"
                }
            }
        }
    }
}

添加文檔

POST	localhost:9200/blog1/article/1
{
	"id":1,
	"title":"ElasticSearch是一個基於Lucene的搜索服務器",
	"content":"它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並做爲Apache許可條款下的開放源碼發佈,是當前流行的企業級搜索引擎。設計用於雲計算中,可以達到實時搜索,穩定,可靠,快速,安裝使用方便。"
}

使用elasticsearch-header查看集羣狀況

 

ElasticSearch第二部分

第一章 ElasticSearch編程操做

1.1 建立工程,導入座標

pom.xml座標

<dependencies>
    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>5.6.8</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>transport</artifactId>
        <version>5.6.8</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-to-slf4j</artifactId>
        <version>2.9.1</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.24</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>

1.2 建立索引index

@Test
//建立索引
public void test1() throws Exception{
    // 建立Client鏈接對象
    Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
    TransportClient client = new PreBuiltTransportClient(settings)
        .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
    //建立名稱爲blog2的索引
    client.admin().indices().prepareCreate("blog2").get();
    //釋放資源
    client.close();
}

1.3 建立映射mapping

@Test
//建立映射
public void test3() throws Exception{
    // 建立Client鏈接對象
    Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
    TransportClient client = new PreBuiltTransportClient(settings)
        .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
    
    // 添加映射
    /**
         * 格式:
         * "mappings" : {
             "article" : {
                "dynamic" : "false",
                 "properties" : {
                    "id" : { "type" : "string" },
                     "content" : { "type" : "string" },
                    "author" : { "type" : "string" }
                 }
            }
         }
         */
    XContentBuilder builder = XContentFactory.jsonBuilder()
        .startObject()
        .startObject("article")
        .startObject("properties")
        .startObject("id")
        .field("type", "integer").field("store", "yes")
        .endObject()
        .startObject("title")
        .field("type", "string").field("store", "yes").field("analyzer", "ik_smart")
        .endObject()
        .startObject("content")
        .field("type", "string").field("store", "yes").field("analyzer", "ik_smart")
        .endObject()
        .endObject()
        .endObject()
        .endObject();
    // 建立映射
    PutMappingRequest mapping = Requests.putMappingRequest("blog2")
        .type("article").source(builder);
    client.admin().indices().putMapping(mapping).get();
    //釋放資源
    client.close();
}

1.4 創建文檔document

1.4.1 創建文檔(經過XContentBuilder)

@Test
//建立文檔(經過XContentBuilder)
public void test4() throws Exception{
    // 建立Client鏈接對象
    Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
    TransportClient client = new PreBuiltTransportClient(settings)
        .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));

    //建立文檔信息
    XContentBuilder builder = XContentFactory.jsonBuilder()
        .startObject()
        .field("id", 1)
        .field("title", "ElasticSearch是一個基於Lucene的搜索服務器")
        .field("content",
               "它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並做爲Apache許可條款下的開放源碼發佈,是當前流行的企業級搜索引擎。設計用於雲計算中,可以達到實時搜索,穩定,可靠,快速,安裝使用方便。")
        .endObject();

    // 創建文檔對象
    /**
         * 參數一blog1:表示索引對象
         * 參數二article:類型
         * 參數三1:創建id
         */
    client.prepareIndex("blog2", "article", "1").setSource(builder).get();

    //釋放資源
    client.close();
}

1.4.2 創建文檔(使用Jackson轉換實體)

1)建立Article實體

public class Article {
	private Integer id;
	private String title;
	private String content;
    getter/setter...
}

2)添加jackson座標

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.8.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.8.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.8.1</version>
</dependency>

3)代碼實現

@Test
//建立文檔(經過實體轉json)
public void test5() throws Exception{
    // 建立Client鏈接對象
    Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
    TransportClient client = new PreBuiltTransportClient(settings)
        .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));

    // 描述json 數據
    //{id:xxx, title:xxx, content:xxx}
    Article article = new Article();
    article.setId(2);
    article.setTitle("搜索工做其實很快樂");
    article.setContent("咱們但願咱們的搜索解決方案要快,咱們但願有一個零配置和一個徹底免費的搜索模式,咱們但願可以簡單地使用JSON經過HTTP的索引數據,咱們但願咱們的搜索服務器始終可用,咱們但願可以一臺開始並擴展到數百,咱們要實時搜索,咱們要簡單的多租戶,咱們但願創建一個雲的解決方案。Elasticsearch旨在解決全部這些問題和更多的問題。");

    ObjectMapper objectMapper = new ObjectMapper();

    // 創建文檔
    client.prepareIndex("blog2", "article", article.getId().toString())
        //.setSource(objectMapper.writeValueAsString(article)).get();
        .setSource(objectMapper.writeValueAsString(article).getBytes(), XContentType.JSON).get();

    //釋放資源
    client.close();
}

1.5 查詢文檔操做

1.5.1關鍵詞查詢

@Test
public void testTermQuery() throws Exception{
    //一、建立es客戶端鏈接對象
    Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
    TransportClient client = new PreBuiltTransportClient(settings)
        .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));

    //二、設置搜索條件
    SearchResponse searchResponse = client.prepareSearch("blog2")
        .setTypes("article")
        .setQuery(QueryBuilders.termQuery("content", "搜索")).get();

    //三、遍歷搜索結果數據
    SearchHits hits = searchResponse.getHits(); // 獲取命中次數,查詢結果有多少對象
    System.out.println("查詢結果有:" + hits.getTotalHits() + "條");
    Iterator<SearchHit> iterator = hits.iterator();
    while (iterator.hasNext()) {
        SearchHit searchHit = iterator.next(); // 每一個查詢對象
        System.out.println(searchHit.getSourceAsString()); // 獲取字符串格式打印
        System.out.println("title:" + searchHit.getSource().get("title"));
    }

    //四、釋放資源
    client.close();

}

2.5.2 字符串查詢

@Test
public void testStringQuery() throws Exception{
    //一、建立es客戶端鏈接對象
    Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
    TransportClient client = new PreBuiltTransportClient(settings)
        .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));

    //二、設置搜索條件
    SearchResponse searchResponse = client.prepareSearch("blog2")
        .setTypes("article")
        .setQuery(QueryBuilders.queryStringQuery("搜索")).get();

    //三、遍歷搜索結果數據
    SearchHits hits = searchResponse.getHits(); // 獲取命中次數,查詢結果有多少對象
    System.out.println("查詢結果有:" + hits.getTotalHits() + "條");
    Iterator<SearchHit> iterator = hits.iterator();
    while (iterator.hasNext()) {
        SearchHit searchHit = iterator.next(); // 每一個查詢對象
        System.out.println(searchHit.getSourceAsString()); // 獲取字符串格式打印
        System.out.println("title:" + searchHit.getSource().get("title"));
    }

    //四、釋放資源
    client.close();

}

2.5.2 使用文檔ID查詢文檔

@Test
    public void testIdQuery() throws Exception {
        //client對象爲TransportClient對象
        SearchResponse response = client.prepareSearch("blog1")
                .setTypes("article")
                //設置要查詢的id
                .setQuery(QueryBuilders.idsQuery().addIds("test002"))
                //執行查詢
                .get();
        //取查詢結果
        SearchHits searchHits = response.getHits();
        //取查詢結果總記錄數
        System.out.println(searchHits.getTotalHits());
        Iterator<SearchHit> hitIterator = searchHits.iterator();
        while(hitIterator.hasNext()) {
            SearchHit searchHit = hitIterator.next();
            //打印整行數據
            System.out.println(searchHit.getSourceAsString());
        }
    }

2.6 查詢文檔分頁操做

2.6.1 批量插入數據

@Test
//批量插入100條數據
public void test9() throws Exception{
    	// 建立Client鏈接對象
        Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
        TransportClient client = new PreBuiltTransportClient(settings)
                .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));

        ObjectMapper objectMapper = new ObjectMapper();

        for (int i = 1; i <= 100; i++) {
            // 描述json 數據
            Article article = new Article();
            article.setId(i);
            article.setTitle(i + "搜索工做其實很快樂");
            article.setContent(i
                    + "咱們但願咱們的搜索解決方案要快,咱們但願有一個零配置和一個徹底免費的搜索模式,咱們但願可以簡單地使用JSON經過HTTP的索引數據,咱們但願咱們的搜索服務器始終可用,咱們但願可以一臺開始並擴展到數百,咱們要實時搜索,咱們要簡單的多租戶,咱們但願創建一個雲的解決方案。Elasticsearch旨在解決全部這些問題和更多的問題。");

            // 創建文檔
            client.prepareIndex("blog2", "article", article.getId().toString())
                    //.setSource(objectMapper.writeValueAsString(article)).get();
                    .setSource(objectMapper.writeValueAsString(article).getBytes(),XContentType.JSON).get();
        }

        //釋放資源
        client.close();
}

2.6.2 分頁查詢

@Test
//分頁查詢
public void test10() throws Exception{
    // 建立Client鏈接對象
    Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
    TransportClient client = new PreBuiltTransportClient(settings)
        .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));

    // 搜索數據
    SearchRequestBuilder searchRequestBuilder = client.prepareSearch("blog2").setTypes("article")
        .setQuery(QueryBuilders.matchAllQuery());//默認每頁10條記錄

    // 查詢第2頁數據,每頁20條
    //setFrom():從第幾條開始檢索,默認是0。
    //setSize():每頁最多顯示的記錄數。
    searchRequestBuilder.setFrom(0).setSize(5);
    SearchResponse searchResponse = searchRequestBuilder.get();

    SearchHits hits = searchResponse.getHits(); // 獲取命中次數,查詢結果有多少對象
    System.out.println("查詢結果有:" + hits.getTotalHits() + "條");
    Iterator<SearchHit> iterator = hits.iterator();
    while (iterator.hasNext()) {
        SearchHit searchHit = iterator.next(); // 每一個查詢對象
        System.out.println(searchHit.getSourceAsString()); // 獲取字符串格式打印
        System.out.println("id:" + searchHit.getSource().get("id"));
        System.out.println("title:" + searchHit.getSource().get("title"));
        System.out.println("content:" + searchHit.getSource().get("content"));
        System.out.println("-----------------------------------------");
    }

    //釋放資源
    client.close();
}

2.7 查詢結果高亮操做

2.7.1 什麼是高亮顯示

在進行關鍵字搜索時,搜索出的內容中的關鍵字會顯示不一樣的顏色,稱之爲高亮

百度搜索關鍵字"傳智播客"

京東商城搜索"筆記本"

2.7.2 高亮顯示的html分析

經過開發者工具查看高亮數據的html代碼實現:

ElasticSearch能夠對查詢出的內容中關鍵字部分進行標籤和樣式的設置,可是你須要告訴ElasticSearch使用什麼標籤對高亮關鍵字進行包裹

2.7.3 高亮顯示代碼實現

@Test
//高亮查詢
public void test11() throws Exception{
    // 建立Client鏈接對象
    Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
    TransportClient client = new PreBuiltTransportClient(settings)
        .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));

    // 搜索數據
    SearchRequestBuilder searchRequestBuilder = client
        .prepareSearch("blog2").setTypes("article")
        .setQuery(QueryBuilders.termQuery("title", "搜索"));

    //設置高亮數據
    HighlightBuilder hiBuilder=new HighlightBuilder();
    hiBuilder.preTags("<font style='color:red'>");
    hiBuilder.postTags("</font>");
    hiBuilder.field("title");
    searchRequestBuilder.highlighter(hiBuilder);

    //得到查詢結果數據
    SearchResponse searchResponse = searchRequestBuilder.get();

    //獲取查詢結果集
    SearchHits searchHits = searchResponse.getHits();
    System.out.println("共搜到:"+searchHits.getTotalHits()+"條結果!");
    //遍歷結果
    for(SearchHit hit:searchHits){
        System.out.println("String方式打印文檔搜索內容:");
        System.out.println(hit.getSourceAsString());
        System.out.println("Map方式打印高亮內容");
        System.out.println(hit.getHighlightFields());

        System.out.println("遍歷高亮集合,打印高亮片斷:");
        Text[] text = hit.getHighlightFields().get("title").getFragments();
        for (Text str : text) {
            System.out.println(str);
        }
    }

    //釋放資源
    client.close();
}

第三章 Spring Data ElasticSearch 使用

3.1 Spring Data ElasticSearch簡介

3.1.1 什麼是Spring Data

Spring Data是一個用於簡化數據庫訪問,並支持雲服務的開源框架。其主要目標是使得對數據的訪問變得方便快捷,並支持map-reduce框架和雲計算數據服務。 Spring Data能夠極大的簡化JPA的寫法,能夠在幾乎不用寫實現的狀況下,實現對數據的訪問和操做。除了CRUD外,還包括如分頁、排序等一些經常使用的功能。

Spring Data的官網:http://projects.spring.io/spring-data/

Spring Data經常使用的功能模塊以下:

3.1.2 什麼是Spring Data ElasticSearch

Spring Data ElasticSearch 基於 spring data API 簡化 elasticSearch操做,將原始操做elasticSearch的客戶端API 進行封裝 。Spring Data爲Elasticsearch項目提供集成搜索引擎。Spring Data Elasticsearch POJO的關鍵功能區域爲中心的模型與Elastichsearch交互文檔和輕鬆地編寫一個存儲庫數據訪問層。

官方網站:http://projects.spring.io/spring-data-elasticsearch/

3.2 Spring Data ElasticSearch入門

1)導入Spring Data ElasticSearch座標

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.itheima</groupId>
    <artifactId>itheima_elasticsearch_demo3</artifactId>
    <version>1.0-SNAPSHOT</version>


    <dependencies>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>5.6.8</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>5.6.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-to-slf4j</artifactId>
            <version>2.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.24</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>


        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.8.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.8.1</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-elasticsearch</artifactId>
            <version>3.0.5.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>org.elasticsearch.plugin</groupId>
                    <artifactId>transport-netty4-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.4.RELEASE</version>
        </dependency>

    </dependencies>
    
</project>

2)建立applicationContext.xml配置文件,引入elasticsearch命名空間

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/data/elasticsearch
		http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
		">
		
</beans>

3)編寫實體Article

package com.itheima.domain;

public class Article {

    private Integer id;
    private String title;
    private String content;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    @Override
    public String toString() {
        return "Article [id=" + id + ", title=" + title + ", content=" + content + "]";
    }

}

4)編寫Dao

package com.itheima.dao;

import com.itheima.domain.Article;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

@Repository
public interface ArticleRepository extends ElasticsearchRepository<Article, Integer> {

}

5)編寫Service

package com.itheima.service;

import com.itheima.domain.Article;

public interface ArticleService {

    public void save(Article article);
    
}
package com.itheima.service.impl;

import com.itheima.dao.ArticleRepository;
import com.itheima.domain.Article;
import com.itheima.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleRepository articleRepository;

    public void save(Article article) {
        articleRepository.save(article);
    }

}

6) 配置applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
       xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/data/elasticsearch
		http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
		">
    
    <!-- 掃描Dao包,自動建立實例 -->
    <elasticsearch:repositories base-package="com.itheima.dao"/>

    <!-- 掃描Service包,建立Service的實體 -->
    <context:component-scan base-package="com.itheima.service"/>

    <!-- 配置elasticSearch的鏈接 -->
        <!-- 配置elasticSearch的鏈接 -->
    <elasticsearch:transport-client id="client" cluster-nodes="localhost:9300" cluster-name="my-elasticsearch"/>


    <!-- ElasticSearch模版對象 -->
    <bean id="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
        <constructor-arg name="client" ref="client"></constructor-arg>
    </bean>
    
</beans>

7)配置實體

基於spring data elasticsearch註解配置索引、映射和實體的關係

package com.itheima.domain;

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

//@Document 文檔對象 (索引信息、文檔類型 )
@Document(indexName="blog3",type="article")
public class Article {

    //@Id 文檔主鍵 惟一標識
    @Id
    //@Field 每一個文檔的字段配置(類型、是否分詞、是否存儲、分詞器 )
    @Field(store=true, index = false,type = FieldType.Integer)
    private Integer id;
    @Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text)
    private String title;
    @Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text)
    private String content;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    @Override
    public String toString() {
        return "Article [id=" + id + ", title=" + title + ", content=" + content + "]";
    }

}
其中,註解解釋以下:
@Document(indexName="blob3",type="article"):
    indexName:索引的名稱(必填項)
    type:索引的類型
@Id:主鍵的惟一標識
@Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text)
    index:是否設置分詞
    analyzer:存儲時使用的分詞器
    searchAnalyze:搜索時使用的分詞器
    store:是否存儲
    type: 數據類型

8)建立測試類SpringDataESTest

package com.itheima.test;

import com.itheima.domain.Article;
import com.itheima.service.ArticleService;
import org.elasticsearch.client.transport.TransportClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataESTest {

    @Autowired
    private ArticleService articleService;

    @Autowired
    private TransportClient client;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**建立索引和映射*/
    @Test
    public void createIndex(){
        elasticsearchTemplate.createIndex(Article.class);
        elasticsearchTemplate.putMapping(Article.class);
    }

    /**測試保存文檔*/
    @Test
    public void saveArticle(){
        Article article = new Article();
        article.setId(100);
        article.setTitle("測試SpringData ElasticSearch");
        article.setContent("Spring Data ElasticSearch 基於 spring data API 簡化 elasticSearch操做,將原始操做elasticSearch的客戶端API 進行封裝 \n" +
                "    Spring Data爲Elasticsearch Elasticsearch項目提供集成搜索引擎");
        articleService.save(article);
    }

}

3.3 Spring Data ElasticSearch的經常使用操做

3.3.1 增刪改查方法測試

package com.itheima.service;

import com.itheima.domain.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface ArticleService {

    //保存
    public void save(Article article);
    //刪除
    public void delete(Article article);
    //查詢所有
    public Iterable<Article> findAll();
    //分頁查詢
    public Page<Article> findAll(Pageable pageable);

}
package com.itheima.service.impl;

import com.itheima.dao.ArticleRepository;
import com.itheima.domain.Article;
import com.itheima.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;


@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleRepository articleRepository;

    public void save(Article article) {
        articleRepository.save(article);
    }

    public void delete(Article article) {
        articleRepository.delete(article);
    }

    public Iterable<Article> findAll() {
        Iterable<Article> iter = articleRepository.findAll();
        return iter;
    }

    public Page<Article> findAll(Pageable pageable) {
        return articleRepository.findAll(pageable);
    }
}
package com.itheima.test;

import com.itheima.domain.Article;
import com.itheima.service.ArticleService;
import org.elasticsearch.client.transport.TransportClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataESTest {

    @Autowired
    private ArticleService articleService;

    @Autowired
    private TransportClient client;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**建立索引和映射*/
    @Test
    public void createIndex(){
        elasticsearchTemplate.createIndex(Article.class);
        elasticsearchTemplate.putMapping(Article.class);
    }

    /**測試保存文檔*/
    @Test
    public void saveArticle(){
        Article article = new Article();
        article.setId(100);
        article.setTitle("測試SpringData ElasticSearch");
        article.setContent("Spring Data ElasticSearch 基於 spring data API 簡化 elasticSearch操做,將原始操做elasticSearch的客戶端API 進行封裝 \n" +
                "    Spring Data爲Elasticsearch Elasticsearch項目提供集成搜索引擎");
        articleService.save(article);
    }

    /**測試保存*/
    @Test
    public void save(){
        Article article = new Article();
        article.setId(1001);
        article.setTitle("elasticSearch 3.0版本發佈");
        article.setContent("ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口");
        articleService.save(article);
    }

    /**測試更新*/
    @Test
    public void update(){
        Article article = new Article();
        article.setId(1001);
        article.setTitle("elasticSearch 3.0版本發佈...更新");
        article.setContent("ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口");
        articleService.save(article);
    }

    /**測試刪除*/
    @Test
    public void delete(){
        Article article = new Article();
        article.setId(1001);
        articleService.delete(article);
    }

    /**批量插入*/
    @Test
    public void save100(){
        for(int i=1;i<=100;i++){
            Article article = new Article();
            article.setId(i);
            article.setTitle(i+"elasticSearch 3.0版本發佈..,更新");
            article.setContent(i+"ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口");
            articleService.save(article);
        }
    }

    /**分頁查詢*/
    @Test
    public void findAllPage(){
        Pageable pageable = PageRequest.of(1,10);
        Page<Article> page = articleService.findAll(pageable);
        for(Article article:page.getContent()){
            System.out.println(article);
        }
    }
}

3.3.2 經常使用查詢命名規則

關鍵字 命名規則 解釋 示例
and findByField1AndField2 根據Field1和Field2得到數據 findByTitleAndContent
or findByField1OrField2 根據Field1或Field2得到數據 findByTitleOrContent
is findByField 根據Field得到數據 findByTitle
not findByFieldNot 根據Field得到補集數據 findByTitleNot
between findByFieldBetween 得到指定範圍的數據 findByPriceBetween
lessThanEqual findByFieldLessThan 得到小於等於指定值的數據 findByPriceLessThan

3.3.3 查詢方法測試

1)dao層實現

package com.itheima.dao;

import com.itheima.domain.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;

public interface ArticleRepository extends ElasticsearchRepository<Article, Integer> {
    //根據標題查詢
    List<Article> findByTitle(String condition);
    //根據標題查詢(含分頁)
    Page<Article> findByTitle(String condition, Pageable pageable);
}

2)service層實現

public interface ArticleService {
    //根據標題查詢
    List<Article> findByTitle(String condition);
    //根據標題查詢(含分頁)
    Page<Article> findByTitle(String condition, Pageable pageable);
}
package com.itheima.service.impl;

import com.itheima.dao.ArticleRepository;
import com.itheima.domain.Article;
import com.itheima.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleRepository articleRepository;

    public List<Article> findByTitle(String condition) {
        return articleRepository.findByTitle(condition);
    }
    public Page<Article> findByTitle(String condition, Pageable pageable) {
        return articleRepository.findByTitle(condition,pageable);
    }

}

3)測試代碼

package com.itheima.test;

import com.itheima.domain.Article;
import com.itheima.service.ArticleService;
import org.elasticsearch.client.transport.TransportClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataESTest {

    @Autowired
    private ArticleService articleService;

    @Autowired
    private TransportClient client;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**條件查詢*/
    @Test
    public void findByTitle(){
        String condition = "版本";
        List<Article> articleList = articleService.findByTitle(condition);
        for(Article article:articleList){
            System.out.println(article);
        }
    }

    /**條件分頁查詢*/
    @Test
    public void findByTitlePage(){
        String condition = "版本";
        Pageable pageable = PageRequest.of(2,10);
        Page<Article> page = articleService.findByTitle(condition,pageable);
        for(Article article:page.getContent()){
            System.out.println(article);
        }
    }

}

###3.3.4使用Elasticsearch的原生查詢對象進行查詢。

@Test
    public void findByNativeQuery() {
        //建立一個SearchQuery對象
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                //設置查詢條件,此處可使用QueryBuilders建立多種查詢
                .withQuery(QueryBuilders.queryStringQuery("備份節點上沒有數據").defaultField("title"))
                //還能夠設置分頁信息
                .withPageable(PageRequest.of(1, 5))
                //建立SearchQuery對象
                .build();


        //使用模板對象執行查詢
        elasticsearchTemplate.queryForList(searchQuery, Article.class)
                .forEach(a-> System.out.println(a));
    }
相關文章
相關標籤/搜索