- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) >
- SpringBoot整合Elasticsearch實(shí)現索引和文檔的操作方法
Elasticsearch 是一個(gè)分布式、可擴展、近實(shí)時(shí)的高性能搜索與數據分析引擎。Elasticsearch 基于 Apache Lucene 構建,采用 Java 編寫(xiě),并使用 Lucene 構建索引、提供搜索功能。Elasticsearch 的目標是讓全文搜索功能的落地變得簡(jiǎn)單。
本文是SpringBoot整合Elasticsearch與綜合實(shí)例的第一篇,主要實(shí)現SpringBoot整合Elasticsearch實(shí)現索引和文檔的相關(guān)操作。
(1)創(chuàng )建SpringBoot項目,項目結構如下圖:
(2)使用Maven添加依賴(lài)文件
在pom.xml配置信息文件中,添加 Elasticsearch服務(wù)、Elasticsearch高級客戶(hù)端的依賴(lài):
<!-- Elasticsearch服務(wù) --> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.11.1</version> </dependency> <!-- Elasticsearch高級客戶(hù)端 --> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.11.1</version> </dependency>
(3)Elasticsearch的配置
在 application.yml 配置文件中配置 Elasticsearch 信息:
# Elasticsearch配置 elasticsearch: hostname: 127.0.0.1 port: 9200 scheme: http
(4)Elasticsearch配置類(lèi)(config層)
創(chuàng )建 com.pjb.config 包,并創(chuàng )建 ElasticsearchConfig 類(lèi)(Elasticsearch配置類(lèi)),并使用 @Configuration 注解,標注該類(lèi)為配置類(lèi)。
package com.pjb.config; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Elasticsearch配置類(lèi) * @author pan_junbiao **/ @Configuration public class ElasticsearchConfig { @Value("${elasticsearch.hostname}") private String hostname; @Value("${elasticsearch.port}") private int port; @Value("${elasticsearch.scheme}") private String scheme; /** * 初始化:高級客戶(hù)端 * @return */ @Bean public RestHighLevelClient restHighLevelClient() { RestHighLevelClient restHighLevelClient = null; try { RestClientBuilder builder = RestClient.builder(new HttpHost(hostname, port, scheme)); restHighLevelClient = new RestHighLevelClient(builder); return restHighLevelClient; } catch (Exception ex) { System.out.println("初始化Elasticsearch高級客戶(hù)端失敗"); ex.printStackTrace(); } return restHighLevelClient; } }
在 Elasticsearch 中開(kāi)始為數據建立索引之前要做的第一步操作是創(chuàng )建——我們的數據主要容器。這里的索引類(lèi)似于 SQL 中的數據庫概念。它是類(lèi)型(相當于 SQL 中的表)和文檔(相當于 SQL 中的記錄)的容器。
存儲數據的行為叫作索引。在 Elasticsearch 中,文檔會(huì )歸屬于一種類(lèi)型,這些類(lèi)型會(huì )存在于索引中。
Elasticsearch 集群和數據庫中核心概念的對應關(guān)系如下:
定義一個(gè)博客信息(blog_info)的數據表結構:
字段類(lèi)型必須映射到 Elasticsearch 的基本類(lèi)型之一,并且需要添加有關(guān)如何索引字段的選項。
推薦本博客文章1:《》
推薦本博客文章2:《》
Elasticsearch教程:《》
創(chuàng )建 com.pjb.entity 包,并創(chuàng )建BlogInfo類(lèi)(博客信息實(shí)體類(lèi))。
package com.pjb.entity; import java.util.Date; /** * 博客信息實(shí)體類(lèi) * @author pan_junbiao **/ public class BlogInfo { private int blogId; //博客ID private String blogName; //博客名稱(chēng) private String blogUrl; //博客地址 private double blogPoints; //博客積分 private Date createDate; //創(chuàng )建時(shí)間 private String blogDescribe; //博客描述 //構建方法1 public BlogInfo() { } //構建方法2 public BlogInfo(int blogId, String blogName, String blogUrl, double blogPoints, Date createDate, String blogDescribe) { this.blogId = blogId; this.blogName = blogName; this.blogUrl = blogUrl; this.blogPoints = blogPoints; this.createDate = createDate; this.blogDescribe = blogDescribe; } public int getBlogId() { return blogId; } public void setBlogId(int blogId) { this.blogId = blogId; } public String getBlogName() { return blogName; } public void setBlogName(String blogName) { this.blogName = blogName; } public String getBlogUrl() { return blogUrl; } public void setBlogUrl(String blogUrl) { this.blogUrl = blogUrl; } public double getBlogPoints() { return blogPoints; } public void setBlogPoints(double blogPoints) { this.blogPoints = blogPoints; } public Date getCreateDate() { return createDate; } public void setCreateDate(Date createDate) { this.createDate = createDate; } public String getBlogDescribe() { return blogDescribe; } public void setBlogDescribe(String blogDescribe) { this.blogDescribe = blogDescribe; } }
(1)編寫(xiě)索引存在驗證方法:
/** * Elasticsearch高級客戶(hù)端 */ @Autowired private RestHighLevelClient restHighLevelClient; /** * 索引存在驗證 * @param indexName 索引名稱(chēng) */ @Override public boolean existsIndex(String indexName) { boolean exists = false; //參數驗證 if(indexName==null || indexName.length()<=0) { return false; } try { //構建索引存在驗證請求 GetIndexRequest request = new GetIndexRequest(indexName); //執行請求 exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT); } catch (Exception ex) { ex.printStackTrace(); } return exists; }
(1)編寫(xiě)創(chuàng )建索引方法:
/** * Elasticsearch高級客戶(hù)端 */ @Autowired private RestHighLevelClient restHighLevelClient; /** * 創(chuàng )建索引 * @param indexName 索引名稱(chēng) */ @Override public boolean createIndex(String indexName) { boolean result = false; //參數驗證 if(indexName==null || indexName.length()<=0) { return false; } try { //1.創(chuàng )建索引的請求 CreateIndexRequest request = new CreateIndexRequest(indexName); //構建索引結構 XContentBuilder builder = XContentFactory.jsonBuilder(); builder.startObject(); { builder.startObject("properties"); { //創(chuàng )建博客ID文檔字段 builder.startObject("blogId"); { builder.field("type", "long"); } builder.endObject(); //創(chuàng )建博客名稱(chēng)文檔字段 builder.startObject("blogName"); { builder.field("type", "text"); } builder.endObject(); //創(chuàng )建博客地址文檔字段 builder.startObject("blogUrl"); { builder.field("type", "keyword"); } builder.endObject(); //創(chuàng )建博客積分字段 builder.startObject("blogPoints"); { builder.field("type", "double"); } builder.endObject(); //創(chuàng )建創(chuàng )建時(shí)間字段 builder.startObject("createDate"); { builder.field("type", "date"); } builder.endObject(); //創(chuàng )建博客描述字段 builder.startObject("blogDescribe"); { builder.field("type", "text") //插入時(shí)分詞 .field("analyzer", "ik_smart") //搜索時(shí)分詞 .field("search_analyzer", "ik_max_word"); } builder.endObject(); } builder.endObject(); } builder.endObject(); request.mapping(builder); //2客戶(hù)端執行請求,請求后獲得響應 CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT); result = true; } catch (Exception ex) { ex.printStackTrace(); } return result; }
(2)編寫(xiě)測試方法:
package com.pjb; import com.pjb.entity.BlogInfo; import com.pjb.service.impl.BlogService; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * 博客服務(wù)測試類(lèi) * @author pan_junbiao **/ @SpringBootTest public class BlogServiceTest { @BeforeEach private void setUp() { } @AfterEach private void tearDown() { } /** * 博客業(yè)務(wù)邏輯類(lèi) */ @Autowired private BlogService blogService; /** * 索引名稱(chēng) * 注意:索引名稱(chēng)必須小寫(xiě) */ private String _indexName = "blog_info"; /** * 測試:創(chuàng )建索引 * @author pan_junbiao */ @Test public void createIndex() { //判斷索引是否存在 boolean exists = blogService.existsIndex(_indexName); if(exists) { System.out.println("索引已經(jīng)存在"); return; } //創(chuàng )建索引 boolean result = blogService.createIndex(_indexName); if(result) { System.out.println("索引創(chuàng )建成功"); } else { System.out.println("索引創(chuàng )建失敗"); } } }
(4)使用 ElasticSearch-head 插件查看執行結果:
(1)編寫(xiě)刪除索引方法:
/** * 刪除索引 * @param indexName 索引名稱(chēng) */ @Override public boolean deleteIndex(String indexName) { boolean result = false; //參數驗證 if(indexName==null || indexName.length()<=0) { return false; } //注意:刪除索引前,必須先判斷索引是否存在,否則會(huì )報異常 if(!existsIndex(indexName)) { //該索引不存在 return false; } try { //創(chuàng )建刪除索引請求 DeleteIndexRequest request = new DeleteIndexRequest(indexName); //執行請求返回響應結果 AcknowledgedResponse deleteIndexResponse = restHighLevelClient.indices().delete(request,RequestOptions.DEFAULT); //解析響應結果 result = deleteIndexResponse.isAcknowledged(); } catch (Exception ex) { ex.printStackTrace(); } return result; }
(2)編寫(xiě)測試方法:
/** * 測試:刪除索引 * @author pan_junbiao */ @Test public void deleteIndex() { //刪除索引 boolean result = blogService.deleteIndex(_indexName); if(result) { System.out.println("刪除索引成功"); } else { System.out.println("刪除索引失敗"); } //判斷索引是否存在 boolean exists = blogService.existsIndex(_indexName); if(exists) { System.out.println("索引存在"); } else { System.out.println("索引不存在"); } }
(3)通過(guò)控制器查看執行結果:
創(chuàng )建文檔表示將一個(gè)或多個(gè)文檔存儲在索引中,這與在關(guān)系型數據庫中插入記錄的概念是類(lèi)似的。
在 Elasticsearch 的核心引擎 Lucene 中,插入或更新文檔的成本是相同的:在 Lucene 和 Elasticsearch 中,更新意味著(zhù)替換。
(1)編寫(xiě)新增文檔方法:
/** * 新增文檔 * @param indexName 索引名稱(chēng) * @param documentId 文檔ID * @param blogInfo 博客實(shí)體類(lèi) */ @Override public boolean addDocument(String indexName, String documentId, BlogInfo blogInfo) { boolean result = false; try { //將博客信息實(shí)體類(lèi)轉換為Map格式 Map<String, Object> blogMap = toBlogMap(blogInfo); //1、構建新增文檔請求 IndexRequest request = new IndexRequest(indexName).id(documentId).source(blogMap); //2、執行請求,返回響應結果 IndexResponse response = restHighLevelClient.index(request,RequestOptions.DEFAULT); result = true; } catch (Exception ex) { ex.printStackTrace(); } return result; } /** * 將博客信息實(shí)體類(lèi)轉換為Map格式 */ private Map<String,Object> toBlogMap(BlogInfo blogInfo) { Map<String, Object> blogMap = new HashMap<>(); blogMap.put("blogId", blogInfo.getBlogId()); blogMap.put("blogName", blogInfo.getBlogName()); blogMap.put("blogUrl", blogInfo.getBlogUrl()); blogMap.put("blogPoints", blogInfo.getBlogPoints()); blogMap.put("createDate", blogInfo.getCreateDate()); blogMap.put("blogDescribe", blogInfo.getBlogDescribe()); return blogMap; }
(2)編寫(xiě)測試方法:
/** * 測試:新增文檔 * @author pan_junbiao */ @Test public void addDocument() { //創(chuàng )建博客實(shí)體類(lèi) BlogInfo blogInfo = new BlogInfo(); blogInfo.setBlogId(1); blogInfo.setBlogName("pan_junbiao的博客"); blogInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao"); blogInfo.setBlogPoints(120.68); blogInfo.setCreateDate(new Date()); blogInfo.setBlogDescribe("您好,歡迎訪(fǎng)問(wèn) pan_junbiao的博客"); //文檔ID(根據業(yè)務(wù),我們以博客ID作為文檔ID) String documentId = String.valueOf(blogInfo.getBlogId()); //新增文檔 boolean result = blogService.addDocument(_indexName, documentId, blogInfo); if(result) { System.out.println("新增文檔成功"); } else { System.out.println("新增文檔失敗"); } }
(3)使用Kibana工具查看執行結果:
Elasticsearch查詢(xún)命令:GET /blog_info/_doc/1
(1)編寫(xiě)批量新增文檔方法:
/** * 批量新增文檔 * @param indexName 索引名稱(chēng) * @param blogList 博客列表 */ @Override public boolean addBulkDocument(String indexName, List<BlogInfo> blogList) { boolean result = false; try { //1、構建批量請求 BulkRequest request = new BulkRequest(); //遍歷博客列表,添加批量請求 for(BlogInfo blogInfo : blogList) { //將博客信息實(shí)體類(lèi)轉換為Map格式 Map<String, Object> blogMap = toBlogMap(blogInfo); //文檔ID(根據業(yè)務(wù),我們以博客ID作為文檔ID) String documentId = String.valueOf(blogInfo.getBlogId()); //加入請求 request.add(new IndexRequest(indexName).id(documentId).source(blogMap)); } //執行批量請求 BulkResponse bulkItemResponses = restHighLevelClient.bulk(request,RequestOptions.DEFAULT); result = true; } catch (Exception ex) { ex.printStackTrace(); } return result; }
(2)編寫(xiě)測試方法:
/** * 測試:批量新增文檔 * @author pan_junbiao */ @Test public void addBulkDocument() { //創(chuàng )建博客實(shí)體列表 List<BlogInfo> blogInfoList = new ArrayList<>(); blogInfoList.add(new BlogInfo(1,"pan_junbiao的博客","https://blog.csdn.net/pan_junbiao",120.68,new Date(),"您好,歡迎訪(fǎng)問(wèn) pan_junbiao的博客")); blogInfoList.add(new BlogInfo(2,"pan_junbiao的博客","https://blog.csdn.net/pan_junbiao",85.12,new Date(),"您好,歡迎訪(fǎng)問(wèn) pan_junbiao的博客")); blogInfoList.add(new BlogInfo(3,"pan_junbiao的博客","https://blog.csdn.net/pan_junbiao",94.37,new Date(),"您好,歡迎訪(fǎng)問(wèn) pan_junbiao的博客")); blogInfoList.add(new BlogInfo(4,"pan_junbiao的博客","https://blog.csdn.net/pan_junbiao",365.19,new Date(),"您好,歡迎訪(fǎng)問(wèn) pan_junbiao的博客")); blogInfoList.add(new BlogInfo(5,"pan_junbiao的博客","https://blog.csdn.net/pan_junbiao",287.33,new Date(),"您好,歡迎訪(fǎng)問(wèn) pan_junbiao的博客")); //批量新增文檔 boolean result = blogService.addBulkDocument(_indexName, blogInfoList); if(result) { System.out.println("批量新增文檔成功"); } else { System.out.println("批量新增文檔失敗"); } }
(3)使用 ElasticSearch-head 插件查看執行結果:
(1)編寫(xiě)修改文檔方法:
/** * 修改文檔 * @param indexName 索引名稱(chēng) * @param documentId 文檔ID * @param blogInfo 博客實(shí)體類(lèi) */ @Override public boolean updateDocument(String indexName, String documentId, BlogInfo blogInfo) { boolean result = false; try { //將博客信息實(shí)體類(lèi)轉換為Map格式 Map<String, Object> blogMap = toBlogMap(blogInfo); //1、構建更新文檔請求 UpdateRequest request = new UpdateRequest(indexName,documentId).doc(blogMap); //2、執行請求,返回響應結果 UpdateResponse response = restHighLevelClient.update(request,RequestOptions.DEFAULT); result = true; } catch (Exception ex) { ex.printStackTrace(); } return result; }
(2)編寫(xiě)測試方法:
/** * 測試:修改文檔 * @author pan_junbiao */ @Test public void updateDocument() { //創(chuàng )建博客實(shí)體類(lèi) BlogInfo blogInfo = new BlogInfo(); blogInfo.setBlogId(2); blogInfo.setBlogName("pan_junbiao的博客_002"); blogInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao"); blogInfo.setBlogPoints(120.68); blogInfo.setCreateDate(new Date()); blogInfo.setBlogDescribe("您好,歡迎訪(fǎng)問(wèn) pan_junbiao的博客_002"); //文檔ID(根據業(yè)務(wù),我們以博客ID作為文檔ID) String documentId = String.valueOf(blogInfo.getBlogId()); //新增文檔 boolean result = blogService.updateDocument(_indexName, documentId, blogInfo); if(result) { System.out.println("修改文檔成功"); } else { System.out.println("修改文檔失敗"); } }
(3)使用Kibana工具查看執行結果:
Elasticsearch查詢(xún)命令:GET /blog_info/_doc/2
(1)編寫(xiě)刪除文檔方法:
/** * 刪除文檔 * @param indexName 索引名稱(chēng) * @param documentId 文檔ID */ @Override public boolean deleteDocument(String indexName, String documentId) { boolean result = false; try { //1、構建刪除文檔請求 DeleteRequest request = new DeleteRequest(indexName,documentId); //2、執行刪除請求,返回響應結果 DeleteResponse deleteResponse = restHighLevelClient.delete(request,RequestOptions.DEFAULT); result = true; } catch (Exception ex) { ex.printStackTrace(); } return result; }
(2)編寫(xiě)測試方法:
/** * 測試:刪除文檔 * @author pan_junbiao */ @Test public void deleteDocument() { //刪除文檔ID為3的文檔信息 String documentId = "3"; boolean result = blogService.deleteDocument(_indexName, documentId); if(result) { System.out.println("修改文檔成功"); } else { System.out.println("修改文檔失敗"); } }
(3)使用Kibana工具查看執行結果:
Elasticsearch查詢(xún)命令:GET /blog_info/_doc/3
(1)編寫(xiě)判斷文檔是否存在方法:
/** * 判斷文檔是否存在 * @param indexName 索引名稱(chēng) * @param documentId 文檔ID */ @Override public boolean existsDocument(String indexName, String documentId) { boolean result = false; try { //1、構建請求 GetRequest getRequest = new GetRequest(indexName, documentId); //禁用提取源 getRequest.fetchSourceContext(new FetchSourceContext(false)); //禁用提取存儲字段 getRequest.storedFields("_none_"); //2、執行請求,返回結果 result = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT); } catch (Exception ex) { ex.printStackTrace(); } return result; }
(2)編寫(xiě)測試方法:
/** * 測試:判斷文檔是否存在 * @author pan_junbiao */ @Test public void existsDocument() { //判斷文檔ID為3的文檔是否存在 String documentId = "3"; boolean result = blogService.existsDocument(_indexName, documentId); if(result) { System.out.println("文檔存在"); } else { System.out.println("文檔不存在"); } }
(3)通過(guò)控制器查看執行結果:
(1)編寫(xiě)獲取文檔方法:
/** * 獲取文檔 * @param indexName 索引名稱(chēng) * @param documentId 文檔ID * @param beanType 返回結果的類(lèi)型 */ @Override public <T> T getDocumentToBean(String indexName, String documentId, Class<T> beanType) { T result = null; try { //1、構建請求 GetRequest getRequest = new GetRequest(indexName, documentId); //2、執行請求,返回響應結果 GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT); //3、解析響應結果 if (getResponse != null) { //獲取JSON結果 String jsonString = getResponse.getSourceAsString(); //使用Jackson工具,將JSON轉換為實(shí)體類(lèi) ObjectMapper mapper = new ObjectMapper(); result = mapper.readValue(jsonString, beanType); } } catch (Exception ex) { ex.printStackTrace(); } return result; }
(2)編寫(xiě)測試方法:
/** * 測試:獲取文檔 * @author pan_junbiao */ @Test public void getDocumentToBean() throws Exception { //判斷文檔ID為1的文檔信息 String documentId = "1"; BlogInfo blogInfo = blogService.getDocumentToBean(_indexName, documentId,BlogInfo.class); //打印信息 if(blogInfo!=null) { System.out.println("博客ID:" + blogInfo.getBlogId()); System.out.println("博客名稱(chēng):" + blogInfo.getBlogName()); System.out.println("博客地址:" + blogInfo.getBlogUrl()); System.out.println("博客積分:" + blogInfo.getBlogPoints()); System.out.println("創(chuàng )建時(shí)間:" + blogInfo.getCreateDate()); System.out.println("博客描述:" + blogInfo.getBlogDescribe()); } }
(3)通過(guò)控制器查看執行結果:
到此這篇關(guān)于SpringBoot整合Elasticsearch的詳細步驟(索引、文檔)的文章就介紹到這了,更多相關(guān)SpringBoot整合Elasticsearch內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站