Spring Data Elasticsearch基础入门详解

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: Spring Data Elasticsearch基础入门详解

【1】Spring Data Elasticsearch


官网地址:https://spring.io/projects/spring-data-elasticsearch#learn,最新稳定版本为3.2.3。


开发文档地址:https://docs.spring.io/spring-data/elasticsearch/docs/3.2.3.RELEASE/reference/html/#reference



版本标识说明

GA:General Availability,正式发布的版本,官方推荐使用此版本。在国外都是用GA来说明release版本的。
PRE: 预览版,内部测试版. 主要是给开发人员和测试人员测试和找BUG用的,不建议使用;
SNAPSHOT: 快照版,可以稳定使用,且仍在继续改进版本。

Spring Data Elasticsearch



版本新特性


Spring Data Elasticsearch 3.2引入了一下新特性:


Elasticsearch集群支持基本身份验证和SSL传输。

升级至Elasticsearch 6.8.1。

Reactive programming support with Reactive Elasticsearch Operations and Reactive Elasticsearch Repositories.

ElasticsearchEntityMapper作为Jackson对象映射器的替代品。

@Field中的字段名自定义。

支持按查询删除。

Reactive programming support with Reactive Elasticsearch Operations and Reactive Elasticsearch Repositories.这句话这样翻译:响应式的Elasticsearch Operations和响应式的Elasticsearch Repositories一起提供了响应式编程支持。


版本对应说明


Spring Data Release Train Spring Data Elasticsearch Elasticsearch Spring Boot
Moore 3.2.x 6.8.4 2.2.x
Lovelace 3.1.x 6.2.2 2.1.x
Kay 3.0.x 5.5.0 2.0.x
Ingalls 2.1.x 2.4.0 1.5.x


【2】Elasticsearch Clients

Spring data Elasticsearch 可以使用Elasticsearch 客户端连接到单一节点或者集群进行操作。

① Transport Client


在前面Java原生操作Elasticsearch我们就使用的是这个客户端,实话说,确实很难用。

static class Config {
//首先得获取客户端
  @Bean
  Client client() {
    Settings settings = Settings.builder()
      .put("cluster.name", "elasticsearch")   
      .build();
    TransportClient client = new PreBuiltTransportClient(settings);
    client.addTransportAddress(new TransportAddress(InetAddress.getByName("127.0.0.1")
      , 9300));                               
    return client;
  }
}
// ...具体使用诸如下面代码
IndexRequest request = new IndexRequest("spring-data", "elasticsearch", randomID())
 .source(someObject)
 .setRefreshPolicy(IMMEDIATE);
IndexResponse response = client.index(request);

② High Level REST Client(高级REST客户端)


High Level REST Client现在是Elasticsearch默认客户端,它替换掉了Transport Client。异步调用在客户端管理的线程池上操作,并要求在请求完成时通知回调。

引入pom:

<dependency>
  <groupId>org.springframework.data</groupId>
  <artifactId>spring-data-elasticsearch</artifactId>
  <version>3.2.3.RELEASE</version>
</dependency>

配置类:

@Configuration
public class ElasticsearchConfig {
    @Bean
    RestHighLevelClient client() {
        ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo("192.168.18.128:9200")
//                .connectedTo("192.168.18.128:9300", "localhost:9301")
                .build();
        RestHighLevelClient restHighLevelClient = RestClients.create(clientConfiguration).rest();
        System.out.println(restHighLevelClient);
        return restHighLevelClient;
    }
}


测试代码:

  @Autowired
    RestHighLevelClient highLevelClient;
    @Test
    public void test() throws IOException {
        GetRequest getRequest=new GetRequest("my-blog","_all","1");
        RequestOptions option=RequestOptions.DEFAULT;
        GetResponse getResponse = highLevelClient.get(getRequest, option);
        System.out.println(getResponse.getIndex());
        System.out.println(getResponse.toString());
    }

控制台打印:

{
    "_index": "my-blog",
    "_type": "article",
    "_id": "1",
    "_version": 1,
    "found": true,
    "_source": {
        "id": "1",
        "title": "基于Lucene的搜索服务器",
        "content": "它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口"
    }
}


③ Reactive Client


