返回 导航

SpringBoot / Cloud

hangge.com

SpringBoot - Spring Data Elasticsearch使用详解2(使用ElasticsearchRepository)

作者:hangge | 2025-05-28 10:36
    Spring Data Elasticsearch 提供了两种不同方式用于与 Elasticsearch 进行交互的,分别是 ElasticsearchRestTemplate 和 ElasticsearchRepository。我在之前的文章中详细介绍了前者的使用(点击查看),本文接着介绍 ElasticsearchRepository 的使用。

一、基本介绍

1,Spring Data Elasticsearch 介绍

(1)Spring Data Elasticsearch 是 Spring Data 项目的一部分,旨在提供对 Elasticsearch 的高级、更抽象的面向对象的数据访问。让我们可以像使用数据库一样,使用简单的 CRUD(创建、读取、更新、删除)操作来与 Elasticsearch 交互。

(2)Spring Data Elasticsearch 中提供了两种不同方式用于与 Elasticsearch 进行交互的,分别是 ElasticsearchRestTemplate 和 ElasticsearchRepository。

2,ElasticsearchRestTemplate 介绍

(1)ElasticsearchRestTemplate 是 Spring Data Elasticsearch 提供的一个强大的 Elasticsearch 客户端,它提供了直接与 Elasticsearch 进行交互的方法。

(2)使用 ElasticsearchRestTemplate,我们可以执行各种 Elasticsearch 操作,如索引创建、数据检索、更新和删除等。

(3)使用 ElasticsearchRestTemplate 这是一个相对底层的方式,我们需要编写自己的 Elasticsearch 查询语句,但也提供了更大的灵活性。

3,ElasticsearchRepository 介绍

(1)ElasticsearchRepository 是 Spring Data Elasticsearch 提供的一种高级抽象,它基于 Spring Data 的 Repository 模式,允许我们定义接口并使用 Spring Data 自动生成查询。

(2)通过继承 ElasticsearchRepository 接口,我们可以获得一些常见的 CRUD 操作,而无需编写太多的实现代码。

(3)这是一种更高层次的抽象,适用于简单的场景,但可能在复杂的查询上缺乏一些灵活性。

4,ElasticsearchRestTemplate 和 ElasticsearchRepository 的选择建议

(1)如果我们需要更多的灵活性,对 Elasticsearch 的操作有更多的控制,并且可以编写自己的查询语句,那么使用 ElasticsearchRestTemplate 可能更适合。

(2)如果我们只需要进行一些基本的 CRUD 操作,而且想要利用 Spring Data 提供的自动化功能,那么使用 ElasticsearchRepository 可能更方便。

二、安装配置

1,添加依赖

在 Spring Boot 项目的 pom.xml 文件中添加相关依赖:
提示:spring-boot-starter-data-elasticsearch 这个依赖会包含 Elasticsearch 的 Java API 和 Spring Data Elasticsearch 模块。
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

2,配置连接信息

在项目的 application.properties 文件中配置 Elasticsearch 的连接信息:
spring.elasticsearch.rest.uris=192.168.60.9:9200,192.168.60.10:9200,192.168.60.11:9200

三、准备工作

1,创建实体类

    在使用 Spring Data Elasticsearch 时,我们需要使用注解来定义实体类,从而告诉 Spring Data Elasticsearch 如何映射数据到 Elasticsearch 中的文档。下面我们创建一个表示图书信息的 Book 实体类。
注意:书籍的标题字段 title 和简介字段 introduction 配置了 IK 分词器以支持后续的中文检索。ik_max_word 和 ik_smart 区别:
  • ik_max_word 会将文本做最细粒度的拆分。
  • ik_smart 会做最粗粒度的拆分。
@Document(indexName = "book")
@Data
public class Book {
  @Id
  private Long id; // 书籍的唯一标识符

  @Field(type = FieldType.Text, analyzer = "ik_max_word")
  private String title; // 书籍的标题

  @Field(type = FieldType.Keyword)
  private String author; // 书籍的作者

  private Integer price; // 书籍的价格

  @Field(type = FieldType.Text, analyzer = "ik_max_word")
  private String introduction; // 书籍的简介
}

2,编写 Elasticsearch Repository 接口

  在 Spring Data Elasticsearch 中,可以使用 Repository 接口来定义 Elasticsearch 的增删改查操作。下面我们定义一个 BookRepository 接口,继承自 ElasticsearchRepository,并指定实体类(Book)和主键的类型(Long)
public interface BookRepository extends ElasticsearchRepository<Book, Long> {
}

