Spring Boot Elasticsearch 入门

转载自  芋道 Spring Boot Elasticsearch 入门

1. 概述

如果胖友之前有用过 Elasticsearch 的话,可能有过被使用的 Elasticsearch 客户端版本搞死搞活。如果有,那么一起握个抓。所以,我们在文章的开始,先一起理一理这块。

Elasticsearch(ES)提供了两种连接方式:

  • transport :通过 TCP 方式访问 ES 。

    对应的库是 org.elasticsearch.client.transport 。

  • rest :通过 HTTP API 方式访问 ES 。

    对应的库是:

    • elasticsearch-rest-client + org.elasticsearch.client.rest,提供 low-level rest API 。

    • elasticsearch-rest-high-level-client ,提供 high-level rest API 。从 Elasticsearch 6.0.0-beta1 开始提供。

如果想进一步了解上述的 3 个 ES 客户端,可以看看 《Elasticsearch 客户端 transport vs rest》 文章。

虽然说,ES 提供了 2 种方式,官方目前建议使用 rest 方式,而不是 transport 方式。并且,transport 在未来的计划中,准备废弃。并且,阿里云提供的 Elasticsearch 更加干脆,直接只提供 rest 方式,而不提供 transport 方式。

在社区中,有个 Jest 开源项目,也提供了的 Elasticsearch REST API 客户端。

参考 《ES Java Client 的历史》

Elasticsearch 5.0 才有了自己的 Rest 客户端 ,6.0 才有了更好用的客户端,所以 Jest 作为第三方客户端,使用非常广泛。

正如我们在项目中,编写数据库操作的逻辑,使用 MyBatis 或者 JPA 为主,而不使用原生的 JDBC 。那么,我们在编写 Elasticsearch 操作的逻辑,也不直接使用上述的客户端,而是:

  • spring-data-elasticsearch ,基于 Elasticsearch transport 客户端封装。

  • spring-data-jest ,基于 Jest 客户端封装。

虽然这两者底层使用的不同客户端,但是都基于 Spring Data 体系,所以项目在使用时,编写的代码是相同的。也因此,如果胖友想从 spring-data-elasticsearch 迁移到 spring-data-jest 时,基本透明无成本,美滋滋~

😈 这样一个梳理,胖友是不是对 Elasticsearch 客户端的选用,心里已经明明白白落。嘿嘿。

下面,艿艿先来讲一个悲伤的故事。大体过程是这样的:

  • 1、在上线的时候,发现线上使用的是阿里云的 Elasticsearch 服务,不提供 transport 连接方式,而项目中使用的是 spring-data-elasticsearch 。所以,先临时在 ECS 搭建一个 Elasticsearch 服务,过度下。

  • 2、然后,了解到有 Jest 客户端可以使用 rest 连接方式,于是将操作 Elasticsearch 的代码,全部改成 Jest 的方式。

  • 3、之后,发现竟然还有 spring-data-jest ,一脸悲伤,重新将操作 Elasticsearch 的代码,全部改成 spring-data-jest 的方式。

泪崩。所以胖友可知,艿艿目前线上使用 spring-data-jest 访问 Elasticsearch 。

下面,我们分别来入门:

  • Spring Data Jest

  • Spring Data Elasticsearch

艿艿:如果胖友还没安装 Elasticsearch ,并安装 IK 插件,可以参考下 《Elasticsearch 安装部署》 文章,先进行下安装。

2. Spring Data Jest

示例代码对应仓库:lab-15-spring-data-jest 。

  • ES 版本号:6.5.0

  • spring-boot-starter-data-jest :3.2.5.RELEASE

本小节,我们会使用 spring-boot-starter-data-jest 自动化配置 Spring Data Jest 主要配置。同时,编写相应的 Elasticsearch 的 CRUD 操作。

2.1 引入依赖

在 pom.xml 文件中,引入相关依赖。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><modelVersion>4.0.0</modelVersion><artifactId>lab-15-spring-data-jest</artifactId><dependencies><!-- 自动化配置 Spring Data Jest --><dependency><groupId>com.github.vanroy</groupId><artifactId>spring-boot-starter-data-jest</artifactId><version>3.2.5.RELEASE</version></dependency><!-- 方便等会写单元测试 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies></project>