ReactiveElasticsearchClient 是基于WebClient的非官方驱动程序,使用Elasticsearch 核心项目提供的request/response对象。调用直接在反应堆栈上操作,而不是将异步(线程池绑定)响应包装为反应类型。


示例代码如下:

static class Config {
  @Bean
  ReactiveElasticsearchClient client() {
    ClientConfiguration clientConfiguration = ClientConfiguration.builder() 
      .connectedTo("localhost:9200", "localhost:9291")
      .build();
    return ReactiveRestClients.create(clientConfiguration);
  }
}
// ...
Mono<IndexResponse> response = client.index(request ->
  request.index("spring-data")
    .type("elasticsearch")
    .id(randomID())
    .source(singletonMap("feature", "reactive-client"))
    .setRefreshPolicy(IMMEDIATE);
);

④ Client Configuration


上面三个客户端对象都是通过ClientConfiguration对象创建出来的,客户端的行为可以通过该对象改变,也可以选择行的进行其他配置,如ssl。


示例代码:

// optional if Basic Auhtentication is needed
HttpHeaders defaultHeaders = new HttpHeaders();
defaultHeaders.setBasicAuth(USER_NAME, USER_PASS);                      
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
  .connectedTo("localhost:9200", "localhost:9291")                      
  .withConnectTimeout(Duration.ofSeconds(5))                            
  .withSocketTimeout(Duration.ofSeconds(3))                             
  .useSsl()                                                             
  .withDefaultHeaders(defaultHeaders)                                   
  .withBasicAuth(username, password)                                    
  . // ... other options
  .build();

【3】Elasticsearch Object Mapping

Spring Data Elasticsearch允许在通过EntityMapper接口抽象的两个映射实现之间进行选择:


  • Jackson Object Mapping
  • Meta Model Object Mapping


① Jackson Object Mapping


基于Jackson2的方法(默认情况下使用)使用带有spring数据特定模块的自定义ObjectMapper实例。实际映射的扩展需要通过Jackson注释(比如@JsonInclude)进行定制。

示例代码:

@Configuration
public class Config extends AbstractElasticsearchConfiguration { 
  @Override
  public RestHighLevelClient elasticsearchClient() {
    return RestClients.create(ClientConfiguration.create("localhost:9200")).rest();
  }
}

AbstractElasticsearchConfiguration已经通过ElasticsearchConfigurationSupport定义了一个基于Jackson2的entityMapper。注意这时这些注解不能使用:CustomConversions, @ReadingConverter & @WritingConverter,并且@Field(name="custom-name")也不行。

② Meta Model Object Mapping

基于元模型的方法使用域类型信息来读/写Elasticsearch。这允许注册特定域类型映射的转换器实例。

示例代码;

@Configuration
public class Config extends AbstractElasticsearchConfiguration {
  @Override
  public RestHighLevelClient elasticsearchClient() {
    return RestClients.create(ClientConfiguration.create("localhost:9200")).rest()
  }
  @Bean
  @Override
  public EntityMapper entityMapper() {                                 
    ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(
      elasticsearchMappingContext(), new DefaultConversionService()    
    );
    entityMapper.setConversions(elasticsearchCustomConversions());     
    return entityMapper;
  }
}


说明:


覆盖掉ElasticsearchConfigurationSupport 默认配置的EntityMapper 并作为bean对外暴露;

Use the provided SimpleElasticsearchMappingContext to avoid inconsistencies and provide a GenericConversionService for Converter registration.

如果需要,可以设置CustomConversions

③ 对象映射注解

ElasticsearchEntityMapper可以使用元数据来驱动对象到文档的映射。对象上面可以使用注解进行标识。


@Id: 目标对象主键,字段级别注解。


@Document: 类级别注解,标明是个文档对象,有如下重要属性:


indexName: 实体中的索引名字


type: the mapping type.如果未设置,则使用类的小写简单名称。


shards: 索引分片数量


replicas: 索引的副本数


refreshIntervall: 索引的刷新间隔。用于创建索引。默认值为“1s”。


indexStoreType:索引存储类型。用于创建索引。默认值为“fs”。


createIndex: 配置是否在存储库引导时创建索引。默认值为true。


versionType: 版本管理的配置,默认值为 EXTERNAL.


@Transient: 默认所有字段都映射到document, 添加该注解的字段可以例外。


