Spring Data Elasticsearch增删改查API

一、简介

Spring Data Elasticsearch 是 Elasticsearch 搜索引擎开发的解决方案。它提供:模板对象,用于存储、搜索、排序文档和构建聚合的高级API。例如,Repository 使开发者能够通过定义具有自定义方法名称的接口来表达查询。学习文档: https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#reference

二、准备工作

案例说明
在 Elasticsearch 中存储学生数据,并对学生数据进行搜索测试。

学号 姓名 性别 出生日期
27 张三 2020-12-4

在 Elasticsearch 中创建 students 索引

PUT /students
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2,
    "index.max_ngram_diff":30,
    "analysis": {
      "analyzer": {
        "ngram_analyzer": {
          "tokenizer": "ngram_tokenizer"
        }
      },
      "tokenizer": {
        "ngram_tokenizer": {
          "type": "ngram",
          "min_gram": 1,
          "max_gram": 30,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "id": {
        "type": "long"
      },
      "name": {
        "type": "text",
        "analyzer": "ngram_analyzer"
      },
      "gender": {
        "type": "keyword"
      },
      "birthDate": {
        "type": "date",
        "format": "yyyy-MM-dd"
      }
    }
  }
}

创建springboot工程,添加Spring Data Elasticsearch依赖
Spring Data Elasticsearch增删改查API_第1张图片
yml配置

spring:
  elasticsearch:
    rest:
      uris: http://192.168.64.181:9200
logging:
  level:
    tracer: trace #与es服务器通信的日志

Student 实体类

/**
 * @Documnet注解对索引的参数进行设置。 上面代码中,把 students 索引的分片数设置为3,副本数设置为2。
 * 指定学生数据,对应的索引
 * 如果服务器的索引不存在,也可以根据这里的配置自动创建说明 shards = 3,replicas = 2
 * 一般不使用自动创建,而是要手动创建索引
 */
@Document(indexName = "students")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    @Id//在 Elasticsearch 中创建文档时,使用 @Id 注解的字段作为文档的 _id 值
    private Long id;
    /**
     * 通过 @Field 注解设置字段的数据类型和其他属性。
     * 文本类型 text 会进行分词 和 keyword 不会分词
     *
     * analyzer 指定分词器
     * 通过 analyzer 设置可以指定分词器,例如 ik_smart、ik_max_word 等。
     * ngram 分词器 刘德华分词结果 刘、刘德、刘德华、德、德华、华
     */
    @Field(analyzer = "ngram",type = FieldType.Text)
    private String name;

    @Field(type = FieldType.Keyword)
    private Character gender;

    @Field(type= FieldType.Date,format = DateFormat.custom,pattern = "yyyy-M-d")
    private String birthDate;
}

三、通过 ElasticsearchRepository 实现 CRUD 操作

Spring Data 的 Repository 接口提供了一种声明式的数据操作规范,无序编写任何代码,只需遵循 Spring Data 的方法定义规范即可完成数据的 CRUD 操作。

ElasticsearchRepository 继承自 Repository,其中已经预定义了基本的 CURD 方法,我们可以通过继承 ElasticsearchRepository,添加自定义的数据操作方法。

Repository 方法命名规范

自定义数据操作方法需要遵循 Repository 规范,详情见官方文档

新建StudentRepository接口

/**
 * Repository是Spring定义的一种数据操作规则,只定义抽象接口和方法,不需要添加任何方法,基础增删改查方法在父接口中已经定义好
 */
public interface StudentRepository extends ElasticsearchRepository<Student, Long> {
    List<Student> findByName(String key);//在姓名中搜索关键词
    List<Student> findByNameOrBirthDate(String name, String birthDate);//在姓名和出生日期中搜索关键词
}

