Elasticsearch(8)之Spring Data Elasticserach使用

Elasticsearch(8)之Spring Data Elasticserach使用

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:

介绍

什么是Spring Data

Spring Data 是一个用于简化数据访问,并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷,并支持 map-reduce 框架和云计算数据服务。Spring Data 可以极大地简化 JPA 的写法,可以在几乎不用写实现的情况下,实现对数据的访问和操作。除了 CRUD 外,还包括如分页、排序等一些常用的功能。

Spring Data 官网:https://spring.io/projects/spring-data

Spring Data的常用模块如下:

image.png

什么是Spring Data Elasticsearch

Spring Data Elasticsearch 基于 Spring Data API 简化 Elasticsearch 的操作,将原始操作 Elasticsearch 的客户端 API 进行封装。Spring Data 为 Elasticsearch 项目提供及集成搜索引擎。Spring Data Elasticsearch POJO 的关键功能区域为中心的模型与 Elasticsearch 交互文档可轻松的编写一个存储库数据访问层。

Spring Data Elasticsearch 官网:https://spring.io/projects/spring-data-elasticsearch/

入门

工程搭建

1、使用 Maven 创建 Java 工程,导入 Spring Data Elasticsearch 的依赖。

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>xyz.zze</groupId>
    <artifactId>es-test-02</artifactId>
    <version>1.0</version>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>6.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>6.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-to-slf4j</artifactId>
            <version>2.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.26</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.8.11</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.11</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.8.11</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.22</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-elasticsearch</artifactId>
            <version>3.1.5.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>org.elasticsearch.plugin</groupId>
                    <artifactId>transport-netty4-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.5.RELEASE</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

2、创建 applicationContext.xml 配置文件,加入 Elasticsearch 相关配置。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/data/elasticsearch
    http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
    ">
  <!-- 配置包扫描器,扫描 Dao 接口 -->
  <elasticsearch:repositories base-package="xyz.zze.es.dao"/>

  <!-- 配置 ElasticSearch 连接集群客户端 -->
  <elasticsearch:transport-client id="esClient" cluster-nodes="127.0.0.1:9301,127.0.0.1:9302,127.0.0.1:9303" cluster-name="my-elasticsearch"/>

  <!-- 配置 ElasticSearch 模版对象 -->
  <bean id="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
    <constructor-arg name="client" ref="esClient"></constructor-arg>
  </bean>
</beans>

3、编写实体类,并添加相关注解配置。

// xyz.zze.es.pojo.Article
import lombok.Data;
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;

@Document(indexName = "test_index", type = "article")    // 指定将该 POJO 映射到 test_index 索引下的 article 类型(Type)
@Data
public class Article {

    @Id
    @Field(type = FieldType.Long, store = true)
    private long id;

    @Field(type = FieldType.text, store = true, analyzer = "ik_smart")
    private String title;

    @Field(type = FieldType.text, store = true, analyzer = "ik_smart")
    private String content;
}

4、创建对索引库操作的 dao 接口,该接口将被 Spring 扫描创建其代理对象。

// xyz.zze.es.dao.ArticleRepository
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import xyz.zze.es.pojo.Article;

public interface ArticleRepository extends ElasticsearchRepository<Article,Long> {
}

管理索引库

创建如下 Spring 单元测试类。

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import xyz.zze.es.dao.ArticleRepository;
import xyz.zze.es.pojo.Article;

import java.util.Optional;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDataElasticsearchTest {
    @Autowired
    private ArticleRepository articleRepository;

    @Autowired
    private ElasticsearchTemplate esTemplate;
}

后续每个示例都是在该单元测试类中的一个测试方法。

创建索引库

// 创建索引,并按 POJO 上的注解配置映射关系
esTemplate.createIndex(Article.class);

// 当已有索引库,只需配置映射关系时可执行下面语句来配置映射关系
// esTemplate.putMapping(Article.class);

添加文档

Article article = new Article();
article.setId(1);
article.setTitle("测试标题");
article.setContent("测试内容");
articleRepository.save(article);

