ElasticSearch学习笔记六:Springboot整合

ops/2024/11/27 8:18:28/

一、前言

在前一篇文章中,我们学习了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/ops/137034.html

相关文章

基础入门-Web应用架构搭建域名源码站库分离MVC模型解析受限对应路径

知识点&#xff1a; 1、基础入门-Web应用-域名上的技术要点 2、基础入门-Web应用-源码上的技术要点 3、基础入门-Web应用-数据上的技术要点 4、基础入门-Web应用-解析上的技术要点 5、基础入门-Web应用-平台上的技术要点 一、演示案例-域名差异-主站&分站&端口站&…

在远程服务器和本地同步数据的指南

在远程服务器和本地同步数据的指南 在现代软件开发和数据管理中&#xff0c;保持本地和远程服务器之间的数据同步是至关重要的。无论是代码、配置文件还是其他数据&#xff0c;确保它们在不同环境中的一致性都是高效工作的关键。本文将介绍如何使用 Bash 脚本和 rsync 工具在本…

Unity中动态生成贴图并保存成png图片实现

实现原理&#xff1a; 要生成长x宽y的贴图&#xff0c;就是生成x*y个像素填充到贴图中&#xff0c;如下图&#xff1a; 如果要改变局部颜色&#xff0c;就是从x1到x2(x1<x2),y1到y2(y1<y2)这个范围做处理&#xff0c; 或者要想做圆形就是计算距某个点&#xff08;x1,y1&…

【Python爬虫实战】深入解析 Scrapy:从阻塞与非阻塞到高效爬取的实战指南

&#x1f308;个人主页&#xff1a;易辰君-CSDN博客 &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html ​ 目录 前言 一、阻塞和非阻塞 &#xff08;一&#xff09;阻塞 &#xff08;二&#xff09;非阻塞 二、Scrapy的工作…

【c语言】文件操作详解 - 从打开到关闭

文章目录 1. 为什么使用文件&#xff1f;2. 什么是文件&#xff1f;3. 如何标识文件&#xff1f;4. 二进制文件和文本文件&#xff1f;5. 文件的打开和关闭5.1 流和标准流5.1.1 流5.1.2 标准流 5.2 文件指针5.3 文件的打开和关闭 6. 文件的读写顺序6.1 顺序读写函数6.2 对比一组…

上下文信息、全局信息、局部信息

摘要 在计算机视觉中&#xff0c;上下文信息&#xff08;contextual information&#xff09;是一个核心概念&#xff0c;它指的是一个像素或一个小区域周围的环境或背景信息。这种信息对于模型理解图像中对象的相对位置、大小、形状&#xff0c;以及与其他对象的关系至关重要…

PHP 超级全局变量

超级全局变量是指在php任意脚本下都可以使用 PHP 超级全局变量列表: $GLOBALS&#xff1a;是PHP的一个超级全局变量组&#xff0c;在一个PHP脚本的全部作用域中都可以访问。 $_SERVER&#xff1a;$_SERVER 是一个PHP内置的超级全局变量,它是一个包含了诸如头信息(header)、路…

【算法】连通块问题(C/C++)

目录 连通块问题 解决思路 步骤&#xff1a; 初始化&#xff1a; DFS函数&#xff1a; 复杂度分析 代码实现&#xff08;C&#xff09; 题目链接&#xff1a;2060. 奶牛选美 - AcWing题库 解题思路&#xff1a; AC代码&#xff1a; 题目链接&#xff1a;687. 扫雷 -…