具体每个依赖的作用,胖友自己认真看下艿艿添加的所有注释噢。

2.2 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

// Application.java@SpringBootApplication(exclude = {ElasticsearchAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class})
public class Application {
}
  • 需要排除 ElasticsearchAutoConfiguration 和 ElasticsearchDataAutoConfiguration 自动配置类,否则会自动配置 Spring Data Elasticsearch 。

2.3 配置文件

在 application.yml 中,添加 Jest 配置,如下:

spring:data:# Jest 配置项jest:uri: http://127.0.0.1:9200
  • 我们使用本地的 ES 服务。默认情况下,ES rest 连接方式暴露的端口是 9200 。

2.4 ESProductDO

在 cn.iocoder.springboot.lab15.springdatajest.dataobject 包路径下,创建 ESProductDO 类。代码如下:

// ESProductDO.java@Document(indexName = "product", // 索引名type = "product", // 类型。未来的版本即将废弃shards = 1, // 默认索引分区数replicas = 0, // 每个分区的备份数refreshInterval = "-1" // 刷新间隔
)
public class ESProductDO {/*** ID 主键*/@Idprivate Integer id;/*** SPU 名字*/@Field(analyzer = FieldAnalyzer.IK_MAX_WORD, type = FieldType.Text)private String name;/*** 卖点*/@Field(analyzer = FieldAnalyzer.IK_MAX_WORD, type = FieldType.Text)private String sellPoint;/*** 描述*/@Field(analyzer = FieldAnalyzer.IK_MAX_WORD, type = FieldType.Text)private String description;/*** 分类编号*/private Integer cid;/*** 分类名*/@Field(analyzer = FieldAnalyzer.IK_MAX_WORD, type = FieldType.Text)private String categoryName;// 省略 setting/getting 方法
}
  • 为了区别关系数据库的实体对象,艿艿习惯以 ES 前缀开头。

  • 字段上的 @Field 注解的 FieldAnalyzer ,是定义的枚举类,记得自己创建下噢。代码如下:
    // FieldAnalyzer.javapublic class FieldAnalyzer {/*** IK 最大化分词** 会将文本做最细粒度的拆分*/public static final String IK_MAX_WORD = "ik_max_word";/*** IK 智能分词** 会做最粗粒度的拆分*/public static final String IK_SMART = "ik_smart";}
    
    • 再友情提示下,一定要记得给 Elasticsearch 安装 IK 插件,不然等会示例会报错的哟。

2.5 ProductRepository

在 cn.iocoder.springboot.lab15.mybatis.repository 包路径下,创建 ProductRepository 接口。代码如下:

// ProductRepository.javapublic interface ProductRepository extends ElasticsearchRepository<ESProductDO, Integer> {}
  • 继承 org.springframework.data.elasticsearch.repository.ProductRepository 接口,第一个泛型设置对应的实体是 ESProductDO ,第二个泛型设置对应的主键类型是 Integer 。

  • 因为实现了 ElasticsearchRepository 接口,Spring Data Jest 会自动生成对应的 CRUD 等等的代码。😈 是不是很方便。

  • ElasticsearchRepository 类图如下:

    • 每个接口定义的方法,胖友可以点击下面每个链接,自己瞅瞅,简单~

    • org.springframework.data.repository.CrudRepository

    • org.springframework.data.repository.PagingAndSortingRepository

    • org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository

    • org.springframework.data.elasticsearch.repository.ElasticsearchRepository

艿艿:如果胖友看过艿艿写的 《芋道 Spring Boot JPA 入门》 文章,会发现和 Spring Data JPA 的使用方式,基本一致。这就是 Spring Data 带给我们的好处,使用相同的 API ,统一访问不同的数据源。o( ̄▽ ̄)d 点赞。

2.6 简单测试

创建 ProductRepositoryTest 测试类,我们来测试一下简单的 ProductRepositoryTest 的每个操作。代码如下:

// ProductRepositoryTest.JAVA@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ProductRepositoryTest {@Autowiredprivate ProductRepository productRepository;@Test // 插入一条记录public void testInsert() {ESProductDO product = new ESProductDO();product.setId(1); // 一般 ES 的 ID 编号,使用 DB 数据对应的编号。这里,先写死product.setName("芋道源码");product.setSellPoint("愿半生编码,如一生老友");product.setDescription("我只是一个描述");product.setCid(1);product.setCategoryName("技术");productRepository.save(product);}// 这里要注意,如果使用 save 方法来更新的话,必须是全量字段,否则其它字段会被覆盖。// 所以,这里仅仅是作为一个示例。@Test // 更新一条记录public void testUpdate() {ESProductDO product = new ESProductDO();product.setId(1);product.setCid(2);product.setCategoryName("技术-Java");productRepository.save(product);}@Test // 根据 ID 编号,删除一条记录public void testDelete() {productRepository.deleteById(1);}@Test // 根据 ID 编号,查询一条记录public void testSelectById() {Optional<ESProductDO> userDO = productRepository.findById(1);System.out.println(userDO.isPresent());}@Test // 根据 ID 编号数组,查询多条记录public void testSelectByIds() {Iterable<ESProductDO> users = productRepository.findAllById(Arrays.asList(1, 4));users.forEach(System.out::println);}}
  • 每个测试单元方法,胖友自己看看方法上的注释。

具体的,胖友可以自己跑跑,妥妥的。

3. Spring Data Elasticsearch

示例代码对应仓库:lab-15-spring-data-elasticsearch 。

  • ES 版本号:6.5.0

  • spring-boot-starter-data-elasticsearch :2.1.3.RELEASE

本小节,我们会使用 spring-boot-starter-data-elasticsearch 自动化配置 Spring Data Elasticsearch 主要配置。同时,编写相应的 Elasticsearch 的 CRUD 操作。

重点是,我们希望通过本小节,让胖友感受到,Spring Data Jest 和 Spring Data Elasticsearch 是基本一致的。

3.1 引入依赖

在 pom.xml 文件中,引入相关依赖。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><modelVersion>4.0.0</modelVersion><artifactId>lab-15-spring-data-elasticsearch</artifactId><dependencies><!-- 自动化配置 Spring Data Elasticsearch --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency><!-- 方便等会写单元测试 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies></project>
  • 差异点,就是将依赖 spring-boot-starter-data-jest 替换成 spring-boot-starter-data-elasticsearch 。

具体每个依赖的作用,胖友自己认真看下艿艿添加的所有注释噢。

3.2 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

// Application.java@SpringBootApplication
public class Application {
}
  • 差异点,在于无需排除 ElasticsearchAutoConfiguration 和 ElasticsearchDataAutoConfiguration 自动配置类,因为需要它们自动化配置 Spring Data Elasticsearch 。

3.3 配置文件

在 application.yml 中,添加 Jest 配置,如下:

spring:data:# Elasticsearch 配置项elasticsearch:cluster-name: elasticsearch # 集群名cluster-nodes: 127.0.0.1:9300 # 集群节点
  • 差异点,将配置项 jest 替换成 elasticsearch 。

  • 我们使用本地的 ES 服务。默认情况下,ES transport 连接方式暴露的端口是 9300 。

3.4 ESProductDO

和 「2.4 ESProductDO」 一致。

3.5 ProductRepository

和 「3.5 ProductRepository」 一致。

3.6 简单测试

和 「3.6 简单测试」 一致。

😈 有没感受到,Spring Data Jest 和 Spring Data Elasticsearch 是基本一致的。

4. 基于方法名查询

示例代码对应仓库:lab-15-spring-data-jest 。

  • ES 版本号:6.5.0

  • spring-boot-starter-data-jest :3.2.5.RELEASE

在 《芋道 Spring Boot JPA 入门》 文章的「4. 基于方法名查询」小节中,我们已经提到:

在 Spring Data 中,支持根据方法名作生成对应的查询(WHERE)条件,进一步进化我们使用 JPA ,具体是方法名以 findByexistsBycountBydeleteBy 开头,后面跟具体的条件。具体的规则,在 《Spring Data JPA —— Query Creation》 文档中,已经详细提供。如下:

关键字方法示例JPQL snippet
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
IsEqualsfindByFirstname,findByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age <= ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullNullfindByAge(Is)Null… where x.age is null
IsNotNullNotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 (parameter bound with appended %)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 (parameter bound with prepended %)
ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection ages)… where x.age not in ?1
TruefindByActiveTrue()… where x.active = true
FalsefindByActiveFalse()… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)
  • 注意,如果我们有排序需求,可以使用 OrderBy 关键字。

