時間:2017年09月14日星期四
說明:本文部份內容均來自慕課網。@慕課網:http://www.imooc.com
教學源碼:無
學習源碼:https://github.com/zccodere/s...java
什麼是ElasticSearchnode
基於Apache Lucene構建的開源搜索引擎 採用Java編寫,提供簡單易用的RESTful API 輕鬆的橫向擴展,可支持PB級的結構化和非結構化數據處理
可用應用場景git
海量數據分析引擎 站內搜索引擎 數據倉庫
一線公司實際應用場景github
英國衛報-實時分析公衆對文章的迴應 維基百科、GitHub-站內實時搜索 百度-實時日誌監控平臺 阿里巴巴、谷歌、京東、騰訊、小米等等
前置知識web
熟悉用Maven構建項目 瞭解Spring Boot的基本使用
環境要求spring
IDE工具:IntelliJ IDEA、Eclipse等經常使用IDE便可 Java版本:JDK1.8 其餘依賴:Maven、NodeJs(6.0以上)
課程安排數據庫
如何安裝單節點的ElasticSearch 如何安裝插件及插件的主要做用 如何安裝分佈式的ElasticSearch 瞭解ElasticSearch的基礎概念 瞭解ElasticSearch的基本用法 瞭解ElasticSearch的高級查詢 使用Spring Boot集合ElasticSearch實戰開發
ES版本問題apache
版本歷史:1.x -> 2.x -> 5.x 版本選擇:擁抱新的版本
學習筆記npm
單機安裝ElasticSearch 安裝前,請確保已經安裝JDK1.8 安裝前,請確保已經安裝nodejs6.0以上 官網:https://www.elastic.co/products/elasticsearch 下載安裝包:https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.6.0.tar.gz 解壓安裝包:tar -vxf elasticsearch-5.6.0.tar.gz cd elasticsearch-5.6.0.tar.gz 啓動前,檢查JDK環境 java -v 請確保已經安裝JDK1.8 啓動elasticsearch sh ./bin/elasticsearch 當日志輸出started時,表示啓動成功 驗證服務 127.0.0.1:9200 elasticsearch服務默認監聽9200端口 訪問:http://127.0.0.1:9200 若是出現版本信息,則安裝成功
學習筆記json
實用插件Head安裝 打開github:https://github.com/mobz/elasticsearch-head 下載插件包:https://codeload.github.com/mobz/elasticsearch-head/zip/master unzip elasticsearch-head-master.zip cd elasticsearch-head-master 檢查Node環境 node -v 請確保已經安裝nodejs6.0以上 安裝插件 npm install 啓動插件 npm run start 輸出日誌表示啓動成功 Started connect web server on http://localhost:9100 訪問 http://localhost:9100 ElasticSearch整合elasticsearch-head插件 cd elasticsearch-5.6.0 vim config/elasticsearch.yml 在配置文件的最後面加上 容許head插件跨域訪問rest接口 http.cors.allowed: true http.cors.allow-origin: "*" :wq 後臺啓動 ./bin/elasticsearch -d 再次從新啓動elasticsearch-head插件 cd elasticsearch-head-master 啓動插件 npm run start 訪問 http://localhost:9100
學習筆記
集羣安裝 1個master、2個slave master節點配置 配置當前節點爲主節點 cd elasticsearch-5.6.0 修改配置 vim config/elasticsearch.yml 在配置文件的最後面加上 # 指定集羣的名字 cluster.name: myes # 指定當前節點的名字 node.name: master # 指定當前節點爲master node.master: true # 指定綁定的IP network.host: 127.0.0.1 # 使用默認端口:9200 :wq ps -ef | grep 'pwd' kill pid 從新啓動 ./bin/elasticsearch -d 檢查服務是否正常啓動 http://localhost:9200 slave節點配置 mkdir es_slave cp elasticsearch-5.6.0.tar.gz es_slave/ cd es_slave tar -vxf elasticsearch-5.6.0.tar.gz cp -r elasticsearch-5.6.0 es_slave1 cp -r elasticsearch-5.6.0 es_slave2 修改es_slave1配置 cd es_slave1 vim config/elasticsearch.yml 在配置文件的最後面加上 # 指定集羣的名字:須要和master節點一致 cluster.name: myes # 指定當前節點的名字 node.name: slave1 # 指定綁定的IP network.host: 127.0.0.1 # 指定當前節點綁定端口號8200 http.port: 8200 # 該配置主要是爲了找到master節點 discovery.zen.ping.unicast.hosts: ["127.0.0.1"] :wq 啓動服務 ./bin/elasticsearch -d 檢查服務是否正常啓動 http://localhost:9100 安裝以前的步驟配置slave2 cd es_slave2 vim config/elasticsearch.yml 在配置文件的最後面加上 # 指定集羣的名字:須要和master節點一致 cluster.name: myes # 指定當前節點的名字 node.name: slave2 # 指定綁定的IP network.host: 127.0.0.1 # 指定當前節點綁定端口號8000 http.port: 8000 # 該配置主要是爲了找到master節點 discovery.zen.ping.unicast.hosts: ["127.0.0.1"] :wq 啓動服務 ./bin/elasticsearch -d 檢查服務是否正常啓動 http://localhost:9100
集羣和節點
一個集羣是由一個或多個ES組成的集合 每個集羣都有一個惟一的名字 每個節點都是經過集羣的名字來加入集羣的 每個節點都有本身的名字 節點可以存儲數據,參與集羣索引數據以及搜索數據的獨立服務
基礎概念
索引:含有相同屬性的文檔集合 類型:索引能夠定義一個或多個類型,文檔必須屬於一個類型 (一般會定義有相同字段的文檔做爲一個類型) 文檔:文檔是能夠被索引的基本數據單位
三者之間的關係
索引至關於SQL裏的DataBase,也就是數據庫 類型至關於SQL裏的Table,也就是表 文檔至關於SQL裏的一行記錄,也就是一行數據
舉個例子
假設有一個信息查詢系統,使用ES作存儲。那麼裏面的數據就能夠分爲各類各樣的索引,好比:汽車索引、圖書索引、傢俱索引等等。圖書索引又能夠細分爲各類類型,好比:科普類、小說類、技術類等等。具體到每一本書籍,就是文檔,就是整個圖書裏面最小的存儲單位。
和索引相關的兩個高級概念
分片:每一個索引都有多個分片,每一個分片是一個Lucene索引 備份:拷貝一份分片就完成了分片的備份 ES默認在建立索引時,會建立5個分片、1個備份 分片的數量只能在建立索引時設置,而不能在後期進行修改 備份是能夠動態修改的
ES的API組成結構:使用RESTful API風格來命名API
API基本格式:http://<ip>:<port>/<索引>/<類型>/<文檔id> 經常使用HTTP動詞:GET/PUT/POST/DELETE
使用Head插件建立非結構化索引
訪問:localhost:9100 路徑:索引->新建索引->索引名稱:book->點擊OK 索引名稱:必須小寫,不能有中劃線
如何區分索引是結構化的仍是非結構化的
結合Head插件查看 點擊索引信息->索引信息->mappings節點 當mappings節點後的內容爲空時:非結構化索引
使用Head插件建立結構化索引
路徑:複合查詢->查詢->book/novel/_mappings 指定映射:使用JSON結構體 { "novel":{ "propertise":{ "title":{"type":"test"} } } } 而後勾選易讀->點擊驗證JSON->提交請求 再次查看mappings節點時,已經不是空的了
使用PostMan建立索引
PUT:127.0.0.1:9200/people Body->raw->JSON(application/json) 編寫JSON體 點擊Send,而後到Head插件中查看people索引信息
編寫JSON體以下
{ "settings":{ "number_of_shards":3, "number_of_replicas":1 }, "mappings":{ "man":{ "properties":{ "name":{ "type": "text" }, "country":{ "type": "keyword" }, "age":{ "type": "integer" }, "date":{ "type": "date", "format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" } } }, "woman":{ } } }
新增文檔
指定文檔id新增 自動產生文檔id新增 文檔id:惟一索引值指向文檔數據
使用PostMan工具新增數據-指定文檔id新增
PUT:127.0.0.1::9200/people/man/1 Body->raw->JSON(application/json) { "name":"zc", "country":"china", "age":22, "date":"1995-01-01" } 點擊Send,能夠看到ES響應的信息 使用Head插件查看索引下的數據,docs字段表明索引下全部文檔的數量值 點擊數據瀏覽,能夠看見剛剛新增的數據
使用PostMan工具新增數據-自動產生文檔id新增
POST:127.0.0.1::9200/people/man/ Body->raw->JSON(application/json) { "name":"myzc", "country":"china", "age":22, "date":"1995-02-01" } 點擊Send,能夠看到ES響應的信息 使用Head插件,點擊數據瀏覽,能夠看見剛剛新增的數據
修改文檔
直接修改文檔 腳本修改文檔
使用PostMan工具修改文檔-指定文檔ID修改
POST:127.0.0.1:9200/people/man/1/_update Body->raw->JSON(application/json) { "doc":{ "name":"who is zc" } } 點擊Send,能夠看到ES響應的信息 使用Head插件,點擊數據瀏覽,能夠看見剛剛修改的數據
使用PostMan工具修改文檔-指定文檔ID使用腳本修改
POST:127.0.0.1:9200/people/man/1/_update Body->raw->JSON(application/json) { "script":{ "lang":"painless", "inline":"ctx._sources.age+=10" } } 或使用如下格式 { "script":{ "lang":"painless", "inline":"ctx._sources.age = params.age", "params":{ "age":100 } } } 點擊Send,能夠看到ES響應的信息 使用Head插件,點擊數據瀏覽,能夠看見剛剛修改的數據
刪除
刪除文檔 刪除索引
使用PostMan刪除文檔-指定文檔ID
DELETE:127.0.0.1:9200/people/man/1 點擊Send,能夠看到ES響應的信息 使用Head插件,點擊數據瀏覽,能夠看見數據已經刪除
使用Head插件刪除索引
路徑:概覽->book->動做->刪除->輸入刪除->肯定 注意:刪除操做自己很危險,刪除索引時會刪除它全部的文檔數據
使用PostMan刪除索引
DELETE:127.0.0.1:9200/people 點擊Send,能夠看到ES響應的信息 使用Head插件,點擊數據瀏覽,能夠看見索引已經刪除
ES查詢分類
簡單查詢 條件查詢 聚合查詢
前置條件,建立book索引,並預先新增一些數據
使用PostMan簡單查詢-指定文檔ID
GET:127.0.0.1:9200/book/novel/1 點擊Send,能夠看到ES響應的信息
使用PostMan條件查詢
POST:127.0.0.1:9200/book/_search Body->raw->JSON(application/json) 編寫查詢JSON體 點擊Send,能夠看到ES響應的信息
編寫查詢JSON體以下
查詢全部數據
{ "query":{ "match_all":{} } }
用from指定從哪裏返回,用size指定返回的數據大小
{ "query":{ "match_all":{} }, "from":1, "size":1 }
使用關鍵字查詢,查詢標題含有ElasticSearch的數據
{ "query":{ "match":{ "title":"ElasticSearch" } } }
使用sort指定結果集排序-按照出版日期倒序
{ "query":{ "match":{ "title":"ElasticSearch" } }, "sort":[ { "publish_date":{ "order":"desc" } } ] }
按照書籍的字數進行單個聚合查詢
{ "aggs":{ "group_by_word_count":{ "terms":{ "field":"word_count" } } } }
按照書籍的字數及出版日期進行多個聚合查詢
{ "aggs":{ "group_by_word_count":{ "terms":{ "field":"word_count" } }, "group_by_publish_date":{ "terms":{ "field":"publish_date" } } } }
對書籍字數進行統計計算
{ "aggs":{ "grades_word_count":{ "stats":{ "field":"word_count" } } } }
高級查詢
子條件查詢:特定字段查詢所指特定值 query context filter context 複合條件查詢:以必定的邏輯組合子條件查詢 固定分數查詢 布爾查詢
query context介紹
在查詢過程當中,除了判斷是否知足查詢條件外 ES還會計算一個_score來標識匹配的程度 旨在判斷目標文檔和查詢條件匹配的有多好
query context查詢
全文本查詢:針對文本類型數據 字段級別查詢:針對結構化數據,如數字、日期等
使用PostMan進行query context文本查詢
POST:127.0.0.1:9200/book/_search Body->raw->JSON(application/json) 編寫查詢JSON體 點擊Send,能夠看到ES響應的信息
編寫查詢JSON體以下
使用match關鍵字模糊匹配
{ "query":{ "match":{ "author":"wali" } } }
使用match_phrase關鍵字習語匹配
{ "query":{ "match_phrase":{ "author":"ElasticSearch入門" } } }
使用multi_match查詢做者和標題包含wali的數據
{ "query":{ "multi_match":{ "query":"wali", "fields":["author","title"] } } }
使用query_string進行語法查詢
{ "query":{ "query_string":{ "query":"(ElasticSearch AND 大法) OR Python" } } }
使用query_string查詢多個字段
{ "query":{ "query_string":{ "query":"wali OR ElasticSearch", "field":["title","author"] } } }
使用PostMan進行query context字段查詢
POST:127.0.0.1:9200/book/_search Body->raw->JSON(application/json) 編寫查詢JSON體 點擊Send,能夠看到ES響應的信息
編寫查詢JSON體以下
查詢字數在某個特定集(1000)的書籍
{ "query":{ "term":{ "word_count":1000 } } }
查詢字符在某個範圍(大於等於1000-小於等於2000)的書籍
{ "query":{ "range":{ "word_count":{ "gte":1000, "lte":2000 } } } }
查詢出版日期在某個範圍(2017-01-01至2017-12-31)的書籍
{ "query":{ "range":{ "publish_date":{ "gte":"2017-01-01", "lte":"2017-12-31"//或 "lte":"now" } } } }
使用關鍵now,代指當前日誌(即如今)
filter context介紹
在查詢過程當中,只判斷該文檔是否知足條件 只有Yes或No
使用PostMan進行filter context查詢
POST:127.0.0.1:9200/book/_search Body->raw->JSON(application/json) 點擊Send,能夠看到ES響應的信息
查詢字數1000的書籍
{ "query":{ "bool":{ "filter":{ "term":{ "word_count":1000 } } } } }
經常使用複合條件查詢
固定分數查詢 布爾查詢
使用PostMan進行復合查詢
127.0.0.1:9200 /_search Body->raw->JSON(application/json) 點擊Send,能夠看到ES響應的信息
全文搜索-標題含有ElasticSearch的書籍
{ "query":{ "constant_score":{ "filter":{ "match":{ "title": "ElasticSearch" } }, "boost":2 } } }
布爾查詢- should知足任意條件
{ "query":{ "bool":{ "should":[ { "match":{ "author":"wali" } }, { "match":{ "title":"ElasticSearch" } } ] } } }
布爾查詢- must知足所有條件
{ "query":{ "bool":{ "must":[ { "match":{ "author":"wali" } }, { "match":{ "title":"ElasticSearch" } } ] } } }
使用must和filter複合查詢
{ "query":{ "bool":{ "must":[ { "match":{ "author":"wali" } }, { "match":{ "title":"ElasticSearch" } } ], "filter":[ { "term":{ "word_count":1000 } } ] } } }
布爾查詢- must_not必定不能知足的條件
{ "query":{ "bool":{ "must_not":{ "term":{ "author":"wali" } } } } }
實戰演練
SpringBoot集成ES 圖書信息管理接口開發
建立名爲springbootes的gradle項目build.gradle以下
buildscript { ext { springBootVersion = '1.5.6.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' group = 'com.myimooc' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 repositories { maven{url:"http://maven.aliyun.com/nexus/content/groups/public/"} mavenCentral() } dependencies { compile('org.springframework.boot:spring-boot-starter-web') //compile('org.springframework.boot:spring-boot-starter-data-elasticsearch') compile('org.elasticsearch.client:transport:5.5.2') compile('org.apache.logging.log4j:log4j-core:2.7.0') testCompile('org.springframework.boot:spring-boot-starter-test') }
接口列表
新增圖書信息 修改圖書信息 刪除圖書信息 綜合查詢功能
代碼編寫
1.編寫EsConfig類
package com.myimooc.springbootes.config; import java.net.InetAddress; import java.net.UnknownHostException; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.transport.client.PreBuiltTransportClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @title ElasticSearch配置類 * @describe ElasticSearch配置 * @author zc * @version 1.0 2017-09-15 */ @Configuration public class EsConfig { @Bean public TransportClient client() throws UnknownHostException{ InetSocketTransportAddress node = new InetSocketTransportAddress(InetAddress.getByName("localhost"),9300); Settings settings = Settings.builder() // es集羣名稱 .put("cluster.name", "myes") .build(); TransportClient client = new PreBuiltTransportClient(settings); client.addTransportAddress(node); return client; } }
2.編寫BookRest類
package com.myimooc.springbootes.rest; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.search.SearchHit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * @title 圖書REST接口類 * @describe 調ES接口 * @author zc * @version 1.0 2017-09-15 */ @RestController public class BookRest { @Autowired private TransportClient client; @GetMapping("/") public String index(){ return "index"; } /** * @describe 查詢接口 * @author zc * @version 1.0 2017-09-15 */ @GetMapping("/get/book/novel") public ResponseEntity<?> get(@RequestParam(name="id",defaultValue="")String id){ if(id.isEmpty()){ return new ResponseEntity<>(HttpStatus.NOT_FOUND); } GetResponse result = this.client.prepareGet("book","novel",id).get(); if(!result.isExists()){ return new ResponseEntity<>(HttpStatus.NOT_FOUND); } return new ResponseEntity<>(result.getSource(), HttpStatus.OK); } /** * @describe 增長接口 * @author zc * @version 1.0 2017-09-15 */ @PostMapping("/add/book/novel") public ResponseEntity<?> add( @RequestParam(name="title")String title, @RequestParam(name="author")String author, @RequestParam(name="word_count")int wordCount, @RequestParam(name="publish_date") @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date publishDate){ try { XContentBuilder content = XContentFactory.jsonBuilder() .startObject() .field("title",title) .field("author", author) .field("word_count", wordCount) .field("publish_date", publishDate.getTime()) .endObject(); IndexResponse result = this.client.prepareIndex("book","novel").setSource(content).get(); return new ResponseEntity<>(result.getId(),HttpStatus.OK); } catch (IOException e) { e.printStackTrace(); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } /** * @describe 刪除接口 * @author zc * @version 1.0 2017-09-15 */ @DeleteMapping("/delete/book/novel") public ResponseEntity<?> delete(@RequestParam(name="id",defaultValue="")String id){ DeleteResponse result = this.client.prepareDelete("book", "novel", id).get(); return new ResponseEntity<>(result.toString(),HttpStatus.OK); } /** * @describe 修改接口 * @author zc * @version 1.0 2017-09-15 */ @DeleteMapping("/update/book/novel") public ResponseEntity<?> update( @RequestParam(name="id",defaultValue="")String id, @RequestParam(name="title",required=false)String title, @RequestParam(name="author",required=false)String author){ UpdateRequest update = new UpdateRequest("book","novel",id); try { XContentBuilder builder = XContentFactory.jsonBuilder() .startObject(); if(!StringUtils.isEmpty(title)){ builder.field("title",title); } if(!StringUtils.isEmpty(author)){ builder.field("author", author); } builder.endObject(); update.doc(builder); UpdateResponse result = this.client.update(update).get(); return new ResponseEntity<>(result.toString(),HttpStatus.OK); } catch (Exception e) { e.printStackTrace(); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } /** * @describe 複合查詢 * @author zc * @version 1.0 2017-09-15 */ @DeleteMapping("/query/book/novel") public ResponseEntity<?> query( @RequestParam(name="author",required=false)String author, @RequestParam(name="title",required=false)String title, @RequestParam(name="gt_word_count",defaultValue="0") int gtWordCount, @RequestParam(name="lt_word_count",required=false) Integer ltWordCount){ // 構建布爾查詢 BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); if(!StringUtils.isEmpty(author)){ boolQuery.must(QueryBuilders.matchQuery("author", author)); } if(!StringUtils.isEmpty(title)){ boolQuery.must(QueryBuilders.matchQuery("title", title)); } // 構建範圍查詢 RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("word_count") .from(gtWordCount); if(ltWordCount != null && ltWordCount > 0){ rangeQuery.to(ltWordCount); } // 使用filter構建 boolQuery.filter(rangeQuery); SearchRequestBuilder builder = this.client.prepareSearch("book") .setTypes("novel") .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(boolQuery) .setFrom(0) .setSize(10); System.out.println("[ES查詢請求參數]:"+builder); SearchResponse response = builder.get(); List<Map<String,Object>> result = new ArrayList<Map<String,Object>>(); for(SearchHit hit:response.getHits()){ result.add(hit.getSource()); } return new ResponseEntity<>(result,HttpStatus.OK); } }
3.編寫SpringbootesApplication類
package com.myimooc.springbootes; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @title SpringBoot集成ElasticSearch * @describe 啓動類 * @author zc * @version 1.0 2017-09-15 */ @SpringBootApplication public class SpringbootesApplication { public static void main(String[] args) { SpringApplication.run(SpringbootesApplication.class, args); } }
課程總結
ES簡介:使用場景例子、ES的重要性 ES安裝:單機安裝、集羣安裝、Head插件安裝 ES基礎:核心基礎概念:索引、類型、文檔 ES用法:基本用法:增刪改查 ES高級:高級查詢語法 ES實戰:SpringBoot集成ES開發增刪改查接口