ElasticSearch学习笔记六:Springboot整合

news/2024/11/27 15:03:32/

一、前言

在前一篇文章中,我们学习了ES中的一部分的搜索功能,作为一名Java工程师,更多时候我们是用代码去操作ES,同时对于Java而言时下最流行的就是Springboot了,所以这里我们将ES和Springboot整合将上一篇文章中的所有DSL操作,使用Java代码来操作一遍从而加深记忆。

二、创建一个Springboot项目

1、POM文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>springboot-es</artifactId><version>0.0.1-SNAPSHOT</version><name>springboot-es</name><description>springboot-es</description><properties><java.version>17</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.7.6</spring-boot.version></properties><dependencies><!--Spring Data ES--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency><!--Spring Web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--Spring Test--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--Lombok:简化开发--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>17</source><target>17</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.example.SpringbootEsApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>

依赖解释:

(1)首先我们是用的是Springboot2.7.6的版本,JDK则使用的是17,当然用JDK8也是一样的。

(2)我们是用SpringData作为操作数据的框架,当然你也可以用原生的客户端。

(3)添加了Web依赖,我们直接使用接口的形式可以更方便的看出效果

(4)lombok:则是为了简化开发,可以简单的认为是用于生成get/set方法

2、配置文件
server:port: 8088
spring:elasticsearch:uris: http://localhost:9200

这里没啥好说的,就是定义了程序运行在8088端口,同时es的地址为localhost:9200。至此Springboot和ES的整合就完成了,是不是很简单。当然这背后可一点也不简单,之所以我们可以这么简单的配置就能做好整合,是因为Springboot为我们提供的强大的自动装配,这个不在本文的范畴,暂时放下不表。

3、编写代码

在上一篇文章中,我们已经定义了索引的结构

PUT /hotel
{"mappings": {"properties": {"title":{"type": "text" },"city":{"type": "keyword"},"price":{"type": "double"},"create_time":{"type": "date","format": "yyyy-MM-dd HH:mm:ss"},"amenities":{"type": "text"},"full_room":{"type": "boolean"},"location":{"type": "geo_point"},"praise":{"type": "integer"}}}
3.1、编写实体类

按照这个索引的结构,我们创建对应的实体类,这个和我们是用Mybatis时很像,也要定义对应的实体类。

package com.example.entity;import com.fasterxml.jackson.annotation.JsonFormat;
import java.math.BigDecimal;
import java.util.Date;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;/*** @Author hardy(叶阳华)* @Description* @Date 2024/11/26 14:06*/
@Data
@Document(indexName = "hotel", createIndex = false)
public class Hotel {/*** ID*/@Idprivate String id;/*** 标题:text类型,使用ik_max_word作为分词器*/@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")private String title;/*** 所在城市:所在城市没必要分词*/@Field(type = FieldType.Keyword)private String city;/*** 价格*/@Field(type = FieldType.Double)private BigDecimal price;/*** 便利措施*/@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")private String amenities;/*** 创建时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")@Field(value = "create_time", type = FieldType.Date, format = {}, pattern = "yyyy-MM-dd HH:mm:ss")private Date createTime;/*** 是否满员*/@Field(value = "full_room", type = FieldType.Boolean)private Boolean fullRoom;/*** 位置*/@GeoPointFieldprivate GeoPoint location;@Field(type = FieldType.Integer)private Integer praise;
}

说一下笔者编写过程中碰到的小坑

(1)Date类型,如果要自定义日期的格式,需要将format设置为custom(不建议,即将被废弃),或者设置为{},否则就会提示日期转换异常

(2)地理位置,一开始笔者也以为可以直接使用@Field(type = FieldType.Point) 然后,并没有这个类型,官网上则说使用 @GeoPoint 然而还是没有,最终发现有一个@GeoPointField尝试了一下发现可以。

(3)@GeoPointField 并没有任何属性,如果我们的字段名和索引中的字段名不一致,则可以使用 @Field去标记,如

