SpringBoot3集成ElasticSearch的方法詳解
一、簡介
Elasticsearch是一個分布式、RESTful風格的搜索和數據分析引擎,適用于各種數據類型,數字、文本、地理位置、結構化數據、非結構化數據;
在實際的工作中,歷經過Elasticsearch從 6.0
到 7.0
的版本升級,而這次SpringBoot3和ES8.0的集成,雖然腳本的語法變化很小,但是Java客戶端的API語法變化很大;
二、環(huán)境搭建
1、下載安裝包
需要注意的是,這些安裝包的版本要選擇對應的,不然容易出問題;
軟件包:elasticsearch-8.8.2-darwin-x86_64.tar.gz 分詞器工具:elasticsearch-analysis-ik-8.8.2.zip 可視化工具:kibana-8.8.2-darwin-x86_64.tar.gz
2、服務啟動
不論是ES還是Kibana,在首次啟動后,會初始化很多配置文件,可以根據自己的需要做相關的配置調整,比如常見的端口調整,資源占用,安全校驗等;
1、啟動ES elasticsearch-8.8.2/bin/elasticsearch 本地訪問:localhost:9200 2、啟動Kibana kibana-8.8.2/bin/kibana 本地訪問:http://localhost:5601 # 3、查看安裝的插件 http://localhost:9200/_cat/plugins -> analysis-ik 8.8.2
三、工程搭建
1、工程結構
2、依賴管理
在 starter-elasticsearch
組件中,實際上依賴的是 elasticsearch-java
組件的 8.7.1
版本;
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> <version>${spring-boot.version}</version> </dependency>
3、配置文件
在上面環(huán)境搭建的過程中,已經禁用了用戶和密碼的登錄驗證,配置ES服務地址即可;
spring: # ElasticSearch配置 elasticsearch: uris: localhost:9200
四、基礎用法
1、實體類
通過 Document
和 Field
注解描述ES索引結構的實體類,注意這里 JsonIgnoreProperties
注解,解決索引中字段和實體類非一一對應的而引起的JSON解析問題;
@JsonIgnoreProperties(ignoreUnknown = true) @Document(indexName = "contents_index", createIndex = false) public class ContentsIndex implements Serializable { private static final long serialVersionUID=1L; @Field(type= FieldType.Integer) private Integer id; @Field(type= FieldType.Keyword) private String title; @Field(type= FieldType.Keyword) private String intro; @Field(type= FieldType.Text) private String content; @Field(type= FieldType.Integer) private Integer createId; @Field(type= FieldType.Keyword) private String createName; @Field(type= FieldType.Date,format = DateFormat.date_hour_minute_second) private Date createTime; }
2、初始化索引
基于 ElasticsearchTemplate
類和上述實體類,實現索引結構的初始化,并且將 tb_contents
表中的數據同步到索引中,最后通過ID查詢一條測試數據;
@Service public class ContentsIndexService { private static final Logger log = LoggerFactory.getLogger(ContentsIndexService.class); @Resource private ContentsService contentsService ; @Resource private ElasticsearchTemplate template ; /** * 初始化索引結構和數據 */ public void initIndex (){ // 處理索引結構 IndexOperations indexOps = template.indexOps(ContentsIndex.class); if (indexOps.exists()){ boolean delFlag = indexOps.delete(); log.info("contents_index exists,delete:{}",delFlag); indexOps.createMapping(ContentsIndex.class); } else { log.info("contents_index not exists"); indexOps.createMapping(ContentsIndex.class); } // 同步數據庫表記錄 List<Contents> contentsList = contentsService.queryAll(); if (contentsList.size() > 0){ List<ContentsIndex> contentsIndexList = new ArrayList<>() ; contentsList.forEach(contents -> { ContentsIndex contentsIndex = new ContentsIndex() ; BeanUtils.copyProperties(contents,contentsIndex); contentsIndexList.add(contentsIndex); }); template.save(contentsIndexList); } // ID查詢 ContentsIndex contentsIndex = template.get("10",ContentsIndex.class); log.info("contents-index-10:{}",contentsIndex); } }
3、倉儲接口
繼承 ElasticsearchRepository
接口,可以對ES這種特定類型的存儲庫進行通用增刪改查操作;在測試類中對該接口的方法進行測試;
// 1、接口定義 public interface ContentsIndexRepository extends ElasticsearchRepository<ContentsIndex,Long> { } // 2、接口測試 public class ContentsIndexRepositoryTest { @Autowired private ContentsIndexRepository contentsIndexRepository; @Test public void testAdd (){ // 單個新增 contentsIndexRepository.save(buildOne()); // 批量新增 contentsIndexRepository.saveAll(buildList()) ; } @Test public void testUpdate (){ // 根據ID查詢后再更新 Optional<ContentsIndex> contentsOpt = contentsIndexRepository.findById(14L); if (contentsOpt.isPresent()){ ContentsIndex contentsId = contentsOpt.get(); System.out.println("id=14:"+contentsId); contentsId.setContent("update-content"); contentsId.setCreateTime(new Date()); contentsIndexRepository.save(contentsId); } } @Test public void testQuery (){ // 單個ID查詢 Optional<ContentsIndex> contentsOpt = contentsIndexRepository.findById(1L); if (contentsOpt.isPresent()){ ContentsIndex contentsId1 = contentsOpt.get(); System.out.println("id=1:"+contentsId1); } // 批量ID查詢 Iterator<ContentsIndex> contentsIterator = contentsIndexRepository .findAllById(Arrays.asList(10L,12L)).iterator(); while (contentsIterator.hasNext()){ ContentsIndex contentsIndex = contentsIterator.next(); System.out.println("id="+contentsIndex.getId()+":"+contentsIndex); } } @Test public void testDelete (){ contentsIndexRepository.deleteById(15L); contentsIndexRepository.deleteById(16L); } }
4、查詢語法
無論是 ElasticsearchTemplate
類還是 ElasticsearchRepository
接口,都是對ES常用的簡單功能進行封裝,在實際使用時,復雜的查詢語法還是依賴 ElasticsearchClient
和原生的API封裝;
這里主要演示七個查詢方法,主要涉及:ID查詢,字段匹配,組合與范圍查詢,分頁與排序,分組統(tǒng)計,最大值查詢和模糊匹配;更多的查詢API還是要多看文檔中的案例才行;
public class ElasticsearchClientTest { @Autowired private ElasticsearchClient client ; @Test public void testSearch1 () throws IOException { // ID查詢 GetResponse<ContentsIndex> resp = client.get( getReq ->getReq.index("contents_index").id("7"), ContentsIndex.class); if (resp.found()){ ContentsIndex contentsIndex = resp.source() ; System.out.println("contentsIndex-7:"+contentsIndex); } } @Test public void testSearch2 () throws IOException { // 指定字段匹配 SearchResponse<ContentsIndex> resp = client.search(searchReq -> searchReq.index("contents_index") .query(query -> query.match(field -> field .field("createName").query("張三"))),ContentsIndex.class); printResp(resp); } @Test public void testSearch3 () throws IOException { // 組合查詢:姓名和時間范圍 Query byName = MatchQuery.of(field -> field.field("createName").query("王五"))._toQuery(); Query byTime = RangeQuery.of(field -> field.field("createTime") .gte(JsonData.of("2023-07-10T00:00:00")) .lte(JsonData.of("2023-07-12T00:00:00")))._toQuery(); SearchResponse<ContentsIndex> resp = client.search(searchReq -> searchReq.index("contents_index") .query(query -> query.bool(boolQuery -> boolQuery.must(byName).must(byTime))),ContentsIndex.class); printResp(resp); } @Test public void testSearch4 () throws IOException { // 排序和分頁,在14條數據中,根據ID倒序排列,從第5條往后取4條數據 SearchResponse<ContentsIndex> resp = client.search(searchReq -> searchReq.index("contents_index") .from(5).size(4) .sort(sort -> sort.field(sortField -> sortField.field("id").order(SortOrder.Desc))),ContentsIndex.class); printResp(resp); } @Test public void testSearch5 () throws IOException { // 根據createId分組統(tǒng)計 SearchResponse<ContentsIndex> resp = client.search(searchReq -> searchReq.index("contents_index") .aggregations("createIdGroup",agg -> agg.terms(term -> term.field("createId"))),ContentsIndex.class); Aggregate aggregate = resp.aggregations().get("createIdGroup"); LongTermsAggregate termsAggregate = aggregate.lterms(); Buckets<LongTermsBucket> buckets = termsAggregate.buckets(); for (LongTermsBucket termsBucket : buckets.array()) { System.out.println(termsBucket.key() + " : " + termsBucket.docCount()); } } @Test public void testSearch6 () throws IOException { // 查詢最大的ID SearchResponse<ContentsIndex> resp = client.search(searchReq -> searchReq.index("contents_index") .aggregations("maxId",agg -> agg.max(field -> field.field("id"))),ContentsIndex.class); for (Map.Entry<String, Aggregate> entry : resp.aggregations().entrySet()){ System.out.println(entry.getKey()+":"+entry.getValue().max().value()); } } @Test public void testSearch7 () throws IOException { // 模糊查詢title字段,允許1個誤差 Query byContent = FuzzyQuery.of(field -> field.field("title").value("設計").fuzziness("1"))._toQuery(); SearchResponse<ContentsIndex> resp = client.search( searchReq -> searchReq.index("contents_index").query(byContent),ContentsIndex.class); printResp(resp); } private void printResp (SearchResponse<ContentsIndex> resp){ TotalHits total = resp.hits().total(); System.out.println("total:"+total); List<Hit<ContentsIndex>> hits = resp.hits().hits(); for (Hit<ContentsIndex> hit: hits) { ContentsIndex contentsIndex = hit.source(); System.out.println(hit.id()+":"+contentsIndex); } } }
五、參考源碼
文檔倉庫: https://gitee.com/cicadasmile/butte-java-note 源碼倉庫: https://gitee.com/cicadasmile/butte-spring-parent
文檔倉庫:https://gitee.com/cicadasmile/butte-java-note
以上就是SpringBoot3集成ElasticSearch的方法詳解的詳細內容,更多關于SpringBoot3集成ElasticSearch的資料請關注腳本之家其它相關文章!
相關文章
java使double保留兩位小數的多方法 java保留兩位小數
這篇文章主要介紹了java使double類型保留兩位小數的方法,大家參考使用吧2014-01-01SpringBoot集成RabbitMQ實現用戶注冊的示例代碼
這篇文章主要介紹了SpringBoot集成RabbitMQ實現用戶注冊的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-12-12springboot打包無法讀取yml、properties等配置文件的解決
這篇文章主要介紹了springboot打包無法讀取yml、properties等配置文件的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-04-04