Elaticsearch,簡稱爲es, es是一個開源的高擴展的分佈式全文檢索引擎,它能夠近乎實時的存儲、檢索數據;本
身擴展性很好,能夠擴展到上百臺服務器,處理PB級別的數據。es也使用Java開發並使用Lucene做爲其核心來實
現全部索引和搜索的功能,可是它的目的是經過簡單的RESTful API來隱藏Lucene的複雜性,從而讓全文搜索變得
簡單。
下載es的安裝包java
ElasticSearch分爲Linux和Window版本 ,ElasticSearch的官方地址: https://www.elastic.co/products/elasticsearch
node
安裝Win版es服務git
Window版的ElasticSearch的安裝很簡單,相似Window版的Tomcat,解壓開即安裝完畢,解壓後的ElasticSearch
的目錄結構以下:
程序員
啓動ES服務github
點擊ElasticSearch下的bin目錄下的elasticsearch.bat啓動,控制檯顯示的日誌信息以下:
web
能夠看到綁定了兩個端口: - 9300:集羣節點間通信接口,接收tcp協議 - 9200:客戶端訪問接口,接收Http協議
注意:算法
修改 config/jvm.options
把內存改成1g
經過瀏覽器訪問ElasticSearch服務器,看到以下返回的json信息,表明服務啓動成功
數據庫
注意:ElasticSearch是使用java開發的,且本版本的es須要的jdk版本要是1.8以上,因此安裝ElasticSearch
以前保證JDK1.8+安裝完畢,並正確的配置好JDK環境變量,不然啓動ElasticSearch失敗。
安裝ES的圖形化界面插件apache
ElasticSearch不一樣於Solr自帶圖形化界面,咱們能夠經過安裝ElasticSearch的head插件,完成圖形化界面的效果,
完成索引數據的查看。安裝插件的方式有兩種,在線安裝和本地安裝。本文檔採用本地安裝方式進行head插件的
安裝。elasticsearch-5-*以上版本安裝head須要安裝node和grunt
npm
1.安裝圖形化界面head插件
下載head插件:https://github.com/mobz/elasticsearch-head
解壓elasticsearch-head-master.zip到任意目錄,可是要和elasticsearch的安裝目錄區別開
2.安裝nodejs程序
https://nodejs.org/en/download/
node-v8.9.4-x64.msi
3.安裝head依賴,將grunt安裝爲全局命令 ,Grunt是基於Node.js的項目構建工具
cmd控制檯中輸入: npm install -g grunt-cli
cmd進入到head目錄中執行 npm install
4.修改elasticsearch配置文件:elasticsearch.yml,增長如下兩句命令:
http.cors.enabled: true http.cors.allow-origin: "*"
此步爲容許elasticsearch跨越訪問
5.進入head目錄啓動head,在命令提示符下輸入命令:
grunt server 注:每次使用都要執行
爲了方便咱們能夠在head目錄下建立文本文檔輸入:grunt server 把它文件名及類型改成head.bat
6.打開瀏覽器,輸入 http://localhost:9100,看到以下頁面:
擴展:測試集羣
繼續安裝一個ES(解壓便可)-->修改內存-->容許跨域-->所有重啓-->測試
ElasticSearch概述
Elasticsearch是面向文檔(document oriented)的,這意味着它能夠存儲整個對象或文檔(document)。然而它不只
僅是存儲,還會索引(index)每一個文檔的內容使之能夠被搜索。在Elasticsearch中,你能夠對文檔(而非成行成列的
數據)進行索引、搜索、排序、過濾。ES比傳統關係型數據庫,就像以下:
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields
接近實時NRT
Elasticsearch是一個接近實時的搜索平臺。這意味着,從索引一個文檔直到這個文檔可以被搜索到有一個輕微的延
遲(一般是1秒之內)
集羣cluster
一個集羣就是由一個或多個節點組織在一塊兒,它們共同持有整個的數據,並一塊兒提供索引和搜索功能。一個集羣由
一個惟一的名字標識,這個名字默認就是「elasticsearch」。這個名字是重要的,由於一個節點只能經過指定某個集
羣的名字,來加入這個集羣
節點node
一個節點是集羣中的一個服務器,做爲集羣的一部分,它存儲數據,參與集羣的索引和搜索功能。和集羣相似,一
個節點也是由一個名字來標識的,默認狀況下,這個名字是一個隨機的漫威漫畫角色的名字,這個名字會在啓動的
時候賦予節點。這個名字對於管理工做來講挺重要的,由於在這個管理過程當中,你會去肯定網絡中的哪些服務器對
應於Elasticsearch集羣中的哪些節點。
一個節點能夠經過配置集羣名稱的方式來加入一個指定的集羣。默認狀況下,每一個節點都會被安排加入到一個叫
作「elasticsearch」的集羣中,這意味着,若是你在你的網絡中啓動了若干個節點,並假定它們可以相互發現彼此,
它們將會自動地造成並加入到一個叫作「elasticsearch」的集羣中。
在一個集羣裏,只要你想,能夠擁有任意多個節點。並且,若是當前你的網絡中沒有運行任何Elasticsearch節點,
這時啓動一個節點,會默認建立並加入一個叫作「elasticsearch」的集羣。
索引index
一個索引就是一個擁有幾分類似特徵的文檔的集合。好比說,你能夠有一個客戶數據的索引,另外一個產品目錄的索
引,還有一個訂單數據的索引。一個索引由一個名字來標識(必須所有是小寫字母的),而且當咱們要對對應於這
個索引中的文檔進行索引、搜索、更新和刪除的時候,都要使用到這個名字。在一個集羣中,能夠定義任意多的索
引
類型type
在一個索引中,你能夠定義一種或多種類型。一個類型是你的索引的一個邏輯上的分類/分區,其語義徹底由你來
定。一般,會爲具備一組共同字段的文檔定義一個類型。好比說,咱們假設你運營一個博客平臺而且將你全部的數
據存儲到一個索引中。在這個索引中,你能夠爲用戶數據定義一個類型,爲博客數據定義另外一個類型,固然,也可
覺得評論數據定義另外一個類型。
文檔document
一個文檔是一個可被索引的基礎信息單元。好比,你能夠擁有某一個客戶的文檔,某一個產品的一個文檔,固然, 也能夠擁有某個訂單的一個文檔。文檔以JSON(Javascript Object Notation)格式來表示,而JSON是一個處處存 在的互聯網數據交互格式。 在一個index/type裏面,你能夠存儲任意多的文檔。注意,儘管一個文檔,物理上存在於一個索引之中,文檔必須 被索引/賦予一個索引的type。
分片和複製 shards&replicas
一個索引能夠存儲超出單個結點硬件限制的大量數據。好比,一個具備10億文檔的索引佔據1TB的磁盤空間,而任 一節點都沒有這樣大的磁盤空間;或者單個節點處理搜索請求,響應太慢。爲了解決這個問題,Elasticsearch提供 了將索引劃分紅多份的能力,這些份就叫作分片。當你建立一個索引的時候,你能夠指定你想要的分片的數量。每 個分片自己也是一個功能完善而且獨立的「索引」,這個「索引」能夠被放置到集羣中的任何節點上。分片很重要,主 要有兩方面的緣由: 1)容許你水平分割/擴展你的內容容量。 2)容許你在分片(潛在地,位於多個節點上)之上 進行分佈式的、並行的操做,進而提升性能/吞吐量。 至於一個分片怎樣分佈,它的文檔怎樣聚合回搜索請求,是徹底由Elasticsearch管理的,對於做爲用戶的你來講, 這些都是透明的。 在一個網絡/雲的環境裏,失敗隨時均可能發生,在某個分片/節點不知怎麼的就處於離線狀態,或者因爲任何緣由 消失了,這種狀況下,有一個故障轉移機制是很是有用而且是強烈推薦的。爲此目的,Elasticsearch容許你建立分 片的一份或多份拷貝,這些拷貝叫作複製分片,或者直接叫複製。
複製之因此重要,有兩個主要緣由: 在分片/節點失敗的狀況下,提供了高可用性。由於這個緣由,注意到複製分 片從不與原/主要(original/primary)分片置於同一節點上是很是重要的。擴展你的搜索量/吞吐量,由於搜索能夠 在全部的複製上並行運行。總之,每一個索引能夠被分紅多個分片。一個索引也能夠被複制0次(意思是沒有複製) 或屢次。一旦複製了,每一個索引就有了主分片(做爲複製源的原來的分片)和複製分片(主分片的拷貝)之別。分 片和複製的數量能夠在索引建立的時候指定。在索引建立以後,你能夠在任什麼時候候動態地改變複製的數量,可是你 過後不能改變分片的數量。 默認狀況下,Elasticsearch中的每一個索引被分片5個主分片和1個複製,這意味着,若是你的集羣中至少有兩個節 點,你的索引將會有5個主分片和另外5個複製分片(1個徹底拷貝),這樣的話每一個索引總共就有10個分片
映射mapping
mapping是處理數據的方式和規則方面作一些限制,如某個字段的數據類型、默認值、分析器、是否被索引等等,
這些都是映射裏面能夠設置的,其它就是處理es裏面數據的一些使用規則設置也叫作映射,按着最優規則處理數據
對性能提升很大,所以才須要創建映射,而且須要思考如何創建映射才能對性能更好?和創建表結構表關係數據庫
三範式相似。
建立maven工程
引入座標
<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.10</version> </dependency> </dependencies>
新建索引
@Test//建立索引庫及添加文檔 public void test1() throws Exception { //1.建立客戶端訪問對象 TransportClient client=new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300)); //2.建立文檔 //{id:"1",title:"xxx",content:"xxxxxx"} XContentBuilder builder= XContentFactory.jsonBuilder() .startObject() .field("id","1") .field("title","ElasticSearch是一個基於Lucene的搜索服務器") .field("content","它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並做爲Apache許可條款下的開放源碼發佈,是當前流行的企業級搜索引擎。") .endObject(); //3.建立索引庫及添加文檔 client.prepareIndex("blog1","article","1").setSource(builder).get(); //4.關閉資源 client.close(); }
搜索文檔數據
查詢所有
@Test//查詢所有 public void test2() throws Exception { //建立客戶端訪問對象 TransportClient client=new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300)); //建立查詢對象 SearchResponse searchResponse=client.prepareSearch("blog1").setTypes("article").setQuery(QueryBuilders.matchAllQuery()) .get(); //處理查詢結果 SearchHits hits=searchResponse.getHits();//表示查詢到的文檔 System.out.println("查詢到了"+hits.totalHits+"個文檔"); //迭代器遍歷 Iterator<SearchHit> iterator = hits.iterator(); while (iterator.hasNext()){ SearchHit hit = iterator.next();//拿到一個文檔對象 System.out.println(hit.getSourceAsString()); System.out.println(hit.getSource().get("title")); } //關閉資源 client.close(); }
字符串查詢
查詢所有的代碼不變,只需改正建立對象便可
//二、建立查詢對象,並返回結果 SearchResponse searchResponse = client.prepareSearch("blog1").setTypes("article")
.setQuery(QueryBuilders.queryStringQuery("提供")).get();
詞條查詢
查詢所有的代碼不變,只需改正建立對象便可
//二、建立查詢對象,並返回結果 SearchResponse searchResponse = client.prepareSearch("blog1").setTypes("article")
.setQuery(QueryBuilders.termQuery("title","搜索")).get();
模糊查詢
查詢所有的代碼不變,只需改正建立對象便可
//二、建立查詢對象,並返回結果 SearchResponse searchResponse = client.prepareSearch("blog1").setTypes("article")
.setQuery(QueryBuilders.wildcardQuery("title","*搜索*")).get();
ik分詞器的安裝
下載地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
解壓
將解壓後的文件夾拷貝到elasticsearch-5.6.8\plugins下,並重命名文件夾爲ik
從新啓動ElasticSearch,便可加載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=我是程序員
輸出的結果爲:
2)最細切分:在瀏覽器地址欄輸入地址
http://127.0.0.1:9200/_analyze?analyzer=ik_max_word&pretty=true&text=我是程序員
輸出的結果爲
建立索引
@Test //建立索引庫 public void test1() throws Exception { //一、建立客戶端訪問對象 TransportClient client = new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300)); //二、建立索引 index //client.admin().indices().prepareCreate("blog2").get(); client.admin().indices().prepareDelete("blog2").get(); //三、關閉資源 client.close(); }
刪除索引
映射相關操做
建立映射
@Test
//建立映射
public void test2() throws Exception {
//1.建立客戶端訪問對象
TransportClient client=new PreBuiltTransportClient(Settings.EMPTY)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300));
//建立索引
client.admin().indices().prepareCreate("blog2").get();
/*** 格式:
* "mappings" : {
"article" : {
"properties" : {
"id" : { "type" : "string" },
"content" : { "type" : "string" },
"title" : { "type" : "string" }
}
}
}
*/
//建立映射
XContentBuilder builder= XContentFactory.jsonBuilder()
.startObject()
.startObject("article")
.startObject("properties")
.startObject("id")
.field("type","long")
.field("store","long")
.endObject()
.startObject("title")
.field("type","string")
.field("store","true")
.field("analyzer","ik_smart")
.endObject()
.startObject("content")
.field("type","string")
.field("store","true")
.field("analyzer","ik_smart")
.endObject()
.endObject()
.endObject()
.endObject();
//創建與索引庫和type的關係
PutMappingRequest mappingRequest= Requests.putMappingRequest("blog2").type("article").source(builder);
//執行
client.admin().indices().putMapping(mappingRequest).get();
//關閉資源
client.close();
}
創建文檔(經過XContentBuilder)
@Test //建立索引庫及添加文檔 public void test3() throws Exception { //一、建立客戶端訪問對象 TransportClient client = new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300)); //二、建立文檔對象 //{id:"1",title:"xxx",content:"xxxxxx"} XContentBuilder builder = XContentFactory.jsonBuilder() .startObject() .field("id","1") .field("title","ElasticSearch是一個基於Lucene的搜索服務器。") .field("content","它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並做爲Apache許可條款下的開放源碼發佈,是當前流行的企業級搜索引擎。設計用於雲計算中,可以達到實時搜索,穩定,可靠,快速,安裝使用方便。官方客戶端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和許多其餘語言中都是可用的。根據DB-Engines的排名顯示,Elasticsearch是最受歡迎的企業搜索引擎,其次是Apache Solr,也是基於Lucene。") .endObject(); //三、建立索引庫及添加文檔 client.prepareIndex("blog2", "article", "1").setSource(builder).get(); //四、關閉資源 client.close(); }
創建文檔(使用Jackson轉換實體)
建立Article實體
public class Article { private Integer id; private String title; private String content; getter/setter... }
引入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>
代碼實現
@Test //建立文檔(經過實體轉json) public void test5() throws Exception { //一、建立客戶端訪問對象 TransportClient client = new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300)); //二、建立文檔對象 Article a = new Article(); a.setId(2L); a.setTitle("搜索工做其實很快樂"); a.setContent("咱們但願咱們的搜索解決方案要快,咱們但願有一個零配置和一個徹底免費的搜索模\n" + "式,咱們但願可以簡單地使用JSON經過HTTP的索引數據,咱們但願咱們的搜索服務器始終可用,咱們但願可以一臺開\n" + "始並擴展到數百,咱們要實時搜索,咱們要簡單的多租戶,咱們但願創建一個雲的解決方案。Elasticsearch旨在解\n" + "決全部這些問題和更多的問題。"); //3.建立一個json轉換器 ObjectMapper mapper =new ObjectMapper(); //四、建立索引庫及添加文檔 {id:xxx, title:xxx, content:xxx} client.prepareIndex("blog2", "article", a.getId()+"").setSource(mapper.writeValueAsString(a)).get(); //五、關閉資源 client.close(); }
更改文檔
在建立文檔代碼基礎上更改步驟4 //方式一 client.prepareUpdate("blog2", "article", a.getId()+"").setDoc(mapper.writeValueAsString(a)).get(); //方式二 client.update(new UpdateRequest("blog2","article",a.getId()+"").doc(mapper.writeValueAsString(a))).get();
刪除文檔
在建立文檔代碼基礎上更改步驟4 方式一 client.prepareDelete("blog2", "article", a.getId()+"").get(); 方式二 client.delete(new DeleteRequest("blog1","article",a.getId()+"")).get();
批量插入數據
刪除blog2而後建立索引和映射
@Test //批量建立文檔 public void test8() throws Exception { //一、建立客戶端訪問對象 TransportClient client = new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300)); //3.建立一個json轉換器 ObjectMapper mapper =new ObjectMapper(); for (int i = 1; i <= 100; i++) { //二、建立文檔對象 Article a = new Article(); a.setId(i); a.setTitle(i+"搜索工做其實很快樂"); a.setContent(i+"咱們但願咱們的搜索解決方案要快,咱們但願有一個零配置和一個徹底免費的搜索模\n" + "式,咱們但願可以簡單地使用JSON經過HTTP的索引數據,咱們但願咱們的搜索服務器始終可用,咱們但願可以一臺開\n" + "始並擴展到數百,咱們要實時搜索,咱們要簡單的多租戶,咱們但願創建一個雲的解決方案。Elasticsearch旨在解\n" + "決全部這些問題和更多的問題。"); //四、建立索引庫及添加文檔 {id:xxx, title:xxx, content:xxx} client.prepareIndex("blog2", "article", a.getId()+"").setSource(mapper.writeValueAsString(a)).get(); } //五、關閉資源 client.close(); }
分頁和排序
@Test //分頁和排序 public void test9() throws Exception { //建立客戶端訪問對象 TransportClient client=new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300)); //建立查詢對象 SearchRequestBuilder requestBuilder = client.prepareSearch("blog2").setTypes("article") .setQuery(QueryBuilders.matchAllQuery()); //分頁:參數1:從哪開始查,參數2:每頁查多少 requestBuilder.setFrom(0).setSize(20); //排序 requestBuilder.addSort("id", SortOrder.ASC); //執行查詢並返回結果 SearchResponse searchResponse = requestBuilder.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()); } }
高亮顯示
@Test //高亮顯示 public void test10() throws Exception { //建立客戶端訪問對象 TransportClient client=new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300)); //建立查詢對象 SearchRequestBuilder requestBuilder = client.prepareSearch("blog2").setTypes("article") .setQuery(QueryBuilders.termQuery("title","搜索")); //高亮顯示 HighlightBuilder builder=new HighlightBuilder(); builder.preTags("<font color='red'>"); builder.field("title"); builder.postTags("</font>"); requestBuilder.highlighter(builder); //分頁:參數1:從哪開始查,參數2:每頁查多少 requestBuilder.setFrom(0).setSize(20); //排序 requestBuilder.addSort("id", SortOrder.ASC); //執行查詢並返回結果 SearchResponse searchResponse = requestBuilder.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()); HighlightField field = searchHit.getHighlightFields().get("title"); System.out.println(field.fragments()[0]); } }