3.2、查询索引是否存在
    @Resourceprivate ElasticsearchOperations elasticsearchOperations;/*** 校验索引是否存在*/@GetMapping("checkIndexExists")public Boolean checkIndexExists() {return elasticsearchOperations.indexOps(Hotel.class).exists();}

tips:ElasticsearchOperations是SpringData为我们提供的一个工具类,用于简化开发。

执行结果

3.3、批量写入数据
  /*** 批量写入*/@PostMapping("/batchCreate")public Boolean batchCreate(@RequestBody List<Hotel> hotelList) {if (CollectionUtils.isEmpty(hotelList)) {throw new IllegalArgumentException("参数不能为空");}final Iterable<Hotel> hotels = elasticsearchOperations.save(hotelList);hotels.iterator().forEachRemaining(System.out::println);return true;}

请求参数:

[{"id": "001","title": "文雅酒店","city": "青岛","price": 556,"createTime": "2020-04-18 12:00:00","amenities": "浴池,普通停车场/充电停车场","fullRoom": false,"location": {"lat": 36.083078,"lon": 120.37566},"praise": 10},{"id": "002","title": "金都嘉怡假日酒店","city": "北京","price": 337,"createTime": "2021-03-15 20:00:00","amenities": "wifi,充电停车场/可升降停车场","fullRoom": false,"location": {"lat": 39.915153,"lon": 116.403},"praise": 60},{"id": "003","itle": "金都欣欣酒店","city": "天津","price": 200,"createTime": "2021-05-09 16:00:00","amenities": "提供假日party,免费早餐,可充电停车场","fullRoom": true,"location": {"lat": 39.186555,"lon": 117.162007},"praise": 30},{"id": "004","title": "金都酒店","city": "北京","price": 500,"createTime": "2021-02-18 08:00:00","amenities": "浴池(假日需预定),室内游泳池,普通停车场","fullRoom": true,"location": {"lat": 39.915343,"lon": 116.4239},"praise": 20},{"id": "005","title": "文雅精选酒店","city": "北京","price": 800,"createTime": "2021-01-01 08:00:00","amenities": "浴池(假日需预定),wifi,室内游泳池,普通停车场","fullRoom": true,"location": {"lat": 39.918229,"lon": 116.422011},"praise": 20}
]

结果:

3.4、查询所有数据
@GetMapping("/queryAll")
public List<Hotel> queryAll() {Criteria criteria = new Criteria();Query query = new CriteriaQuery(criteria);final SearchHits<Hotel> searchHits = elasticsearchOperations.search(query, Hotel.class);//没有命中任何文档if (!searchHits.hasSearchHits()) {return new ArrayList<>();}return searchHits.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
}

结果:

3.5、分页查询
   @GetMapping("/pageQuery")public Page<Hotel> pageQuery(String city, int pageNo, int pageSize) {Criteria criteria = Criteria.where("city").is(city);PageRequest pageRequest = PageRequest.of(pageNo, pageSize);Query query = new CriteriaQuery(criteria);query.setPageable(pageRequest);final SearchHits<Hotel> searchHits = elasticsearchOperations.search(query, Hotel.class);if (!searchHits.hasSearchHits()) {return new PageImpl<>(new ArrayList<>());}List<Hotel> hotels = searchHits.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());//总记录数final long totalHits = searchHits.getTotalHits();// 返回分页结果return new PageImpl<>(hotels, pageRequest, totalHits);}

结果:

{"content": [{"id": "002","title": "金都嘉怡假日酒店","city": "北京","price": 337,"amenities": "wifi,充电停车场/可升降停车场","createTime": "2021-03-15 20:00:00","fullRoom": false,"location": {"lat": 39.915153,"lon": 116.403},"praise": 60},{"id": "004","title": "金都酒店","city": "北京","price": 500,"amenities": "浴池(假日需预定),室内游泳池,普通停车场","createTime": "2021-02-18 08:00:00","fullRoom": true,"location": {"lat": 39.915343,"lon": 116.4239},"praise": 20},{"id": "005","title": "文雅精选酒店","city": "北京","price": 800,"amenities": "浴池(假日需预定),wifi,室内游泳池,普通停车场","createTime": "2021-01-01 08:00:00","fullRoom": true,"location": {"lat": 39.918229,"lon": 116.422011},"praise": 20}],"pageable": {"sort": {"empty": true,"unsorted": true,"sorted": false},"offset": 0,"pageNumber": 0,"pageSize": 3,"paged": true,"unpaged": false},"last": true,"totalPages": 1,"totalElements": 3,"first": true,"size": 3,"number": 0,"sort": {"empty": true,"unsorted": true,"sorted": false},"numberOfElements": 3,"empty": false
}
和上面直接返回所有数据不同,分页查询还会返回分页相关信息

三、结束语

至此Springboot和ES已经整合,并且做了一些基础的查询操作,后续我们会继续审核ES的查询,更多的复杂的查询在后面的文章中,希望对你有所帮助。


http://www.ppmy.cn/news/1550374.html

相关文章

【C++】读取数量不定的输入数据

读取数量不定的输入数据 似乎是一个很实用的东西&#xff1f; 问题&#xff1a; 我们如何对用户输入的一组数&#xff08;事先不知道具体有多少个数&#xff09;求和&#xff1f; 这需要不断读取数据直至没有新的输入为止。&#xff08;所以我们的代码就是这样设计的&#x…

淘宝/天猫按图搜索(拍立淘)API的深度解析与应用实践

在数字化时代&#xff0c;电商行业的快速发展带来了消费者购物习惯的转变&#xff0c;个性化、便捷性和高效性成为新的购物需求。淘宝/天猫作为国内领先的电商平台&#xff0c;推出了按图搜索&#xff08;拍立淘&#xff09;API&#xff0c;这一功能通过图像识别技术&#xff0…

鸿蒙HarmonyOS系统相机Camera相关API使用

HarmonyOS下Camera相机相关API使用 准备工作 1. 导入camera接口 import { camera } from kit.CameraKit; import { BusinessError } from kit.BasicServicesKit; import { common } from kit.AbilityKit;2.获取cameraManager对象 getCameraManager(): camera.CameraManager…

大模型面试题:能简单说下attention中存在的问吗?

我整理了1000道算法面试题&#xff1a; 获取 先说结论&#xff1a;从Attention is not all you need 这篇论文来看&#xff0c;单纯的不加残差连接且不加MLP的多层多头的Attention堆叠会导致模型输出的秩坍缩到rank-1的矩阵&#xff0c;也就是最后所有的表征都趋向于同一个向量…

训练的decoder模型文本长度不一致,一般设置为多大合适,需要覆盖最长的文本长度么

在训练解码器模型时,文本长度不一致是常见的情况,需要根据任务的特性和数据集的长度分布来设置合理的最大长度 (max_length)。以下是一些指导原则,帮助你设置合适的最大长度: 1. 是否需要覆盖最长文本长度 覆盖最长文本长度: 如果任务对完整性要求很高(例如生成数学公式、…

银行卡OCR 识别 API 接口如何用Java如何调用

银行卡 OCR 识别是利用光学字符识别技术&#xff0c;对银行卡上的卡号、有效期、持卡人姓名等信息进行快速、准确识别的过程。而银行卡 OCR 识别 API 接口则是将这种识别能力以接口的形式提供给开发者&#xff0c;使其能够轻松地集成到各种应用程序中&#xff0c;实现对银行卡信…

Mac——鼠标增强插件Mos

功能说明&#xff1a; 能够解决鼠标断续、不灵敏等鼠标问题。 下载地址&#xff1a; Mac——鼠标增强插件Mos

【面试题】2025年百度校招Java后端面试题

文章目录 前言一、网络IO1、服务器处理并发请求有哪几种方式&#xff1f;2、说一下select&#xff0c;poll&#xff0c;epoll的区别&#xff1f;3、Java 有一种现代的处理方式&#xff0c;属于异步I/O&#xff0c;是什么&#xff1f;redis&#xff0c;nginx&#xff0c;netty 是…