栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

Elasticsearch(五)Spring Data Elasticsearch - 增删改查API

Elasticsearch(五)Spring Data Elasticsearch - 增删改查API

创建一个Spring工程 es 添加依赖

spring data elasticsearch



    4.0.0
    
    
        org.springframework.boot
        spring-boot-starter-parent
        2.3.2.RELEASE
         
    
    
    cn.tedu
    es
    0.0.1-SNAPSHOT
    es
   
    Demo project for Spring Boot
    
    
        1.8
    
    
    
        
            org.springframework.boot
            spring-boot-starter-data-elasticsearch
        

		
            org.projectlombok
            lombok
        	
 
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


yml文件
spring:
  elasticsearch:
    rest:
      uris:
        - http://192.168.64.181:9200
        - http://192.168.64.181:9201
        - http://192.168.64.181:9202
logging:
  level:
    tracer: TRACE
Student 实体类
package cn.tedu.es.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

@document(indexName = "students",shards = 3,replicas = 2)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    @Id
    private Long id;

    @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;
}
@document 注解

@Documnet注解对索引的参数进行设置。

上面代码中,把 students 索引的分片数设置为3,副本数设置为2。

@Id 注解

在 Elasticsearch 中创建文档时,使用 @Id 注解的字段作为文档的 _id 值

@Field 注解

通过 @Field 注解设置字段的数据类型和其他属性。

文本类型 text 和 keyword

text 类型会进行分词。

keyword 不会分词。

analyzer 指定分词器

通过 analyzer 设置可以指定分词器,例如 ik_smart、ik_max_word 等。

我们这个例子中,对学生姓名字段使用的分词器是 ngram 分词器,其分词效果如下面例子所示:

字符串分词结果
刘德华
刘德
刘德华

德华
通过 ElasticsearchRepository 实现 CRUD 操作

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

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

Repository 方法命名规范

自定义数据操作方法需要遵循 Repository 规范,示例如下:

关键词方法名es查询
AndfindByNameAndPrice{ “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } }, { “query_string” : { “query” : “?”, “fields” : [ “price” ] } } ] } }}
OrfindByNameOrPrice{ “query” : { “bool” : { “should” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } }, { “query_string” : { “query” : “?”, “fields” : [ “price” ] } } ] } }}
IsfindByName{ “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } } ] } }}
NotfindByNameNot{ “query” : { “bool” : { “must_not” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } } ] } }}
BetweenfindByPriceBetween{ “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : ?, “include_lower” : true, “include_upper” : true } } } ] } }}
LessThanfindByPriceLessThan{ “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : null, “to” : ?, “include_lower” : true, “include_upper” : false } } } ] } }}
LessThanEqualfindByPriceLessThanEqual{ “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : null, “to” : ?, “include_lower” : true, “include_upper” : true } } } ] } }}
GreaterThanfindByPriceGreaterThan{ “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : null, “include_lower” : false, “include_upper” : true } } } ] } }}
GreaterThanEqualfindByPriceGreaterThan{ “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : null, “include_lower” : true, “include_upper” : true } } } ] } }}
BeforefindByPriceBefore{ “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : null, “to” : ?, “include_lower” : true, “include_upper” : true } } } ] } }}
AfterfindByPriceAfter{ “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : null, “include_lower” : true, “include_upper” : true } } } ] } }}
LikefindByNameLike{ “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?*”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }}
StartingWithfindByNameStartingWith{ “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?*”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }}
EndingWithfindByNameEndingWith{ “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “*?”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }}
Contains/ContainingfindByNameContaining{ “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }}
In (when annotated as FieldType.Keyword)findByNameIn(Collectionnames){ “query” : { “bool” : { “must” : [ {“bool” : {“must” : [ {“terms” : {“name” : ["?","?"]}} ] } } ] } }}
InfindByNameIn(Collectionnames){ “query”: {“bool”: {“must”: [{“query_string”:{“query”: “”?" “?”", “fields”: [“name”]}}]}}}
NotIn (when annotated as FieldType.Keyword)findByNameNotIn(Collectionnames){ “query” : { “bool” : { “must” : [ {“bool” : {“must_not” : [ {“terms” : {“name” : ["?","?"]}} ] } } ] } }}
NotInfindByNameNotIn(Collectionnames){“query”: {“bool”: {“must”: [{“query_string”: {“query”: “NOT(”?" “?”)", “fields”: [“name”]}}]}}}
NearfindByStoreNearNot Supported Yet !
TruefindByAvailableTrue{ “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “true”, “fields” : [ “available” ] } } ] } }}
FalsefindByAvailableFalse{ “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “false”, “fields” : [ “available” ] } } ] } }}
OrderByfindByAvailableTrueOrderByNameDesc{ “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “true”, “fields” : [ “available” ] } } ] } }, “sort”:[{“name”:{“order”:“desc”}}] }
StudentRepository
package cn.tedu.es.repo;

import cn.tedu.es.entity.Student;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;