下面,我们来编写一个简单的示例。

艿艿:IDEA 牛逼,提供的插件已经能够自动提示上述关键字。太强了~

因为 Spring Data Elasticsearch 和 Spring Data Jest 也是 Spring Data 体系中的一员,所以也能享受到基于方法名查询的福利。所以,我们在本小节中,我们也来尝试下。

我们会在 「2. Spring Data Jest」 的示例代码对应仓库 lab-15-spring-data-jest 的基础上,进行本小节的示例。

4.1 ProductRepository02

在 cn.iocoder.springboot.lab15.springdatajest.repository 包路径下,创建 UserRepository02 接口。代码如下:

// ProductRepository02.javapublic interface ProductRepository02 extends ElasticsearchRepository<ESProductDO, Integer> {ESProductDO findByName(String name);Page<ESProductDO> findByNameLike(String name, Pageable pageable);}
  • 对于分页操作,需要使用到 Pageable 参数,需要作为方法的最后一个参数。

4.2 简单测试

创建 UserRepository02Test 测试类,我们来测试一下简单的 UserRepository02Test 的每个操作。代码如下:

// UserRepository02Test.java@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ProductRepository02Test {@Autowiredprivate ProductRepository02 productRepository;@Test // 根据名字获得一条记录public void testFindByName() {ESProductDO product = productRepository.findByName("芋道源码");System.out.println(product);}@Test // 使用 name 模糊查询,分页返回结果public void testFindByNameLike() {// 根据情况,是否要制造测试数据if (true) {testInsert();}// 创建排序条件Sort sort = new Sort(Sort.Direction.DESC, "id"); // ID 倒序// 创建分页条件。Pageable pageable = PageRequest.of(0, 10, sort);// 执行分页操作Page<ESProductDO> page = productRepository.findByNameLike("芋道", pageable);// 打印System.out.println(page.getTotalElements());System.out.println(page.getTotalPages());}/*** 为了给分页制造一点数据*/private void testInsert() {for (int i = 1; i <= 100; i++) {ESProductDO product = new ESProductDO();product.setId(i); // 一般 ES 的 ID 编号,使用 DB 数据对应的编号。这里,先写死product.setName("芋道源码:" + i);product.setSellPoint("愿半生编码,如一生老友");product.setDescription("我只是一个描述");product.setCid(1);product.setCategoryName("技术");productRepository.save(product);}}}
  • 每个测试单元方法,胖友自己看看方法上的注释。

具体的,胖友可以自己跑跑,妥妥的。

5. 复杂查询

在一些业务场景下,我们需要编写相对复杂的查询,例如说类似京东 https://search.jd.com/Search?keyword=华为手机 搜索功能,需要支持关键字、分类、品牌等等,并且可以按照综合、销量等等升降序排序,那么我们就无法在上面看到的 Spring Data Repository 提供的简单的查询方法,而需要使用到 ElasticsearchRepository 的 search 方法,代码如下:

// ElasticsearchRepository.java
// 省略非 search 方法Page<T> search(QueryBuilder query, Pageable pageable);Page<T> search(SearchQuery searchQuery);Page<T> searchSimilar(T entity, String[] fields, Pageable pageable);

此时,我们就需要使用 QueryBuilder 和 SearchQuery 构建相对复杂的搜索和排序条件。所以,我们继续在 「2. Spring Data Jest」 的示例代码对应仓库 lab-15-spring-data-jest 的基础上,进行本小节的示例,实现一个简单的商品搜索功能。

5.1 ProductRepository03

在 cn.iocoder.springboot.lab15.springdatajest.repository 包路径下,创建 ProductRepository03 接口。代码如下:

// ProductRepository03.javapublic interface ProductRepository03 extends ElasticsearchRepository<ESProductDO, Integer> {default Page<ESProductDO> search(Integer cid, String keyword, Pageable pageable) {// <1> 创建 NativeSearchQueryBuilder 对象NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();// <2.1> 筛选条件 cidif (cid != null) {nativeSearchQueryBuilder.withFilter(QueryBuilders.termQuery("cid", cid));}// <2.2> 筛选if (StringUtils.hasText(keyword)) {FunctionScoreQueryBuilder.FilterFunctionBuilder[] functions = { // TODO 芋艿,分值随便打的new FunctionScoreQueryBuilder.FilterFunctionBuilder(matchQuery("name", keyword),ScoreFunctionBuilders.weightFactorFunction(10)),new FunctionScoreQueryBuilder.FilterFunctionBuilder(matchQuery("sellPoint", keyword),ScoreFunctionBuilders.weightFactorFunction(2)),new FunctionScoreQueryBuilder.FilterFunctionBuilder(matchQuery("categoryName", keyword),ScoreFunctionBuilders.weightFactorFunction(3)),
//                    new FunctionScoreQueryBuilder.FilterFunctionBuilder(matchQuery("description", keyword),
//                            ScoreFunctionBuilders.weightFactorFunction(2)), // TODO 芋艿,目前这么做,如果商品描述很长,在按照价格降序,会命中超级多的关键字。};FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(functions).scoreMode(FunctionScoreQuery.ScoreMode.SUM) // 求和.setMinScore(2F); // TODO 芋艿,需要考虑下 scorenativeSearchQueryBuilder.withQuery(functionScoreQueryBuilder);}// 排序if (StringUtils.hasText(keyword)) { // <3.1> 关键字,使用打分nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));} else if (pageable.getSort().isSorted()) { // <3.2> 有排序,则进行拼接pageable.getSort().get().forEach(sortField -> nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(sortField.getProperty()).order(sortField.getDirection().isAscending() ? SortOrder.ASC : SortOrder.DESC)));} else { // <3.3> 无排序,则按照 ID 倒序nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC));}// <4> 分页nativeSearchQueryBuilder.withPageable(PageRequest.of(pageable.getPageNumber(), pageable.getPageSize())); // 避免// <5> 执行查询return search(nativeSearchQueryBuilder.build());}}
  • 使用 QueryBuilder 和 SearchQuery 构建相对复杂的搜索和排序条件,我们可以放在 Service 层,也可以放在 Repository 层。艿艿个人的偏好放在 Repository 层。

    • 主要原因是,尽量避免数据层的操作暴露在 Service 层。

    • 缺点呢,就像我们这里看到的,有点业务逻辑就到了 Repository 层。

    • 😈 有舍有得,看个人喜好。翻了一些开源项目,放在 Service 或 Repository 层的都有。

  • 简单来说下这个方法的整体逻辑,根据商品分类编号 + 关键字,检索相应的商品,分页返回结果。

  • <1> 处,创建 NativeSearchQueryBuilder 对象。

  • 筛选条件

    • <2.1> 处,如果有分类编号 cid ,则进行筛选。

    • <2.2> 处,如果有关键字 keyword ,则按照 name 10 分、sellPoint 2 分、categoryName 3 分,计算求和,筛选至少满足 2 分。

  • 排序条件

    • <3.1> 处,如果有关键字,则按照打分结果降序。

    • <3.2> 处,如果有排序条件,则按照该排序即可。

    • <3.3> 处,如果无排序条件,则按照 ID 编号降序。

  • 分页条件

    • <4> 处,创建新的 PageRequest 对象,避免 pageable 里原有的排序条件。

  • 执行搜索

    • <5> 处,调用 #search(SearchQuery searchQuery) 方法,执行 Elasticsearch 搜索。

5.2 ProductRepository03Test

创建 ProductRepository03Test 测试类,我们来测试一下简单的 UserRepository03Test 的每个操作。代码如下:

// ProductRepository03Test.java@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ProductRepository03Test {@Autowiredprivate ProductRepository03 productRepository;@Testpublic void testSearch() {// 查找分类为 1 + 指定关键字,并且按照 id 升序Page<ESProductDO> page = productRepository.search(1, "技术",PageRequest.of(0, 5, Sort.Direction.ASC, "id"));System.out.println(page.getTotalPages());// 查找分类为 1 ,并且按照 id 升序page = productRepository.search(1, null,PageRequest.of(0, 5, Sort.Direction.ASC, "id"));System.out.println(page.getTotalPages());}}
  • 每个测试单元方法,胖友自己看看方法上的注释。