@PersistenceConstructor: 从数据库中实例化对象时,标记要使用的给定构造函数(甚至是受包保护的构造函数)。构造函数参数按名称映射到检索到的文档中的键值。


@Field: 应用于字段级别并定义字段的属性,大多数属性映射到相应的Elasticsearch Mapping定义:


name: field映射到Elasticsearch document中的名称,默认为字段名。


type: 字段类型,可以是如下之一: Text, Integer, Long, Date, Float, Double, Boolean, Object, Auto, Nested, Ip, Attachment, Keyword.


format and pattern custom definitions for the Date type.


store: 标记原始字段值是否应存储在Elasticsearch中,默认值为false。


analyzer, searchAnalyzer, normalizer用于指定自定义分析器和规范化器。


copy_to: 拷贝到多个文档字段的目标字段


@GeoPoint:将字段标记为地理位置数据类型。如果字段是GeoPoint类的实例,则可以忽略。


上述映射元数据注解定义在一个单独的spring-data-commons 项目中,是技术无关的。④ 映射规则

映射规则主要有四方面:

  • Type Hints:按照类型映射;

  • Geospatial Types:点和地质点等地理空间类型转换为纬度/经纬度对。

  • Collections:对于集合内的值,当涉及类型提示和自定义转换时,将应用与聚合根相同的映射规则。
    Maps:同Collections,但是键是需要是字符串

  • Custom Conversions
    可以使用ElasticsearchCustomConversions 注册自定义的映射规则,示例代码如下:
@Configuration
public class Config extends AbstractElasticsearchConfiguration {
  @Override
  public RestHighLevelClient elasticsearchClient() {
    return RestClients.create(ClientConfiguration.create("localhost:9200")).rest();
  }
  @Bean
  @Override
  public EntityMapper entityMapper() {
    ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(
      elasticsearchMappingContext(), new DefaultConversionService());
    entityMapper.setConversions(elasticsearchCustomConversions());  
    return entityMapper;
  }
  @Bean
  @Override
  public ElasticsearchCustomConversions elasticsearchCustomConversions() {
    return new ElasticsearchCustomConversions(
      Arrays.asList(new AddressToMap(), new MapToAddress()));       
  }
  @WritingConverter                                                 
  static class AddressToMap implements Converter<Address, Map<String, Object>> {
    @Override
    public Map<String, Object> convert(Address source) {
      LinkedHashMap<String, Object> target = new LinkedHashMap<>();
      target.put("ciudad", source.getCity());
      // ...
      return target;
    }
  }
  @ReadingConverter                                                 
  static class MapToAddress implements Converter<Map<String, Object>, Address> {
    @Override
    public Address convert(Map<String, Object> source) {
      // ...
      return address;
    }
  }
}


【4】Elasticsearch Operations


在第一部分描述新特性时,有个特性是Reactive programming support with Reactive Elasticsearch Operations and Reactive Elasticsearch Repositorie,这里不能简单翻译而要深入了解一下什么是Reactive Elasticsearch Operations、Reactive Elasticsearch Repositorie才能知道如何提供响应式编程支持。


Spring Data Elasticsearch使用两个接口来定义可以针对Elasticsearch索引调用的操作。分别是ElasticsearchOperations and ReactiveElasticsearchOperations。前者通常用于经典的同步实现,后者用于响应式编程。

接口的默认实现提供如下三方面功能:

  • 对域类型的读/写映射支持。
  • 一个丰富的查询和条件api。
  • 资源管理和异常转换

① ElasticsearchTemplate

ElasticsearchTemplate是ElasticsearchOperations 接口的一个实现,是基于Transport Client操作的。

示例代码如下:

@Configuration
public class TransportClientConfig extends ElasticsearchConfigurationSupport {
  @Bean
  public Client elasticsearchClient() throws UnknownHostException {                 
    Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build();
    TransportClient client = new PreBuiltTransportClient(settings);
    client.addTransportAddress(new TransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
    return client;
  }
  @Bean(name = {"elasticsearchOperations", "elasticsearchTemplate"})
  public ElasticsearchTemplate elasticsearchTemplate() throws UnknownHostException { 
    return new ElasticsearchTemplate(elasticsearchClient(), entityMapper());
  }
  // use the ElasticsearchEntityMapper
  @Bean
  @Override
  public EntityMapper entityMapper() {                                               
    ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(),
      new DefaultConversionService());
    entityMapper.setConversions(elasticsearchCustomConversions());
    return entityMapper;
  }
}