public interface StudentRepository extends ElasticsearchRepository {
    //在name字段中查找关键字
    List findByName(String name);
    //在name字段中搜索关键词,或者birthDate字段匹配日期
    List findByNameOrBirthDate(String name, String birthDate);
}
测试学生数据的 CRUD 操作

添加测试类,对学生数据进行 CRUD 测试

package cn.tedu.es;

import cn.tedu.es.entity.Student;
import cn.tedu.es.repo.StudentRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;
import java.util.Optional;

@SpringBootTest
public class Test1 {

    @Autowired
    private StudentRepository repository;

    @Test
    public void test1(){
        //在 es 服务器的 student索引中保存学生
        repository.save(new Student(9527L,"唐伯虎",'男',"2021-11-12"));
        repository.save(new Student(9528L,"华夫人",'女',"2021-11-12"));
        repository.save(new Student(9529L,"祝枝山",'男',"2021-11-12"));
        repository.save(new Student(9530L,"小强",'男',"2021-11-12"));
        repository.save(new Student(9531L,"旺财",'男',"2021-11-12"));
        repository.save(new Student(9532L,"如花",'女',"2021-11-12"));
    }

    @Test
    public void test2(){
        repository.save(new Student(9533L,"华太师",'男',"2020-11-20"));
    }

    @Test
    public void test3(){
        Optional stu = repository.findById(9527L);

        if(stu.isPresent()){ //Optional对象中是否存在Student对象
            System.out.println(stu);
        }
        System.out.println("------------------------------------");

        Iterable it = repository.findAll();
        for (Student s : it){
            System.out.println(s);
        }
    }

    @Test
    public void test4(){
        repository.deleteById(9531L);
    }

    @Test
    public void test5(){
        List list = repository.findByName("唐");
        for(Student s :list){
            System.out.println(s);
        }
    }

    @Test
    public void test6(){
        List list = repository.findByNameOrBirthDate("唐", "2021-11-12");
        for(Student s :list){
            System.out.println(s);
        }
    }
}

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

业务类 StudentService
package cn.tedu.esspringboot.es;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class StudentService {
    @Autowired
    private StudentRepository studentRepo;

    public void save(Student student) {
        studentRepo.save(student);
    }

    public void delete(Long id) {
        studentRepo.deleteById(id);
    }

    public void update(Student student) {
        save(student);
    }

    public List findByName(String name) {
        return studentRepo.findByName(name);
    }

    public List findByNameOrBirthDate(String name, String birthDate) {
        return studentRepo.findByNameOrBirthDate(name, birthDate);
    }
}
在 Elasticsearch 中创建 students 索引

在开始运行测试之前,在 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"
      }
    }
  }
}
使用 Criteria 构建查询

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

Spring Data Elasticsearch 中的 Query 有三种:

  • CriteriaQuery
  • StringQuery
  • NativeSearchQuery

多数情况下,CriteriaQuery 都可以满足我们的查询求。下面来看两个 Criteria 查询示例:

StudentSearcher
package cn.tedu.es.creteria;

import cn.tedu.es.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class StudentSearcher {

    @Autowired
    private ElasticsearchOperations operations;

    public List searchByName(String key) {
        //在 name 字段中搜索关键词
        Criteria c = new Criteria("name");//新建条件对象
        c.is(key); //设置条件
        return exec(c);
    }

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

    private List exec(Criteria c) {
        // 搜索条件封装到 Query 对象
        CriteriaQuery query = new CriteriaQuery(c);
        //使用 ElasticsearchOperations 工具来执行查询
        //SearchHits 对象中包含学生数据、相关度得分、高亮字段
        SearchHits search = operations.search(query, Student.class);
        List list = new ArrayList<>();
        for(SearchHit sh : search){
            Student stu = sh.getContent();
            list.add(stu);
        }
        return list;
    }
}
新建测试类测试
package cn.tedu.es;

import cn.tedu.es.creteria.StudentSearcher;
import cn.tedu.es.entity.Student;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class Test2 {
    @Autowired
    private StudentSearcher searcher;

    @Test
    public void test1(){
        List list = searcher.searchByName("唐");
        for(Student s : list){
            System.out.println(s);
        }
    }

    @Test
    public void test2(){
        List list = searcher.searchByBirthDate("2020-01-01", "2022-01-01");
        for(Student s : list){
            System.out.println(s);
        }
    }
}
分页查询 在 StudentRepository 添加方法

新建测试类
package cn.tedu.es;

import cn.tedu.es.entity.Student;
import cn.tedu.es.repo.StudentRepository;
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 org.springframework.data.domain.Pageable;

@SpringBootTest
public class Test3 {
    @Autowired
    private StudentRepository repository;

    @Test
    public void test1(){
        Pageable pageable = PageRequest.of(0, 2);

        Page list = repository.findByNameOrBirthDate("唐", "2021-11-12",pageable);
        System.out.println("共有几页:"+list.getTotalPages());
        System.out.println("是否有上一页:"+list.hasPrevious());
        System.out.println("是否有下一页:"+list.hasNext());
        System.out.println("每页大小(每页显示几条数据):"+list.getSize());

        for(Student s :list){
            System.out.println(s);
        }
    }
}

查看分页数据

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/422728.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号