学生数据的 CRUD 操作

    @Autowired
    private StudentRepository r;

    @Test//测试添加和修改
    void testSave() {
        //save既是添加,也是修改,id重复就是修改
        r.save(new Student(9527L, "唐伯虎1111", '男', "2021-09-01"));
        r.save(new Student(9528L, "华夫人", '男', "2021-02-01"));
    }

    @Test//测试通过id查询
    void testFindById(){
        Optional<Student> opt=r.findById(9527L);
        if(opt.isPresent()){
            Student student = opt.get();
            System.out.println(student);
        }
    }

    @Test//测试查询所有数据
    void testFineAll(){
        Iterable<Student> all = r.findAll();
        all.forEach(System.out::println);
    }

    @Test
    void testFindByName(){
        List<Student> list = r.findByName("唐");
        list.stream().forEach(System.out::println);
    }

    @Test
    void testFindByNameOrBirthDate(){
        List<Student> list = r.findByNameOrBirthDate("唐", "2021-01-02");
        list.stream().forEach(System.out::println);
    }

依次运行每个测试方法,并使用 head 观察测试结果

四、使用 Criteria 构建查询

Spring Data Elasticsearch 中,可以使用 ElasticsearchOperations 工具执行一些更复杂的查询,这些查询操作接收一个 Query 对象封装的查询操作。

Spring Data Elasticsearch 中的 Query 有三种:

  • CriteriaQuery(多数情况下,CriteriaQuery 都可以满足我们的查询求)
  • StringQuery
  • NativeSearchQuery
@Component
public class StudentSearcher {

    @Autowired
    private ElasticsearchOperations op;//用来执行查询的工具

    public List<Student> findByBirthDate(String birthDate) {
        //用Criteria设置搜索条件
        Criteria c = new Criteria("birthDate");
        c.is(birthDate);
         return exec(c);
    }

    public List<Student> findByBirthDate(String from, String to) {
        Criteria c = new Criteria("birthDate");
        c.between(from, to);
        return exec(c);
    }

    public List<Student> exec(Criteria c) {
        //用查询对象,封装搜索条件
        CriteriaQuery query=new CriteriaQuery(c);
        SearchHits<Student> hits = op.search(query, Student.class);
        //hit集合中取出所有学生对象,放入一个ArrayList集合
        List<Student> studentList = hits.stream().map(SearchHit::getContent).collect(Collectors.toList());
        return studentList;
    }
}

编写测试类测试

1 Repository添加分页

修改StudentRepository接口,添加Pageable参数,返回Page结果

/**
 * Repository是Spring定义的一种数据操作规则,只定义抽象接口和方法,不需要添加任何方法,基础增删改查方法在父接口中已经定义好
 */
public interface StudentRepository extends ElasticsearchRepository<Student, Long> {
    Page<Student> findByName(String key, Pageable pageable);//在姓名中搜索关键词
   
}

测试

    @Test
    void testFindByName(){
        PageRequest pageRequest = PageRequest.of(1, 1);
        Page<Student> page = r.findByName("唐",pageRequest);
        List<Student> content = page.getContent();
        System.out.println(content);
        System.out.println("当前页号:"+page.getNumber()+" ,是否有上一页:"+page.hasPrevious()+",是否有下一页:"+page.hasNext()+",最大页号:"+page.getTotalPages());
    }

2 Criteria添加分页

@Component
public class StudentSearcher {
    @Autowired
    private ElasticsearchOperations op;//用来执行查询的工具

    public List<Student> findByBirthDate(String from, String to,Pageable pageable) {
        Criteria c = new Criteria("birthDate");
        c.between(from, to);
        return exec(c,pageable);
    }

    public List<Student> exec(Criteria c, Pageable pageable) {
        //用查询对象,封装搜索条件
        CriteriaQuery query=new CriteriaQuery(c);
        if(pageable!=null){
            query.setPageable(pageable);
        }
        SearchHits<Student> hits = op.search(query, Student.class);
        //hit集合中取出所有学生对象,放入一个ArrayList集合
        List<Student> studentList = hits.stream().map(SearchHit::getContent).collect(Collectors.toList());
        return studentList;
    }
}

测试

    @Autowired
    private StudentSearcher studentSearcher;

    @Test
    void testElasticsearchOperations(){
        PageRequest pageRequest = PageRequest.of(0, 2);
        List<Student> list = studentSearcher.findByBirthDate("2021-04-01", "2021-09-01", pageRequest);
        System.out.println(list);
    }

你可能感兴趣的:(全文检索,elasticsearch,spring,restful)