四、使用 ElasticsearchRepository 通过主键实现索引的增、删、改、查

1,新增数据

(1)下面代码使用 BookRepository 来新增一条数据:
@RestController
public class BookController {
  @Autowired
  private BookRepository bookRepository;

  @GetMapping("/test")
  public void test() {
    // 添加书籍数据
    Book book = new Book();
    book.setId(1L);
    book.setTitle("汉书");
    book.setAuthor("班固");
    book.setPrice(268);
    book.setIntroduction("《汉书》是中国第一部纪传体断代史,全书记述了自西汉的汉高祖元年" +
            "至新朝王莽地皇四年,共二百三十年史事。");
    bookRepository.save(book);
  }
}

(2)BookRepository 同样支持批量新增数据:
@RestController
public class BookController {
  @Autowired
  private BookRepository bookRepository;

  @GetMapping("/test")
  public void test() {
    // 批量添加书籍数据
    ArrayList<Book> books = new ArrayList<>();
    Book book1 = new Book();
    book1.setId(2L);
    book1.setTitle("史记");
    book1.setAuthor("司马迁");
    book1.setPrice(28);
    book1.setIntroduction("《史记》是我国著名史学家司马迁所著的史学巨著,列“二十四史”之首," +
            "记载了从传说中的黄帝开始一直到汉武帝元狩元年(前122)三千年左右的历史," +
            "被誉为“史家之绝唱,无韵之《离骚》”。读中国历史,不能不读《史记》。");
    books.add(book1);
    Book book2 = new Book();
    book2.setId(3L);
    book2.setTitle("资治通鉴");
    book2.setAuthor("司马光");
    book2.setPrice(498);
    book2.setIntroduction("《资治通鉴》是中国古代著名的编年体史书,记载了战国至五代期间1300多年的历史," +
            "向为史学界所推崇,在收集史料、考订事实及文字剪裁润色等方面都代表了古代编年体史书的最高成就");
    books.add(book2);
    bookRepository.saveAll(books);
  }
}

2,更新数据

通过使用 BookRepository 的 save 方法可以实现数据更新。如果指定 ID 的索引数据(文档)已经存在,则执行更新操作。
注意:ElasticsearchRepository 提供了一些基本的 CRUD 操作,但它不直接支持部分更新。然而,我们可以使用 elasticsearchTemplate 来执行原生的 Elasticsearch 操作,从而实现部分更新,具体可以查看我之前写的文章(点击访问)。
Book book = new Book();
book.setId(1L);
book.setTitle("战争与和平");
book.setAuthor("托尔斯泰");
book.setPrice(88);
book.setIntroduction("《战争与和平》描写1812年俄法战争的全过程,以当时四大贵族家庭的人物活动为线索," +
        "反映了1805至1820年间许多重大的历史事件,以及各阶层的现实生活。");
bookRepository.save(book);

3,删除数据

(1)下面代码删除类型对应的索引中的指定主键数据。
bookRepository.deleteById(1L);

(2)我们也可以删除所有的数据:
bookRepository.deleteAll();

4,查询数据

(1)下面代码查询主键为 2 的文档数据:
Optional<Book> optional = bookRepository.findById(2L);
System.out.println(optional.get());

(2)我们也可以查询所有的数据:
Iterable<Book> all = bookRepository.findAll();
all.forEach(System.out::println);

五、使用 ElasticsearchRepository 的自定义方法进行查询

1,基本介绍

(1)Spring Data 的另一个强大功能,是根据方法名称自动实现功能。比如:我们在 BookRepository 中添加一个 findByAuthor 方法,那么就是根据 author 查询,无需写实现类。
public interface BookRepository extends ElasticsearchRepository<Book, Long> {
  // 根据作者名进行查询
  List<Book> findByAuthor(String author);
}

(2)测试使用如下:
List<Book> book = bookRepository.findByAuthor("司马迁");
System.out.println(book);

2,约定规则

提示:我们定义的方法要遵循一些命名约定规则,以便 Spring Data 能够正确地解析方法名称并生成对应的 Elasticsearch 查询。
(1)按字段查询:
  • findBy<FieldName>:按照字段名查询
List<Book> findByTitle(String title);
  • findBy<FieldName>Not:通过字段名排除
List<Book> findByTitleNot(String title);
  • find<FieldName>True:指定字段为 true
List<Book> findByAvailableTrue();
  • find<FieldName>True:指定字段为 false
List<Book> findByAvailableFalse();

