1. 程式人生 > >手把手教你Spring Boot2.x整合Elasticsearch(ES)

手把手教你Spring Boot2.x整合Elasticsearch(ES)

#文末會附上完整的程式碼包供大家下載參考,碼字不易,如果對你有幫助請給個點贊和關注,謝謝! #如果只是想看java對於Elasticsearch的操作可以直接看第四大點 ##一、docker部署Elasticsearch(下面簡稱es)單機版教程 ###1、部署es * 拉取es映象(這裡我使用的版本是7.5.1) docker pull docker.elastic.co/elasticsearch/elasticsearch:7.5.1 * 構建容器並啟動 docker run -di --restart=always --name=es -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms512m -Xmx512m" docker.elastic.co/elasticsearch/elasticsearch:7.5.1 ####注意:es預設佔用2G記憶體,我這裡新增 -e ES_JAVA_OPTS="-Xms512m -Xmx512m" 引數指定佔用記憶體 * 此時如果你訪問 伺服器ip:9200會出現無法訪問的情況,這是因為還需要開啟es的跨域訪問 ![](https://img2020.cnblogs.com/blog/1543487/202103/1543487-20210304192423105-1987781301.png) ###2、配置es允許跨域訪問 * 進入es的容器 docker exec -it es /bin/bash * 執行命令 `vi /usr/share/elasticsearch/config/elasticsearch.yml` 編輯配置檔案,在檔案末尾新增下面的配置然後 `wq` 儲存退出 http.cors.enabled: true http.cors.allow-origin: "*" * 執行 `exit` 命令退出容器,然後執行 `docker restart es` 命令重啟es,然後再訪問 伺服器ip:9200 ,出現下圖就表示單機版es搭建完成並可以遠端訪問了 ![](https://img2020.cnblogs.com/blog/1543487/202103/1543487-20210304192310443-1519146707.png) ###注意:如果此時出現還是無法訪問的,稍等幾分鐘後再重新整理頁面就好了,因為es重啟是需要一些時間的 ##二、Elasticsearch(下面簡稱es)安裝ik分詞器教程 ###由於es自帶沒有中文分詞器,所以這裡新增大家用的比較多的ik分詞器(注意ik分詞器的版本必須和es版本一致) * 首先執行`docker exec -it es bash`進入es的容器 * 然後執行`cd /usr/share/elasticsearch/bin/`進入bin目錄然後執行下面的命令線上安裝ik分詞器 ./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.5.1/elasticsearch-analysis-ik-7.5.1.zip * 執行`cd ../plugins/`進入plugins檢視ik分詞器是否成功安裝 ![](https://img2020.cnblogs.com/blog/1543487/202103/1543487-20210304151133551-220966758.png) ##三、Elasticsearch(下面簡稱es)安裝視覺化外掛head教程 * 拉取elasticsearch-head映象 docker pull mobz/elasticsearch-head:5 * 建立並啟動容器 docker run --restart=always --name elasticsearch-head -di -p 9100:9100 docker.io/mobz/elasticsearch-head:5 * 訪問伺服器ip:9100,然後輸入伺服器ip:9200,點選“連線”按鈕 ![](https://img2020.cnblogs.com/blog/1543487/202103/1543487-20210304192208738-1172491496.png) ##四、SpringBoot2.x整合Elasticsearch(下面簡稱es)教程 ###1、老規矩,先在pom.xml中新增es的依賴 ###2、在application.yml中新增es的配置 #elasticsearch配置 elasticsearch: rest: #es節點地址,叢集則用逗號隔開 uris: 10.24.56.154:9200 ###3、新增es的工具類ElasticSearchUtils.java,工具類中我只添加了常用的一些方法,大家可以根據需要自行完善 package com.example.study.util; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpHost; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.indices.GetIndexRequest; import org.elasticsearch.common.Strings; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.FetchSourceContext; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; /** * ElasticSearch工具類 * * @author [email protected] * @date 2021/3/4 19:34 */ @Slf4j @Component public class ElasticSearchUtils { @Value("${spring.elasticsearch.rest.uris}") private String uris; private RestHighLevelClient restHighLevelClient; /** * 在Servlet容器初始化前執行 */ @PostConstruct private void init() { try { if (restHighLevelClient != null) { restHighLevelClient.close(); } if (StringUtils.isBlank(uris)) { log.error("spring.elasticsearch.rest.uris is blank"); return; } //解析yml中的配置轉化為HttpHost陣列 String[] uriArr = uris.split(","); HttpHost[] httpHostArr = new HttpHost[uriArr.length]; int i = 0; for (String uri : uriArr) { if (StringUtils.isEmpty(uris)) { continue; } try { //拆分出ip和埠號 String[] split = uri.split(":"); String host = split[0]; String port = split[1]; HttpHost httpHost = new HttpHost(host, Integer.parseInt(port), "http"); httpHostArr[i++] = httpHost; } catch (Exception e) { log.error(e.getMessage()); } } RestClientBuilder builder = RestClient.builder(httpHostArr); restHighLevelClient = new RestHighLevelClient(builder); } catch (IOException e) { log.error(e.getMessage()); } } /** * 建立索引 * * @param index * @return */ public boolean createIndex(String index) throws IOException { if (isIndexExist(index)) { log.error("Index is exits!"); return false; } //1.建立索引請求 CreateIndexRequest request = new CreateIndexRequest(index); //2.執行客戶端請求 CreateIndexResponse response = restHighLevelClient.indices() .create(request, RequestOptions.DEFAULT); return response.isAcknowledged(); } /** * 判斷索引是否存在 * * @param index * @return */ public boolean isIndexExist(String index) throws IOException { GetIndexRequest request = new GetIndexRequest(index); return restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT); } /** * 刪除索引 * * @param index * @return */ public boolean deleteIndex(String index) throws IOException { if (!isIndexExist(index)) { log.error("Index is not exits!"); return false; } DeleteIndexRequest request = new DeleteIndexRequest(index); AcknowledgedResponse delete = restHighLevelClient.indices() .delete(request, RequestOptions.DEFAULT); return delete.isAcknowledged(); } /** * 新增/更新資料 * * @param object 要新增/更新的資料 * @param index 索引,類似資料庫 * @param id 資料ID * @return */ public String submitData(Object object, String index, String id) throws IOException { if (null == id) { return addData(object, index); } if (this.existsById(index, id)) { return this.updateDataByIdNoRealTime(object, index, id); } else { return addData(object, index, id); } } /** * 新增資料,自定義id * * @param object 要增加的資料 * @param index 索引,類似資料庫 * @param id 資料ID,為null時es隨機生成 * @return */ public String addData(Object object, String index, String id) throws IOException { if (null == id) { return addData(object, index); } if (this.existsById(index, id)) { return this.updateDataByIdNoRealTime(object, index, id); } //建立請求 IndexRequest request = new IndexRequest(index); request.id(id); request.timeout(TimeValue.timeValueSeconds(1)); //將資料放入請求 json request.source(JSON.toJSONString(object), XContentType.JSON); //客戶端傳送請求 IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT); log.info("新增資料成功 索引為: {}, response 狀態: {}, id為: {}", index, response.status().getStatus(), response.getId()); return response.getId(); } /** * 資料新增 隨機id * * @param object 要增加的資料 * @param index 索引,類似資料庫 * @return */ public String addData(Object object, String index) throws IOException { return addData(object, index, UUID.randomUUID().toString().replaceAll("-", "").toUpperCase()); } /** * 通過ID刪除資料 * * @param index 索引,類似資料庫 * @param id 資料ID * @return */ public String deleteDataById(String index, String id) throws IOException { DeleteRequest request = new DeleteRequest(index, id); DeleteResponse deleteResponse = restHighLevelClient.delete(request, RequestOptions.DEFAULT); return deleteResponse.getId(); } /** * 通過ID 更新資料 * * @param object 要更新資料 * @param index 索引,類似資料庫 * @param id 資料ID * @return */ public String updateDataById(Object object, String index, String id) throws IOException { UpdateRequest updateRequest = new UpdateRequest(index, id); updateRequest.timeout("1s"); updateRequest.doc(JSON.toJSONString(object), XContentType.JSON); UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT); log.info("索引為: {}, id為: {},updateResponseID:{}, 更新資料成功", index, id, updateResponse.getId()); return updateResponse.getId(); } /** * 通過ID 更新資料,保證實時性 * * @param object 要增加的資料 * @param index 索引,類似資料庫 * @param id 資料ID * @return */ public String updateDataByIdNoRealTime(Object object, String index, String id) throws IOException { //更新請求 UpdateRequest updateRequest = new UpdateRequest(index, id); //保證資料實時更新 updateRequest.setRefreshPolicy("wait_for"); updateRequest.timeout("1s"); updateRequest.doc(JSON.toJSONString(object), XContentType.JSON); //執行更新請求 UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT); log.info("索引為: {}, id為: {},updateResponseID:{}, 實時更新資料成功", index, id, updateResponse.getId()); return updateResponse.getId(); } /** * 通過ID獲取資料 * * @param index 索引,類似資料庫 * @param id 資料ID * @param fields 需要顯示的欄位,逗號分隔(預設為全部欄位) * @return */ pu