安裝eshtml
項目添加maven依賴java
es客戶端組件注入到spring容器中mysql
es與mysql表結構對比spring
索引的刪除建立sql
文檔的crud數據庫
es能快速搜索的核心-倒排索引apache
基於倒排索引的精確搜索、全文搜索(重點)json
es集羣springboot
安裝文章app
1.<dependency> 2. <groupId>org.elasticsearch.client</groupId> 3. <artifactId>elasticsearch-rest-high-level-client</artifactId> 4. <version>7.10.2</version> </dependency>
1.package com.shuang.config; 2. 3.import org.apache.http.HttpHost; 4.import org.elasticsearch.client.RestClient; 5.import org.elasticsearch.client.RestHighLevelClient; 6.import org.springframework.context.annotation.Bean; 7.import org.springframework.context.annotation.Configuration; 8. 9.@Configuration //xml文件-bean 10.public class ElasticSearchClientConfig { 11. 12. @Bean 13. public RestHighLevelClient restHighLevelClient(){ 14. RestHighLevelClient client = new RestHighLevelClient( 15. RestClient.builder( 16. //多個集羣,就new多個 17. new HttpHost("localhost", 9200, "http"))); 18. return client; 19. } 20.}
1)java代碼建立索引
package com.shuang; @SpringBootTest class DemoApplicationTests { @Autowired private RestHighLevelClient restHighLevelClient; @Test void contextLoads() throws IOException { //1,建立索引表 CreateIndexRequest request=new CreateIndexRequest("shuangbao"); //2,客戶端執行請求 IndicesClient,請求後得到響應 CreateIndexResponse createIndexResponse= restHighLevelClient.indices().create(request, RequestOptions.DEFAULT); System.out.println(createIndexResponse); } }
2)刪除索引
@Test void testDeleteIndex() throws IOException { DeleteIndexRequest request=new DeleteIndexRequest(); AcknowledgedResponse delete =restHighLevelClient.indices().delete(request,RequestOptions.DEFAULT); System.out.println(delete); }
先新建索引,默認類型爲_doc,創建文檔結構json格式的屬性有string類型的name,integer類型的age。
1.PUT /shuang_index1 2. { 3. "settings": { 4. "index": { 5. "number_of_replicas": "1", 6. "number_of_shards": "5" } 7. }, 8. "mappings": { 9. "test_type": { 10. "properties": { 11. "name": { 12. "type": "string", 13. }, 14. "age": { 15. "type": "integer" 16. } 17. } 18. } 19. } 20. }
插入一條文檔id爲1的數據
PUT shuang_index2/_doc/1 { "name":"shuang1", "age":"1" }
1)獲取文檔的信息,這裏咱們獲取文檔id爲1的信息
//獲取文檔的信息 @Test void testIsGetDocument() throws IOException { GetRequest getRequest=new GetRequest("shuang_index1","1"); //不獲取返回的_source的上下文 GetResponse getResponse=restHighLevelClient.get(getRequest,RequestOptions.DEFAULT); System.out.println(getResponse.getSourceAsString());//打印文檔的數據_source System.out.println(getResponse); //打印文檔id爲1的完整返回信息 } {"age":1,"name":"shuang1"} "_index":"shuang_index1","_type":"_doc","_id":"1","_version":1,"_seq_no":4,"_primary_term":1,"found":true,"_source":{"age":1,"name":"shuang1"}}
2)插入數據(數據來源能夠是其餘地方)
1.@Test 2.void testBulkRequest() throws IOException { 3. BulkRequest bulkRequest=new BulkRequest(); 4. bulkRequest.timeout("10s"); 5. 6. ArrayList<User> userList=new ArrayList<>(); 7. userList.add(new User("jiang1",1)); 8. userList.add(new User("jiang2",2)); 9. userList.add(new User("jiang3",3)); 10. userList.add(new User("jiang4",4)); 11. userList.add(new User("jiang5",5)); 12. userList.add(new User("jiang6",6)); 13. userList.add(new User("jiang7",7)); 14. userList.add(new User("jiang8",8)); 15. 16. //批處理請求 17. for(int i=0;i<userList.size();i++){ 18. //批量更新和刪除,就在這裏修改對應的請求就能夠了 19. bulkRequest.add( 20. new IndexRequest("shuang_index1") 21. .id(""+(i+1)) 22. .source(JSON.toJSONString(userList.get(i)),XContentType.JSON)); 23. 24. } 25. BulkResponse bulkResponse=restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT); 26. 27. System.out.println(bulkResponse.hasFailures());//是否失敗,返回false表明成功 28.}
3)刪除文檔信息
1.@Test 2.void testDeleteRequest() throws IOException { 3. DeleteRequest request=new DeleteRequest("shuang_index1","1"); 4. request.timeout("1s"); 5. 6. DeleteResponse deleteResponse=restHighLevelClient.delete(request,RequestOptions.DEFAULT); 7. System.out.println(deleteResponse.status()); 8. 9.}
4)更新文檔信息
1.@Test 2. void testUpdateRequest() throws IOException { 3. UpdateRequest updateRequest=new UpdateRequest("shuang_index1","1"); 4. updateRequest.timeout("1s"); 5. 6. User user=new User("爽爽爽",18); 7. updateRequest.doc(JSON.toJSONString(user),XContentType.JSON); 8. 9. UpdateResponse updateResponse=restHighLevelClient.update(updateRequest,RequestOptions.DEFAULT); 10. 11. System.out.println(updateResponse.status()); 12. }
前面介紹了文檔的查找,是普通的查找get方式的,須要指定_index、_type、_id。也就是根據id從正排索引中獲取內容,肯定惟一文檔。
但搜索search方式須要一種更復雜的模型,由於不知道查詢會命中哪些文檔。採用倒排索引能夠知足複雜的搜索過程。
搜索也分精確值搜索和全文搜索,對數據創建索引和執行搜索的原理以下圖所示:
Term(精確,不會被分詞器解析,keyword類型的字段也不會被分詞器解析)和match(全文,會被分詞器解析)是兩個經常使用的基於倒排索引的搜索類型。他們對應的java類主要有 TermQueryBuilder和MatchQueryBuilder。
精確搜索(在shuang_index1索引中,name字段爲shuang1的文檔)
1.@Test 2. void testSearch() throws IOException { 3. SearchRequest searchRequest=new SearchRequest("shuang_index1"); 4. //構建搜索條件 5. SearchSourceBuilder sourceBuilder=new SearchSourceBuilder(); 6. 7. TermQueryBuilder termQueryBuilder=QueryBuilders.termQuery("name","shuang1"); 8. 9. sourceBuilder.query(termQueryBuilder); 10. sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); 11. 12. searchRequest.source(sourceBuilder); 13. 14. SearchResponse searchResponse=restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT); 15. System.out.println(JSON.toJSONString(searchResponse.getHits())); 16. 17. for(SearchHit documentFields :searchResponse.getHits().getHits()){ 18. System.out.println(documentFields.getSourceAsMap()); 19. } 20. }
第二個輸出是對搜索返回信息進行了提取關鍵字段。
全文搜索
1)在kibana上新建shuang_index2索引(至關於在navicat上去新建mysql數據庫)
通常咱們不指定類型(系統會默認爲_doc,es7不推薦使用了,es8將會移除類型,至關於mysql沒有了表這個結構)。
設置裏面的文檔字段爲name和age,它們類型爲string與interger。
1.PUT /shuang_index2 2. { 3. "settings": { 4. "index": { 5. "number_of_replicas": "1", //設置副本數爲1 6. "number_of_shards": "5" } //設置分片數爲5 7. }, 8. "mappings": { 9. "test_type": { 10. "properties": { 11. "name": { 12. "type": "string", 13. }, 14. "age": { 15. "type": "integer" 16. } 17. } 18. } 19. } 20. }
2)插入數據(通常咱們是從數據倉庫批量導入,java代碼見上面文檔的插入)
Kibana控制檯也能夠本身手動插入
1.PUT shuang_index2/_doc/5 2.{ 3. "name":"shuang e", 4. "age":"5" 5.}
這裏shuang_index2爲索引、_doc爲類型、5表明文檔id(大數據環境下,咱們通常不指定文檔id,系統會隨機生成一個文檔id,惟一標識該文檔)。它們分別對應mysql的數據庫、表、行。name和age表明mysql字段中的列屬性。文檔結構必須爲json格式。
3)搭建好索引結構後,咱們去用java代碼實現一下
(內置分詞器先把shuang bao分詞爲shuang 與 bao ,再去shuang_index2索引中去尋找,文檔一、二、三、四、5分別有name=shuang a、b、c、d、e。他們事先也被分詞器拆解了,只要有一個與上面對應,就搜索成功,而且會攜帶一個類似程度score返回)
1.@Test 2.void testSearch() throws IOException { 3. SearchRequest searchRequest=new SearchRequest("shuang_index2"); 4. //構建搜索條件 5. SearchSourceBuilder sourceBuilder=new SearchSourceBuilder(); 6. 7. MatchQueryBuilder matchQueryBuilder=QueryBuilders.matchQuery("name","shuang bao"); 8. sourceBuilder.query(matchQueryBuilder); 9. sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); 10. 11. searchRequest.source(sourceBuilder); 12. 13. SearchResponse searchResponse=restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT); 14. System.out.println(searchResponse); 15. 16. for(SearchHit documentFields :searchResponse.getHits().getHits()){ 17. System.out.println(documentFields.getSourceAsMap()); 18. } 19.}
返回結果:
{"took":770,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":5,"relation":"eq"},"max_score":0.08701137,"hits":[{"_index":"shuang_index2","_type":"_doc","_id":"1","_score":0.08701137,"_source":{"name":"shuang a","age":"1"}},{"_index":"shuang_index2","_type":"_doc","_id":"2","_score":0.08701137,"_source":{"name":"shuang b","age":"2"}},{"_index":"shuang_index2","_type":"_doc","_id":"3","_score":0.08701137,"_source":{"name":"shuang c","age":"3"}},{"_index":"shuang_index2","_type":"_doc","_id":"4","_score":0.08701137,"_source":{"name":"shuang d","age":"4"}},{"_index":"shuang_index2","_type":"_doc","_id":"5","_score":0.08701137,"_source":{"name":"shuang e","age":"5"}}]}} {name=shuang a, age=1} {name=shuang b, age=2} {name=shuang c, age=3} {name=shuang d, age=4} {name=shuang e, age=5}
如圖3個es服務構成的集羣,索引test分紅了5片,一個副本(粗框的),而book一個分片一個副本。保證了若是有一個服務壞了,其餘服務也能執行全部工做。
一個搜索請求必須詢問請求的索引中全部分片的某個副原本進行匹配。假設一個索引有5個主分片,每一個主分片有1個副分片,共10個分片,一次搜索請求會由5個分片來共同完成,它們多是主分片,也多是副分片。也就是說,一次搜索請求只會命中全部分片副本中的一個。
ElasticSearch極簡入門總結就結束了感謝您的閱讀