Spring Data Elasticsearch和集群简单实现高亮和分页显示

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 查询,调试和分析搜索结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值