具体的,胖友可以自己跑跑,妥妥的。

6. ElasticsearchTemplate

在 Spring Data Elasticsearch 中,有一个 ElasticsearchTemplate 类,提供了 Elasticsearch 操作模板,方便我们操作 Elasticsearch 。

😈 要注意,这是 Spring Data Elasticsearch 独有,而 Spring Data Jest 没有的一个类。

咳咳咳,当艿艿写完这篇博客后,突然发现,Spring Data Jest 有一个 JestElasticsearchTemplate 类,和 ElasticsearchTemplate 是对等的。

也因此,我们继续在 「3. Spring Data Elasticsearch」 的示例代码对应仓库 lab-15-spring-data-elasticsearch 的基础上,进行本小节的示例,实现一个商品搜索条件返回的功能。

6.1 ProductConditionBO

在 cn.iocoder.springboot.lab15.springdataelasticsearch.bo 包路径下,创建 ProductConditionBO 类,商品搜索条件 BO ,代码如下:

// ProductConditionBO.javapublic class ProductConditionBO {/*** 商品分类数组*/private List<Category> categories;public static class Category {/*** 分类编号*/private Integer id;/*** 分类名称*/private String name;// ... 省略 setting/getting 方法}// ... 省略 setting/getting 方法}

6.2 简单示例

创建 ProductRepository04Test 测试类,我们来测试一下简单的 ProductRepository04Test 的每个操作。代码如下:

// ProductRepository04Test.java@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ProductRepository04Test {@Autowiredprivate ElasticsearchTemplate elasticsearchTemplate;@Testpublic void test() {// <1> 创建 ES 搜索条件NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withIndices("product");;// <2> 筛选nativeSearchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery("芋道","name", "sellPoint", "categoryName"));// <3> 聚合nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("cids").field("cid")); // 商品分类// <4> 执行查询ProductConditionBO condition = elasticsearchTemplate.query(nativeSearchQueryBuilder.build(), response -> {ProductConditionBO result = new ProductConditionBO();// categoryIds 聚合Aggregation categoryIdsAggregation = response.getAggregations().get("cids");if (categoryIdsAggregation != null) {result.setCategories(new ArrayList<>());for (LongTerms.Bucket bucket  : (((LongTerms) categoryIdsAggregation).getBuckets())) {result.getCategories().add(new ProductConditionBO.Category().setId(bucket.getKeyAsNumber().intValue()));}}// 返回结果return result;});// <5> 后续遍历 condition.categories 数组,查询商品分类,设置商品分类名。System.out.println();}}
  • 简单来说下这个方法的整体逻辑,根据关键字检索 namesellPointcategoryName 字段,聚合 cid 返回。

  • <1> 处,创建 NativeSearchQueryBuilder 对象,并设置查询的索引是 product ,即 ESProductDO 类的对应的索引。

  • 筛选条件

    • <2> 处,根据关键字检索 namesellPointcategoryName 字段。此处,我们使用的关键字是 "芋道" 。

  • 聚合

    • <3> 处,将商品分类编号 cid 聚合成 cids 返回。

    • 如果 ESProductDO 上有品牌编号,我们可以多在聚合一个品牌编号返回。

  • 执行搜索

    • <4> 处,执行查询,解析聚合结果,设置回 ProductConditionBO 中。

  • <5> 处,后续遍历 condition.categories 数组,查询商品分类,设置商品分类名。

6.3 小结

可能胖友会有疑惑?Spring Data Jest 没有 ElasticsearchTemplate 类,岂不是不能实现当前示例么?答案是否定的,我们回过头看 「5. 复杂查询」 。对于 Spring Data Jest 来说,可以通过 ElasticsearchRepository 提供的 search 方法,实现聚合操作的功能。当然,Spring Data Elasticsearch 也可以。

所以呢,绝大多数情况下,我们并不会直接使用 ElasticsearchTemplate 类。

666. 彩蛋

