1. 项目结构
2. Maven依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.1</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- MySQL Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies>
3. 数据库相关命令
-- 创建数据库
create database es;
-- 使用数据库
use es;
-- 创建 blog 表
CREATE TABLE blog (
id INT AUTO_INCREMENT PRIMARY KEY, -- id 字段,使用 INT 类型,并设置为自增主键
title TEXT, -- title 字段,使用 TEXT 类型来存储大文本数据
content TEXT, -- content 字段,使用 TEXT 类型来存储大文本数据
author VARCHAR(255), -- author 字段,使用 VARCHAR(255) 类型来存储字符串,适用于关键字类型(精确匹配)
published_date DATE -- publishedDate 字段,使用 DATE 类型来存储日期数据,支持范围查询和排序操作
);
-- 插入20数据
INSERT INTO `blog` (`title`, `content`, `author`, `published_date`)
VALUES ('探索区块链的实际应用', '区块链技术不仅限于数字货币,其在供应链管理中的应用同样革命性。', '张三', '2022-07-15'),
('家庭园艺的基础知识', '简单介绍如何在家里开始你的园艺活动,包括基本的园艺工具和技巧。', '李四', '2022-06-20'),
('智能家居技术的前景', '随着科技的进步,智能家居逐渐走进我们的生活,带来了便利和安全。', '王五', '2022-08-01'),
('最新科技趋势大揭秘', '2023年科技行业的五大趋势,包括AI的进步和物联网的发展。', '赵六', '2022-05-11'),
('健康饮食的误区', '讨论常见的健康饮食误区,帮助你制定更科学的饮食计划。', '钱七', '2022-04-22'),
('如何选择跑鞋', '正确的跑鞋可以提升你的跑步体验,减少受伤的风险,了解如何选择适合你的跑鞋。', '孙八',
'2022-07-08'),
('提升时间管理能力', '高效的时间管理技巧可以让你事半功倍,这里有一些实用的建议。', '周九', '2022-03-30'),
('深入理解云计算', '云计算如何改变企业 IT 架构和成本效益,以及如何选择合适的云服务提供商。', '吴十', '2022-08-15'),
('精致咖啡的冲泡技巧', '从咖啡豆的选择到冲泡方法,一步步教你制作精致的咖啡。', '郑十一', '2022-07-18'),
('职场软技能的重要性', '软技能对职业发展同样重要,了解哪些软技能是你职业生涯的加分项。', '王十二', '2022-06-06'),
('程序员的学习路径', '如何成为一名成功的程序员?这里有一些关于学习路径和资源的建议。', '李十三', '2022-05-20'),
('数据分析的基本工具', '初学者如何入门数据分析,这些工具和技巧你不能错过。', '张十四', '2022-04-07'),
('运动对心理健康的好处', '运动不仅可以改善你的身体健康,还能提升你的心理状态。', '赵十五', '2022-03-15'),
('数字营销的最佳实践', '掌握数字营销的关键技巧,让你的业务在竞争激烈的市场中脱颖而出。', '周十六', '2022-08-10'),
('城市园林的设计原则', '城市园林设计不仅要美观,还应考虑生态和可持续性。', '吴十七', '2022-09-09'),
('远程工作的生产力技巧', '远程工作成为常态,如何保持高效?这些技巧可以帮到你。', '钱十八', '2022-02-28'),
('宠物照护的基本常识', '拥有宠物之前,了解这些基本的照护知识是必须的。', '孙十九', '2022-01-10'),
('探索古代中国的建筑艺术', '中国古代建筑不仅雄伟,每一砖一瓦都蕴含深厚的文化意义。', '周二十', '2022-10-01'),
('电影摄影的艺术技巧', '电影摄影不同于普通摄影,了解其背后的艺术和技术。', '赵二十一', '2022-11-11'),
('创新教育方法的探索', '传统教育方法已不适应新时代,探索更有效的教育创新方法。', '王二十二', '2022-12-12');
4. application.yml
spring:
application:
name: spring_data_es
datasource:
url: jdbc:mysql://localhost:3306/es?useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
elasticsearch:
uris: http://192.168.163.128:9201,http://192.168.163.129:9202,http://192.168.163.130:9203
mybatis:
configuration:
#开启驼峰命名规则
map-underscore-to-camel-case: true
5. SpringDataEsApplication.java
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringDataEsApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDataEsApplication.class, args);
}
}
6. Blog.java
package org.example.entity;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "blog")
@JsonIgnoreProperties(ignoreUnknown = true) // 忽略未识别的字段
//indexName = "blog":指定索引的名称为 blog。
public class Blog {
@Id
// @Id: 标识 id 字段为主键。
private String id;
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
// FieldType.Text:标识 title 字段为文本类型(Text)。
// ik_max_word 分词器会将文本进行最细粒度的切分,生成尽可能多的词语,适用于需要最大化搜索命中率的场景。
// ik_smart 分词器会对文本进行智能切分,生成较少但较为精准的词语,适用于搜索时需要较高精确度的场景。
private String title;
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
private String content;
@Field(type = FieldType.Keyword)
//FieldType.Keyword:标识 author 字段为关键字类型(Keyword),适用于精确匹配。
private String author;
@Field(type = FieldType.Date)
//FieldType.Date:标识 publishedDate 字段为日期类型(Date)。
// 日期类型字段用于存储日期或时间信息,支持范围查询、排序等操作。
private String publishedDate;
}
7. BlogMapper.java
package org.example.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.example.entity.Blog;
import java.util.List;
@Mapper
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog findById(int id);
@Select("SELECT * FROM blog")
List<Blog> findAll();
}
8. BlogRepository.java
package org.example.repository;
import org.example.entity.Blog;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
public interface BlogRepository extends ElasticsearchRepository<Blog, String> {
List<Blog> findByPublishedDateBetween(String startDate, String endDate);
}
9. CustomBlogRepository.java
package org.example.repository;
import org.example.entity.Blog;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.io.IOException;
public interface CustomBlogRepository {
Page<Blog> findByContentAndTitleWithPaginationAndHighlight(String keyword, Pageable pageable) throws IOException;
}
10.CustomBlogRepositoryImpl.java
package org.example.repository.impl;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import org.example.entity.Blog;
import org.example.repository.CustomBlogRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
@Repository
public class CustomBlogRepositoryImpl implements CustomBlogRepository {
@Autowired
private ElasticsearchClient elasticsearchClient;
/**
* 根据关键词在内容和标题中查询包含该关键词的记录,并分页和高亮显示。
*
* @param keyword 查询的关键词
* @param pageable 分页参数
* @return 包含高亮显示结果的分页数据
* @throws IOException 如果执行查询时发生I/O错误
*/
@Override
public Page<Blog> findByContentAndTitleWithPaginationAndHighlight(String keyword, Pageable pageable) throws IOException {
// 构建布尔查询,匹配标题或内容包含关键词的记录
Query query = QueryBuilders.bool()
.should(QueryBuilders.match().field("title").query(keyword).build()._toQuery())
.should(QueryBuilders.match().field("content").query(keyword).build()._toQuery())
.build()._toQuery();
// 构建搜索请求,设置索引、查询条件、高亮设置、分页参数
SearchRequest searchRequest = new SearchRequest.Builder()
.index("blog")
.query(query)
.highlight(h -> h
.fields("title", f -> f.preTags("<strong>").postTags("</strong>"))
.fields("content", f -> f.preTags("<strong>").postTags("</strong>"))
)
.from((int) pageable.getOffset())
.size(pageable.getPageSize())
.build();
// 执行搜索请求
SearchResponse<Blog> searchResponse = elasticsearchClient.search(searchRequest, Blog.class);
HitsMetadata<Blog> hitsMetadata = searchResponse.hits();
// 处理搜索结果,提取高亮信息并设置到对应的Blog对象中
List<Blog> blogs = hitsMetadata.hits().stream()
.map(hit -> {
Blog blog = hit.source(); // 获取原始Blog对象
if (hit.highlight() != null) { // 检查是否存在高亮信息
if (hit.highlight().get("title") != null) {
// 设置高亮后的标题
blog.setTitle(String.join(" ", hit.highlight().get("title")));
}
if (hit.highlight().get("content") != null) {
// 设置高亮后的内容
blog.setContent(String.join(" ", hit.highlight().get("content")));
}
}
return blog;
})
.collect(Collectors.toList());
// 返回包含分页和高亮结果的Page对象
return new PageImpl<>(blogs, pageable, hitsMetadata.total().value());
}
}
11. ElasticsearchConfig.java
package org.example.config;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ElasticsearchConfig {
@Bean
public ElasticsearchClient elasticsearchClient() {
RestClient restClient = RestClient.builder(
new HttpHost("192.168.163.128", 9201, "http"),
new HttpHost("192.168.163.129", 9202, "http"),
new HttpHost("192.168.163.130", 9203, "http")
).build();
RestClientTransport transport = new RestClientTransport(
restClient, new JacksonJsonpMapper());
return new ElasticsearchClient(transport);
}
}
12. SpringDataEsApplicationTests.java
package org.example;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.indices.DeleteIndexRequest;
import org.example.entity.Blog;
import org.example.mapper.BlogMapper;
import org.example.repository.BlogRepository;
import org.example.repository.CustomBlogRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import java.io.IOException;
import java.util.List;
@SpringBootTest
public class SpringDataEsApplicationTests {
@Autowired
private BlogMapper blogMapper;
@Autowired
private BlogRepository blogRepository;
@Autowired
private ElasticsearchClient elasticsearchClient;
@Autowired
private CustomBlogRepository customBlogRepository;
/**
* 删除存在的索引
*
* @throws IOException 如果执行删除操作时发生I/O错误
*/
@Test
public void delete_index() throws IOException {
deleteIndexIfExists("blog");
}
/**
* 查询数据库中的单个数据
*/
@Test
public void testFindById() {
Blog blog = blogMapper.findById(1);
System.out.println(blog);
}
/**
* 查询数据库中的全部数据
*/
@Test
public void testFindAll() {
blogMapper.findAll().forEach(System.out::println);
}
/**
* 删除指定索引(如果存在)
*
* @param indexName 索引名称
* @throws IOException 如果执行删除操作时发生I/O错误
*/
private void deleteIndexIfExists(String indexName) throws IOException {
// 检查索引是否存在
boolean exists = elasticsearchClient.indices().exists(c -> c.index(indexName)).value();
if (exists) {
// 构建删除索引请求
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest.Builder().index(indexName).build();
// 执行删除索引操作
elasticsearchClient.indices().delete(deleteIndexRequest);
}
}
/**
* 测试将单个记录保存到Elasticsearch中
*/
@Test
public void testSaveToElasticsearchById() {
int id = 1;
// 从数据库中查询 id 为 1 的记录
Blog blog = blogMapper.findById(id);
System.out.println("Mybatis:" + blog);
// 将查询到的记录插入到 Elasticsearch
blogRepository.save(blog);
// 从Elasticsearch查询数据
Blog findBlog = blogRepository.findById(String.valueOf(id)).orElse(null);
System.out.println("Doc查询:" + findBlog);
}
/**
* 测试将所有记录保存到Elasticsearch中
*/
@Test
public void testSaveAllToElasticsearch() {
// 将数据库所有记录插入到 Elasticsearch
blogRepository.saveAll(blogMapper.findAll());
// 查看所有插入doc的文档
Iterable<Blog> blogs = blogRepository.findAll();
blogs.forEach(System.out::println);
}
/**
* 测试根据发布日期范围查询记录
*/
@Test
public void testFindByPublishedDateBetween() {
// 定义日期范围
String startDate = "2022-04-01";
String endDate = "2022-08-31";
// 使用自定义查询方法查询日期在2022-04-01到2022-08-31之间的记录
List<Blog> blogs = blogRepository.findByPublishedDateBetween(startDate, endDate);
blogs.forEach(blog -> System.out.println("Doc查询:" + blog));
}
/**
* 测试更新Elasticsearch中的记录
*/
@Test
public void testUpdateInElasticsearch() {
int id = 1;
// 从数据库中查询 id 为 1 的记录
Blog blog = blogMapper.findById(id);
System.out.println("Mybatis:" + blog);
// 更新记录内容
String title = "Updated"+blog.getTitle();
blog.setTitle(title);
// 将更新后的记录插入到 Elasticsearch
blogRepository.save(blog);
// 从Elasticsearch查询更新后的数据
Blog updatedBlog = blogRepository.findById(String.valueOf(id)).orElse(null);
System.out.println("Updated Doc查询:" + updatedBlog);
}
/**
* 测试从Elasticsearch中删除记录
*/
@Test
public void testDeleteFromElasticsearch() {
int id = 1;
// 删除Elasticsearch中的记录
blogRepository.deleteById(String.valueOf(id));
// 确认记录已删除
boolean exists = blogRepository.existsById(String.valueOf(id));
System.out.println("记录是否存在:" + exists);
}
/**
* 测试从Elasticsearch中分页查询记录
*/
@Test
public void testFindAllWithPagination() {
// 分页参数
PageRequest pageable = PageRequest.of(0, 10);
// 分页查询所有记录
Page<Blog> page = blogRepository.findAll(pageable);
// 处理查询结果
List<Blog> blogs = page.getContent();
blogs.forEach(blog -> System.out.println("分页查询:" + blog));
}
/**
* 测试检查记录是否存在
*/
@Test
public void testExistsById() {
int id = 1;
// 检查记录是否存在
boolean exists = blogRepository.existsById(String.valueOf(id));
System.out.println("记录是否存在:" + exists);
}
/**
* 测试自定义查询,根据内容和标题查询,并分页和高亮显示
*
* @throws IOException 如果执行查询操作时发生I/O错误
*/
@Test
public void testFindByContentAndTitleWithPaginationAndHighlight() throws IOException {
// 关键词
String keyword = "科技";
// 分页参数
PageRequest pageable = PageRequest.of(0, 10);
// 使用自定义查询方法查询标题和内容包含关键词"科技"的记录,并分页和高亮
Page<Blog> page = customBlogRepository.findByContentAndTitleWithPaginationAndHighlight(keyword, pageable);
// 处理查询结果
List<Blog> blogs = page.getContent();
blogs.forEach(blog -> System.out.println("自定义查询:" + blog));
}
}
13. 运行结果
1.1 在idea测试
16:51:39.712 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration org.example.SpringDataEsApplication for test class org.example.SpringDataEsApplicationTests
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/:: Spring Boot :: (v3.3.1)
2024-07-18T16:51:44.137+08:00 INFO 25528 --- [spring_data_es] [ main] o.example.SpringDataEsApplicationTests : Starting SpringDataEsApplicationTests using Java 22.0.1 with PID 25528 (started by i in E:\ideaProject\spring_data_es)
2024-07-18T16:51:44.162+08:00 INFO 25528 --- [spring_data_es] [ main] o.example.SpringDataEsApplicationTests : No active profile set, falling back to 1 default profile: "default"
2024-07-18T16:51:48.137+08:00 INFO 25528 --- [spring_data_es] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Elasticsearch repositories in DEFAULT mode.
2024-07-18T16:51:48.357+08:00 INFO 25528 --- [spring_data_es] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 199 ms. Found 1 Elasticsearch repository interface.
2024-07-18T16:51:48.394+08:00 INFO 25528 --- [spring_data_es] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Reactive Elasticsearch repositories in DEFAULT mode.
2024-07-18T16:51:48.420+08:00 INFO 25528 --- [spring_data_es] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 24 ms. Found 0 Reactive Elasticsearch repository interfaces.
2024-07-18T16:51:56.698+08:00 WARN 25528 --- [spring_data_es] [ main] .m.SimpleElasticsearchPersistentProperty : Unsupported type 'class java.lang.String' for date property 'publishedDate'.
2024-07-18T16:52:00.385+08:00 INFO 25528 --- [spring_data_es] [ main] o.example.SpringDataEsApplicationTests : Started SpringDataEsApplicationTests in 19.232 seconds (process running for 26.426)
WARNING: A Java agent has been loaded dynamically (D:\apache-maven\apache-maven-3.9.6\repository\net\bytebuddy\byte-buddy-agent\1.14.17\byte-buddy-agent-1.14.17.jar)
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
WARNING: Dynamic loading of agents will be disallowed by default in a future release
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
自定义查询:Blog(id=4, title=最新<strong>科技</strong>趋势大揭秘, content=2023年<strong>科技</strong>行业的五大趋势,包括AI的进步和物联网的发展。, author=赵六, publishedDate=2022-05-11)
自定义查询:Blog(id=3, title=智能家居技术的前景, content=随着<strong>科技</strong>的进步,智能家居逐渐走进我们的生活,带来了便利和安全。, author=王五, publishedDate=2022-08-01)
1.2 在kibana开发工具测试
执行代码
POST /blog/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"title": "科技"
}
},
{
"match": {
"content": "科技"
}
}
]
}
},
"highlight": {
"fields": {
"title": {
"pre_tags": [
"<strong>"
],
"post_tags": [
"</strong>"
]
},
"content": {
"pre_tags": [
"<strong>"
],
"post_tags": [
"</strong>"
]
}
}
},
"from": 0,
"size": 10
}
测试结果
{
"took": 2915,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 4.3247013,
"hits": [
{
"_index": "blog",
"_id": "4",
"_score": 4.3247013,
"_source": {
"_class": "org.example.entity.Blog",
"id": "4",
"title": "最新科技趋势大揭秘",
"content": "2023年科技行业的五大趋势,包括AI的进步和物联网的发展。",
"author": "赵六",
"publishedDate": "2022-05-11"
},
"highlight": {
"title": [
"最新<strong>科技</strong>趋势大揭秘"
],
"content": [
"2023年<strong>科技</strong>行业的五大趋势,包括AI的进步和物联网的发展。"
]
}
},
{
"_index": "blog",
"_id": "3",
"_score": 2.1103668,
"_source": {
"_class": "org.example.entity.Blog",
"id": "3",
"title": "智能家居技术的前景",
"content": "随着科技的进步,智能家居逐渐走进我们的生活,带来了便利和安全。",
"author": "王五",
"publishedDate": "2022-08-01"
},
"highlight": {
"content": [
"随着<strong>科技</strong>的进步,智能家居逐渐走进我们的生活,带来了便利和安全。"
]
}
}
]
}
}
14. 总结
-
Elasticsearch:一个分布式搜索引擎,用于存储和检索复杂的数据结构。它提供了强大的全文搜索能力和高效的数据索引。我们使用 Elasticsearch 集群来保证数据的高可用性和可扩展性,通过分片和副本机制来提升搜索性能和数据安全。
-
Spring Data Elasticsearch:Spring Data 提供的 Elasticsearch 支持库,用于简化与 Elasticsearch 的交互。通过
ElasticsearchRepository
和自定义仓库接口,我们可以方便地执行 CRUD 操作和复杂查询。具体包括:BlogRepository
:继承自ElasticsearchRepository
,提供基本的 CRUD 操作和自定义查询方法。CustomBlogRepository
:定义自定义查询方法,实现复杂的搜索需求,如分页和高亮显示。
-
MyBatis:一个优秀的持久层框架,用于简化数据库访问。通过 MyBatis,我们能够轻松地从关系型数据库中查询数据并与 Elasticsearch 集成。例如:
BlogMapper
:MyBatis 的 Mapper 接口,用于执行数据库查询,如根据 ID 查询博客、查询所有博客等。
-
DSL 查询:使用 Elasticsearch 的查询 DSL 来构建查询条件。在本例中,我们使用了
bool
查询和match
查询来在title
和content
字段中搜索关键词 "科技"。 -
高亮显示:通过
highlight
参数设置高亮显示字段,在搜索结果中标注出匹配关键词的部分。我们定义了pre_tags
和post_tags
,将高亮内容用<strong>
标签包裹。 -
分页:使用
from
和size
参数进行分页控制,from
指定结果的起始位置,size
指定每页返回的记录数。这有助于处理大规模数据,提供更好的用户体验。 -
Elasticsearch 客户端:通过
ElasticsearchClient
与 Elasticsearch 服务器进行低级别交互。我们使用它来执行索引管理和文档操作,如索引创建、删除、数据插入和查询等。 -
Kibana Dev Tools:一个用于与 Elasticsearch 交互的开发工具,支持在控制台中执行 DSL 查询,调试和分析搜索结果。