② ElasticsearchRestTemplate

ElasticsearchRestTemplate是ElasticsearchOperations 接口的另一个实现,其是基于High Level REST Client.实现的。


配置代码示例如下:

@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {
    @Override
    public RestHighLevelClient elasticsearchClient() {
        ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo("192.168.18.128:9200")
                .withSocketTimeout(60000)
                .withConnectTimeout(60000)
                .build();
        RestHighLevelClient restHighLevelClient = RestClients.create(clientConfiguration).rest();
        System.out.println("RestClientConfig-elasticsearchClient:"+restHighLevelClient);
        return restHighLevelClient;
    }
    // no special bean creation needed
    // use the ElasticsearchEntityMapper
    @Bean
    @Override
    public EntityMapper entityMapper() {
        ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(),
                new DefaultConversionService());
        entityMapper.setConversions(elasticsearchCustomConversions());
        return entityMapper;
    }
}

③ Spring REST controller中使用ElasticsearchOperations

具体ElasticsearchOperations 使用哪种实现,主要依据上面两种配置。示例代码如下:

@RestController
public class TestController {
    @Autowired
    private ElasticsearchOperations elasticsearchOperations;
//    public TestController(ElasticsearchOperations elasticsearchOperations) {
//        this.elasticsearchOperations = elasticsearchOperations;
//    }
    @PostMapping("/person")
    public String save(@RequestBody Person person) {
        System.out.println("elasticsearchOperations:"+elasticsearchOperations);
        IndexQuery indexQuery = new IndexQueryBuilder()
                .withId(person.getId().toString())
                .withObject(person)
                .build();
        String documentId = elasticsearchOperations.index(indexQuery);
        return documentId;
    }
    @GetMapping("/person/{id}")
    public Person findById(@PathVariable("id")  Long id) {
        Person person = elasticsearchOperations
                .queryForObject(GetQuery.getById(id.toString()), Person.class);
        return person;
    }
}

Person类实例代码:

@Document(indexName = "person",type = "person")
public class Person {
    @Id
    private Integer id;
    @Field
    private String name;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

上面两个都是ElasticsearchOperations 的实现,下面讲解Reactive Elasticsearch Operations实现。


④ Reactive Elasticsearch Operations


ReactiveElasticsearchOperations是Elasticsearch集群使用ReactiveElasticsearchClient执行高级命令的网关。ReactiveElasticsearchOperations的默认实现是ReactiveElasticsearchTemplate 。


示例代码如下:

@Configuration
public class Config extends AbstractReactiveElasticsearchConfiguration {
  @Bean 
  @Override
  public ReactiveElasticsearchClient reactiveElasticsearchClient() {
      // ...
  }
}

使用ReactiveElasticsearchClient 最简单方法就是继承AbstractReactiveElasticsearchConfiguration 并覆盖reactiveElasticsearchClient方法,然后作为bean暴露给外部。方法体内部可以使用ReactiveRestClients 定义 Reactive Client或者默认使用DefaultReactiveElasticsearchClient。


如果想对组件有更多自定义控制,可以如下所示进行配置:

@Configuration
public class Config {
  @Bean 
  public ReactiveElasticsearchClient reactiveElasticsearchClient() {
    // ...
  }
  @Bean 
  public ElasticsearchConverter elasticsearchConverter() {
    return new MappingElasticsearchConverter(elasticsearchMappingContext());
  }
  @Bean 
  public SimpleElasticsearchMappingContext elasticsearchMappingContext() {
    return new SimpleElasticsearchMappingContext();
  }
  @Bean 
  public ReactiveElasticsearchOperations reactiveElasticsearchOperations() {
    return new ReactiveElasticsearchTemplate(reactiveElasticsearchClient(), elasticsearchConverter());
  }
}

⑤ ReactiveElasticsearchTemplate实际使用

实例代码如下:

@Document(indexName = "marvel", type = "characters")
public class Person {
  private @Id String id;
  private String name;
  private int age;
  // Getter/Setter omitted...
}
template.save(new Person("Bruce Banner", 42))                    
  .doOnNext(System.out::println)
  .flatMap(person -> template.findById(person.id, Person.class)) 
  .doOnNext(System.out::println)
  .flatMap(person -> template.delete(person))                    
  .doOnNext(System.out::println)
  .flatMap(id -> template.count(Person.class))                   
  .doOnNext(System.out::println)
  .subscribe(); 

控制台打印:


> Person(id=QjWCWWcBXiLAnp77ksfR, name=Bruce Banner, age=42)
> Person(id=QjWCWWcBXiLAnp77ksfR, name=Bruce Banner, age=42)
> QjWCWWcBXiLAnp77ksfR
> 0

可以发现相比于RestHighLevelClient 而言ReactiveElasticsearchTemplate主要就是流式编程,可以直接使用Lamda表达式及隐式函数进行操作。


【5】Elasticsearch Repositories


Repository,了解jpa的应该知道,Spring Data默认定义了一些接口实现了一些常用的增删改查方法,你只需要声明自己接口继承于Spring Data的接口即可使用那些方法且不用自己实现。当然,你可以自己实现自己定义方法。


① 查询方法与查询策略


Elasticsearch模块支持所有基本的查询构建功能,如字符串查询、本地索查询、基于条件的查询或从方法名派生。从方法名派生查询并不总是足够的,并且/或者可能导致无法读取方法名。在这种情况下,可以使用@Query注解。

通常,Elasticsearch的查询创建机制的工作方式如查询方法中所述,实例如下:

interface BookRepository extends Repository<Book, String> {
  List<Book> findByNameAndPrice(String name, Integer price);
}

等同于如下Elasticsearch json 查询串:

{ "bool" :
    { "must" :
        [
            { "field" : {"name" : "?"} },
            { "field" : {"price" : "?"} }
        ]
    }
}

Elasticsearch 支持的关键字与对应的json 查询列表如下:

Keyword Sample Elasticsearch Query String
And findByNameAndPrice {“bool” : {“must” : [ {“field” : {“name” : “?”}}, {“field” : {“price” : “?”}} ]}}

4.png5.png6.png


② @Query注解

如果想自定义查询,可以选择在方法上用注解标识查询条件,实例如下:

interface BookRepository extends ElasticsearchRepository<Book, String> {
    @Query("{\"bool\" : {\"must\" : {\"field\" : {\"name\" : \"?0\"}}}}")
    Page<Book> findByName(String name,Pageable pageable);
}


③ 基于注解的配置

Spring Data Elasticsearch repositories using JavaConfig,for example:

@Configuration
@EnableElasticsearchRepositories(                             
  basePackages = "org.springframework.data.elasticsearch.repositories"
  )
static class Config {
  @Bean
  public ElasticsearchOperations elasticsearchTemplate() {    
      // ...
  }
}
class ProductService {
  private ProductRepository repository;                       
  public ProductService(ProductRepository repository) {
    this.repository = repository;
  }
  public Page<Product> findAvailableBookByName(String name, Pageable pageable) {
    return repository.findByAvailableTrueAndNameStartingWith(name, pageable);
  }
}

需要说明的是,EnableElasticsearchRepositories注解激活Repository 支持。如果没有配置基包( base package),则它将使用在任何添加该注解的配置类上。


④ Elasticsearch Repositories using CDI*


Spring Data Elasticsearch repositories同样支持CDI(上下文依赖注入)能力,实例如下:

class ElasticsearchTemplateProducer {
  @Produces
  @ApplicationScoped
  public ElasticsearchOperations createElasticsearchTemplate() {
    // ...                               
  }
}
class ProductService {
  private ProductRepository repository;  
  public Page<Product> findAvailableBookByName(String name, Pageable pageable) {
    return repository.findByAvailableTrueAndNameStartingWith(name, pageable);
  }
  @Inject
  public void setRepository(ProductRepository repository) {
    this.repository = repository;
  }
}

⑤ Spring applicationContext.xml中配置Elasticsearch

Setting up Elasticsearch repositories using Namespace:

<?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:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/data/elasticsearch
       https://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
  <elasticsearch:repositories base-package="com.acme.repositories" />
</beans>

Transport Client using Namespace:

<?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:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/data/elasticsearch
       https://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
  <elasticsearch:transport-client id="client" cluster-nodes="localhost:9300,someip:9300" />
</beans>

Rest Client using Namespace:

<?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:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
       xsi:schemaLocation="http://www.springframework.org/schema/data/elasticsearch
       https://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch.xsd
       http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans.xsd">
  <elasticsearch:rest-client id="restClient" hosts="http://localhost:9200">
</beans>

【6】Reactive Elasticsearch Repositories

Reactive Elasticsearch repository支持Spring Data Repositories核心接口扩展,通过Reactive Elasticsearch Operations实现(Reactive Client实际执行)。

Reactive Elasticsearch repository是使用Project Reactor作为其组件来实现响应编程。

有三个接口主要被使用:

  • ReactiveRepository
  • ReactiveCrudRepository
  • ReactiveSortingRepository

① 配置ReactiveRepositoryConfig

@Configuration
@EnableReactiveElasticsearchRepositories
public class ReactiveRepositoryConfig extends AbstractReactiveElasticsearchConfiguration {
    @Override
    public ReactiveElasticsearchClient reactiveElasticsearchClient() {
        ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo("192.168.18.128:9200")
                .withSocketTimeout(60000)
                .withConnectTimeout(60000)
                .build();
        ReactiveElasticsearchClient reactiveElasticsearchClient = ReactiveRestClients.create(clientConfiguration);
        System.out.println("reactiveElasticsearchClient is created:"+reactiveElasticsearchClient);
        return reactiveElasticsearchClient;
    }
}


② Domain Object

@Document(indexName = "person",type = "person")
public class Person {
    @Id
    private String id;
    private String firstname;
    private String lastname;
//...
}

③ 自定义Repository接口继承自ReactiveSortingRepository

实例代码如下:

public interface ReactivePersonRepository extends ReactiveSortingRepository<Person, String> {
    Flux<Person> findByFirstname(String firstname);
    Flux<Person> findByFirstname(Publisher<String> firstname);
    Flux<Person> findByFirstnameOrderByLastname(String firstname);
    Flux<Person> findByFirstname(String firstname, Sort sort);
    Flux<Person> findByFirstname(String firstname, Pageable page);
    Mono<Person> findByFirstnameAndLastname(String firstname, String lastname);
    Mono<Person> findFirstByLastname(String lastname);
    @Query("{ \"bool\" : { \"must\" : { \"term\" : { \"lastname\" : \"?0\" } } } }")
    Flux<Person> findByLastname(String lastname);
    Mono<Long> countByFirstname(String firstname);
    Mono<Boolean> existsByFirstname(String firstname);
    Mono<Long> deleteByFirstname(String firstname);
}

可以看到ReactiveSortingRepository又继承自ReactiveCrudRepository,故而当前ReactivePersonRepository 可以使用CRUD和Sort等方法。


④ 测试代码

@RestController
public class ReactiveController {
    @Autowired
    ReactivePersonRepository repository;
    @RequestMapping("/testReactive")
    public String testReactive() {
        Flux<Person> persons = repository.findAll();
        System.out.println(persons.blockFirst());
        Mono<List<Person>> listMono = persons.collectList();
        System.out.println("listMono:"+ listMono);
        List<Person> personList = listMono.block();
        System.out.println("personList:"+personList);
        return persons.toString();
    }
}

【7】Miscellaneous Elasticsearch Operation Support

Elasticsearch Operation还提供了许多其他支持,而这些支持不能直接通过repository 接口来使用,它更被推荐在自定义接口实现里面使用。


① 查询过滤器

实例如下:

private ElasticsearchTemplate elasticsearchTemplate;
SearchQuery searchQuery = new NativeSearchQueryBuilder()
  .withQuery(matchAllQuery())
  .withFilter(boolFilter().must(termFilter("id", documentId)))
  .build();
Page<SampleEntity> sampleEntities =
  elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.class);


② 滚动输出大结果集

Elasticsearch 针对大数据量结果提供了scroll API,ElasticsearchTemplate 有startScroll and continueScroll 方法可以被使用,如下所示:

SearchQuery searchQuery = new NativeSearchQueryBuilder()
  .withQuery(matchAllQuery())
  .withIndices(INDEX_NAME)
  .withTypes(TYPE_NAME)
  .withFields("message")
  .withPageable(PageRequest.of(0, 10))
  .build();