通过写这篇文章,艿艿自己也查了一些资料,终于把 Elasticsearch 客户端的情况理顺了。😈 当然,也推荐几篇艿艿觉得不错的 Elasticsearch 文章:

  • 《图解 Elasticsearch 原理》

  • 《全文搜索引擎选 ElasticSearch 还是 Solr?》

  • 《别再说你不会 ElasticSearch 调优了,都给你整理好了》

  • 《Elasticsearch 如何做到亿级数据查询毫秒级返回?》

  • 《日均 5 亿查询量的京东订单中心,为什么舍 MySQL 用 ES ?》

另外,在推荐一个 Chrome ElasticSearch Head 插件,可用于监控 Elasticsearch 状态的客户端,提供数据可视化、执行增删改查操作等等功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/322649.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在.NET Core类库中使用EF Core迁移数据库到SQL Server

前言 如果大家刚使用EntityFramework Core作为ORM框架的话&#xff0c;想必都会遇到数据库迁移的一些问题。 起初我是在ASP.NET Core的Web项目中进行的&#xff0c;但后来发现放在此处并不是很合理&#xff0c;一些关于数据库的迁移&#xff0c;比如新增表&#xff0c;字段&…

Spring Boot MongoDB 入门

转载自 芋道 Spring Boot MongoDB 入门 1. 概述 可能有一些胖友对 MongoDB 不是很了解&#xff0c;这里我们引用一段介绍&#xff1a; FROM 《分布式文档存储数据库 MongoDB》 MongoDB 是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最…

Spring框架-事务管理注意事项

转载自 Spring框架-事务管理注意事项 常见事务问题 事务不起作用 可能是配置不起效&#xff0c;如扫描问题 事务自动提交了&#xff08;批量操作中&#xff09; 可能是在没事务的情况下&#xff0c;利用了数据库的隐式提交 事务配置说明 通常情况下我们的Spring Component扫…

Ocelot统一权限验证

Ocelot作为网关&#xff0c;可以用来作统一验证&#xff0c;接上一篇博客Ocelot网关&#xff0c;我们继续 前一篇&#xff0c;我们创建了OcelotGateway网关项目&#xff0c;DemoAAPI项目&#xff0c;DemoBAPI项目&#xff0c;为了验证用户并分发Token&#xff0c;现在还需要添…

Spring Boot之程序性能监控

转载自 Spring Boot之程序性能监控 Spring Boot特别适合团队构建各种可快速迭代的微服务&#xff0c;同时为了减少程序本身监控系统的开发量&#xff0c;Spring Boot提供了actuator模块&#xff0c;可以很方便的对你的Spring Boot程序做监控。 1. actuator接口说明 Spring B…

laravel部署在linux出现404 not found

laravel项目放在本地服务器后&#xff0c;访问是成功的 http://localhost/blogkjh/public/article 但是在linux服务器上访问显示404 not found 但是我在服务器上使用 php artisan serve --host 0.0.0.0 命令 却可以访问 甚至连swagger都可以访问 关于这个我最近就特别疑…

Visual Studio 2017 15.6版本预览,增加新功能

上周Visual Studio 2017 15.5 版本已正式发布&#xff0c;同时发布的还有 Visual Studio for Mac 7.3 。 Visual Studio 2017 15.6 版本预览&#xff0c;这个最新的预览包含新功能&#xff0c;生产力改进和其他增强功能&#xff0c;以解决客户的反馈意见。 本发行版中的更新摘要…

使用 mono 编译 .NET Standard 应用

微软发布 .NET Standard 2.0 已经有一段时间了&#xff0c; 根据 .NET Standard 2.0 支持版本的文档&#xff0c; Mono 5.4 是支持 .NET Standard 2.0 的&#xff0c; 对于 .NET Standard 2.0 应用的开发的介绍&#xff0c; 几乎全部都是在 Windows 系统下使用 Visual Studio 2…

Spring Boot 热部署入门

转载自 Spring Boot 热部署入门 1. 概述 在日常开发中&#xff0c;我们需要经常修改 Java 代码&#xff0c;手动重启项目&#xff0c;查看修改后的效果。如果在项目小时&#xff0c;重启速度比较快&#xff0c;等待的时间是较短的。但是随着项目逐渐变大&#xff0c;重启的速…

微服务架构的理论基础 - 康威定律