(2)复合条件查询:
  • findBy<FieldName>And<FieldName>:按照多个字段的 AND 条件查询
List<Book> findByTitleAndAuthor(String title, String author);
  • findBy<FieldName>Or<FieldName>:按照多个字段的 OR 条件查询
List<Book> findByTitleOrAuthor(String title, String author);

(3)模糊查询:
  • findBy<FieldName>Like:模糊查询
List<Book> findByTitleLike(String title);
  • findBy<FieldName>StartingWith:按照前缀查询
List<Book> findByTitleStartingWith(String prefix);
  • findBy<FieldName>EndingWith:按照后缀查询
List<Book> findByTitleEndingWith(String suffix);

(4)范围查询:
  • findBy<FieldName>Between:在指定范围区间查询
List<Book> findByPriceBetween(Integer minPrice, Integer maxPrice);
  • findBy<FieldName>LessThan:小于指定值
List<Book> findByPriceLessThan(Integer maxPrice);
  • findBy<FieldName>LessThanEqual:小于等于指定值
List<Book> findByPriceLessThanEqual(Integer maxPrice);
  • findBy<FieldName>GreaterThan:大于指定值
List<Book> findByPriceGreaterThan(Integer minPrice);
  • findBy<FieldName>GreaterThanEqual:大于等于指定值
List<Book> findByPriceGreaterThanEqual(Integer minPrice);

(5)全文检索:
  • findBy<FieldName>Containing:全文检索
List<Book> findByIntroductionContaining(String keyword);

(6)集合匹配:
  • findBy<FieldName>In:按照集合查询
List<Book> findByAuthorIn(Collection<String> authors);
  • findBy<FieldName>NotIn:按照集合排除查询
List<Book> findByAuthorNotIn(Collection<String> authors);

3,结果排序

(1)自定义的方法可以通过指定排序字段和规则实现结果排序,比如下面查询价格大于 50 的书籍并按照价格降序排序:
public interface BookRepository extends ElasticsearchRepository<Book, Long> {
  List<Book> findByPriceGreaterThanOrderByPriceDesc(Integer minPrice);
}

(2)测试使用如下:
List<Book> books = bookRepository.findByPriceGreaterThanOrderByPriceDesc(50);
for (Book book : books) {
  System.out.println("书名:" + book.getTitle() + " 价格:" + book.getPrice());
}

六、ElasticsearchRepository 的注解查询

1,@Query 注解使用

(1)我们在 ElasticsearchRepository 中添加的自定义方法可以使用 @Query 注解查询,设置为注释参数的 String 必须是有效的 Elasticsearch JSON 查询。
提示:JSON 字符串中使用 ?index 进行参数占位,? 表示该位置为参数,index 表示参数下标,从 0 开始。
public interface BookRepository extends ElasticsearchRepository<Book, Long> {
  @Query("{\n" +
          "  \"match\": {\n" +
          "    \"author\": \"?0\"\n" +
          "  }\n" +
          "}")
  List<SearchHit<Book>> listBookByAuthor(String author);
}

(2)测试使用如下:
List<SearchHit<Book>> all = bookRepository.listBookByAuthor("班固");
for (SearchHit<Book> hit: all) {
  System.out.println(hit.getContent());
}

2,@Highlight 注解使用

(1)@Highlight 注解用于设置高亮查询,子注解 @HighlightField 用于指定高亮字段,@HighlightParameters 用于配置高亮选项。下面是高亮查询的样例:
提示:默认分词器会将每个中文文字分成一个词,这里我们使用了 IK 分词器进行中文内容的分词。
public interface BookRepository extends ElasticsearchRepository<Book, Long> {
  @Query("{\n" +
          "  \"match\": {\n" +
          "    \"introduction\": {" +
          "      \"query\": \"?0\"," +
          "      \"analyzer\": \"ik_max_word\"" +
          "    }" +
          "  }\n" +
          "}")
  @Highlight(
      fields = { @HighlightField(name = "introduction")  },
      parameters = @HighlightParameters(preTags = "<span style='color:red'>", postTags = "</span>")
  )
  List<SearchHit<Book>> listBookByIntroductionHighlight(String introduction);
}

(2)测试使用如下:
List<SearchHit<Book>> all = bookRepository.listBookByIntroductionHighlight("中国历史");
for (SearchHit<Book> hit: all) {
  System.out.println("\n" + hit.getContent().getTitle());
  List<String> highlightField = hit.getHighlightField("introduction");
  highlightField.forEach(System.out::println);
}
评论

全部评论(0)

回到顶部