ScrolledPage<SampleEntity> scroll = elasticsearchTemplate.startScroll(1000, searchQuery, SampleEntity.class);
String scrollId = scroll.getScrollId();
List<SampleEntity> sampleEntities = new ArrayList<>();
while (scroll.hasContent()) {
  sampleEntities.addAll(scroll.getContent());
  scrollId = scroll.getScrollId();
  scroll = elasticsearchTemplate.continueScroll(scrollId, 1000, SampleEntity.class);
}
elasticsearchTemplate.clearScroll(scrollId);

ElasticsearchTemplate 同样提供了流方法使用,如下所示:

SearchQuery searchQuery = new NativeSearchQueryBuilder()
  .withQuery(matchAllQuery())
  .withIndices(INDEX_NAME)
  .withTypes(TYPE_NAME)
  .withFields("message")
  .withPageable(PageRequest.of(0, 10))
  .build();
CloseableIterator<SampleEntity> stream = elasticsearchTemplate.stream(searchQuery, SampleEntity.class);
List<SampleEntity> sampleEntities = new ArrayList<>();
while (stream.hasNext()) {
  sampleEntities.add(stream.next());
}

相关实例代码GitHub地址:https://github.com/JanusJ/SpringBoot/tree/master/elasticsearch

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
目录
相关文章
|
30天前
|
存储 Java API
如何使用 Java 记录简化 Spring Data 中的数据实体
如何使用 Java 记录简化 Spring Data 中的数据实体
34 9
|
25天前
|
Java API Spring
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中拦截器的入门教程和实战项目场景实现的详细指南。
17 0
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
|
25天前
|
Java API Spring
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中过滤器的基础知识和实战项目应用的教程。
21 0
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
|
2月前
|
Java 数据库连接 API
【Java笔记+踩坑】Spring Data JPA
从常用注解、实体类和各层编写方法入手,详细介绍JPA框架在增删改查等方面的基本用法,以及填充用户名日期、分页查询等高级用法。
【Java笔记+踩坑】Spring Data JPA
|
3月前
|
Java Spring 数据库
怎样动动手指就能实现数据操作?Spring Data JPA背后的魔法揭秘
【8月更文挑战第31天】在Java开发中,数据库交互至关重要。传统的JDBC操作繁琐且难维护,而Spring Data JPA作为集成JPA的数据访问层解决方案,提供了CRUD等通用操作接口,显著减少代码量。通过继承`JpaRepository`,开发者能轻松实现数据的增删改查,甚至复杂查询和分页也不再困难。本文将通过示例详细介绍如何利用Spring Data JPA简化数据访问层的开发,提升代码质量和可维护性。
41 0
|
3月前
|
缓存 Java Spring
Spring缓存实践指南:从入门到精通的全方位攻略!
【8月更文挑战第31天】在现代Web应用开发中,性能优化至关重要。Spring框架提供的缓存机制可以帮助开发者轻松实现数据缓存,提升应用响应速度并减少服务器负载。通过简单的配置和注解,如`@Cacheable`、`@CachePut`和`@CacheEvict`,可以将缓存功能无缝集成到Spring应用中。例如,在配置文件中启用缓存支持并通过`@Cacheable`注解标记方法即可实现缓存。此外,合理设计缓存策略也很重要,需考虑数据变动频率及缓存大小等因素。总之,Spring缓存机制为提升应用性能提供了一种简便快捷的方式。
48 0
|
3月前
|
SQL Java 数据库连接
Spring Boot联手MyBatis,打造开发利器:从入门到精通,实战教程带你飞越编程高峰!
【8月更文挑战第29天】Spring Boot与MyBatis分别是Java快速开发和持久层框架的优秀代表。本文通过整合Spring Boot与MyBatis,展示了如何在项目中添加相关依赖、配置数据源及MyBatis,并通过实战示例介绍了实体类、Mapper接口及Controller的创建过程。通过本文,你将学会如何利用这两款工具提高开发效率,实现数据的增删查改等复杂操作,为实际项目开发提供有力支持。
144 0
|
3月前
|
存储 Java 数据库
|
3月前
|
存储 Java API
|
3月前
|
Java 数据库连接 数据库
Spring Data JPA 与 Hibernate 之区别
【8月更文挑战第21天】
73 0