摘要&#xff1a; 可能出乎很多人意料之外的一个事实是&#xff0c;微服务很多核心理念其实在半个世纪前的一篇文章中就被阐述过了&#xff0c;而且这篇文章中的很多论点在软件开发飞速发展的这半个世纪中竟然一再被验证&#xff0c;这就是康威定律。前段时间看了Mike Amundsen…

阿里微服务架构下分布式事务Seata

转载自 阿里微服务架构下分布式事务Seata Seata 是什么&#xff1f; Seata 是一款开源的分布式事务解决方案&#xff0c;致力于在微服务架构下提供高性能和简单易用的分布式事务服务。在 Seata 开源之前&#xff0c;Seata 对应的内部版本在阿里经济体内部一直扮演着分布式一…

用于.NET Core的ORM

尽管EF Core正努力提供视图和存储过程等基本数据库特性&#xff0c;但是开发人员也在寻求能满足他们数据访问需求的ORM工具。下面列出一些相对广为使用的ORM。 LLBLGen Pro Runtime Framework LLBLGen Pro Runtime Framework是一种“可选”的ORM&#xff0c;它是与LLBLGen实体建…

Spring Boot之基于Dubbo和Seata的分布式事务解决方案

转载自 Spring Boot之基于Dubbo和Seata的分布式事务解决方案 1. 分布式事务初探 一般来说&#xff0c;目前市面上的数据库都支持本地事务&#xff0c;也就是在你的应用程序中&#xff0c;在一个数据库连接下的操作&#xff0c;可以很容易的实现事务的操作。但是目前&#xff…

Ocelot监控

网关的作用之一&#xff0c;就是有统一的数据出入口&#xff0c;基于这个功能&#xff0c;我们可以在网关上配置监控&#xff0c;从而把所有web服务的请求应答基本数据捕获并展显出来。 关于web的监控&#xff0c;一般的做法是采集数据并保存&#xff0c;然后通过图表的方式展示…

Spring Boot之基于Redis实现MyBatis查询缓存解决方案

转载自 Spring Boot之基于Redis实现MyBatis查询缓存解决方案 1. 前言 MyBatis是Java中常用的数据层ORM框架&#xff0c;笔者目前在实际的开发中&#xff0c;也在使用MyBatis。本文主要介绍了MyBatis的缓存策略、以及基于SpringBoot和Redis实现MyBatis的二级缓存的过程。实现本…

数据库架构演变概要

一&#xff0e;背景为了适应业务增长,数据库数据量快速增长&#xff0c;性能日趋下降&#xff0c;稳定性不佳的实际情况&#xff0c;急需架构逐步演变适应未来的业务发展。二&#xff0e;现状【稳定性】数据库为单点&#xff0c;没有高可用和稳定性方案。【数据量大】数据库目前…

面试请不要再问我Spring Cloud底层原理

转载自 面试请不要再问我Spring Cloud底层原理 概述 毫无疑问&#xff0c;Spring Cloud是目前微服务架构领域的翘楚&#xff0c;无数的书籍博客都在讲解这个技术。不过大多数讲解还停留在对Spring Cloud功能使用的层面&#xff0c;其底层的很多原理&#xff0c;很多人可能并…

nginx配置前端反向代理

本地这里有两个端口&#xff1a; 8080&#xff1a;前端页面 80&#xff1a;后端接口 在nginx配置 listen 8888;server_name 127.0.0.1;location / {root html;proxy_pass http://127.0.0.1:8080;# try_files $uri $uri/ /index.php$is_args$args;index index.html…

Visual Studio 2017的第五个更新包扩展了调试工具

Visual Studio 2017近日收到了最新的完整更新包&#xff0c;版本号为15.5。跟随前几次更新的步伐&#xff0c;这次发布提供了一系列几乎会让所有用户从中受益的特性。此次发布的一个重点是IDE的性能&#xff0c;尤其是减少C#/Visual Basic项目的加载时间。在.NET Core项目中进行…

深港澳大湾区第三次.NET技术交流会圆满成功

2017年12月10日&#xff0c;一场以云、devops、微服务、容器是现在这个发展阶段的软件形态&#xff0c; 本次活动我们围绕这些话题介绍.NET生态下的发展本地社区活动&#xff0c;这次活动还得到如鹏网杨中科老师的大力支持开通网上直播&#xff0c;网上有229位参与活动&#xf…