修改文档

Article article = new Article();
article.setId(1);
article.setTitle("测试修改标题");
article.setContent("测试修改内容");
articleRepository.save(article);
// 修改文档同样是调用 save 方法,当索引库中存在相同 id 的文档 时即为修改操作。

删除所有文档

articleRepository.deleteAll();

根据id删除文档

articleRepository.deleteById(1l);

查询全部

Iterable<Article> all = articleRepository.findAll();
all.forEach(doc -> System.out.println(doc));

根据id查询文档

Optional<Article> doc = articleRepository.findById(1l);
// 如果查询结果不为 null
if(doc.isPresent()){
    Article article = doc.get();
    System.out.println(article);
}

自定义查询方法

常用查询命名规则

关键字命名规则解释示例
andfindByField1AndField2根据 Field1 和 Field2 查询数据findByTitleAndContent
orfindByField1OrField2根据 Field1 或 Field2 查询数据findByTitleOrContent
isfindByField根据 Field 获得数据findByTitle
notfindByFieldNot根据 Field 获得补集数据findByTitleNot
betweenfindByFieldBetween查询指定范围的数据findByPriceBetween
lessThanEqualfindByFieldLessThan获取小于等于指定值的数据findByPrizeLessThan

查询方法测试

1、修改 Dao 类 ArticleRepository 如下。

// xyz.zze.es.dao.ArticleRepository
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import xyz.zze.es.pojo.Article;

import java.util.List;

@Repository
public interface ArticleRepository extends ElasticsearchRepository<Article,Long> {
    /**
     * 根据标题查询
     */
    List<Article> findByTitle(String title);

    /**
     * 根据标题和内容查询
     */
    List<Article> findByTitleAndContent(String title,String content);

    /**
     * 根据标题或内容查询
     */
    List<Article> findByTitleOrContent(String title,String content);

    /**
     * 根据标题或内容查询,带分页
     */
    List<Article> findByTitleOrContent(String title, String content, Pageable pageable);
}

2、测试:

/**
 * 根据标题查询
 */
@Test
public void testFindByTitle() {
    List<Article> articleList = articleRepository.findByTitle("测试");
    articleList.forEach(doc -> System.out.println(doc));
}

/**
 * 根据标题和内容查询
 */
@Test
public void testFindByTitleAndContent() {
    List<Article> articleList = articleRepository.findByTitleAndContent("测试","内容");
    articleList.forEach(doc -> System.out.println(doc));
}

/**
 * 根据标题或内容查询
 */
@Test
public void testFindByTitleOrContent() {
    List<Article> articleList = articleRepository.findByTitleOrContent("测试","内容");
    articleList.forEach(doc -> System.out.println(doc));
}

/**
 * 根据标题或内容查询,带分页
 */
@Test
public void testFindByTitleOrContentWithPageable() {
    // 参数1:页码,从 0 开始
    // 参数2:每页的条数
    Pageable pageConf = PageRequest.of(0, 10);
    List<Article> articleList = articleRepository.findByTitleOrContent("测试","内容",pageConf);
    articleList.forEach(doc -> System.out.println(doc));
}

自定义查询方法中是先将查询内容进行分词然后进行查询,但要注意的是内容分词后的结果即多个关键词之间的关系是 and,如果需要多个关键词之间是 or 关系,可使用下面的原生条件查询。

原生条件查询 NativeSearchQuery

// 创建原生查询对象并设置查询信息
NativeSearchQuery query = new NativeSearchQueryBuilder()
        .withQuery(QueryBuilders.queryStringQuery("maven是一个项目构建工具").defaultField("title"))
        .withPageable(PageRequest.of(0, 10))
        .build();
// 执行查询
List<Article> articleList = esTemplate.queryForList(query, Article.class);
articleList.forEach(doc -> System.out.println(doc));

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.zze.xyz/archives/elasticsearch8.html

Buy me a cup of coffee ☕.