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可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
目录
相关文章
|
2月前
|
存储 Java API
Elasticsearch 7.8.0从入门到精通
这篇文章详细介绍了Elasticsearch 7.8.0的安装、核心概念(如正排索引和倒排索引)、RESTful风格、各种索引和文档操作、条件查询、聚合查询以及在Spring Boot中整合Elasticsearch的步骤和示例。
156 1
Elasticsearch 7.8.0从入门到精通
|
3月前
|
数据可视化 Java Windows
Elasticsearch入门-环境安装ES和Kibana以及ES-Head可视化插件和浏览器插件es-client
本文介绍了如何在Windows环境下安装Elasticsearch(ES)、Elasticsearch Head可视化插件和Kibana,以及如何配置ES的跨域问题,确保Kibana能够连接到ES集群,并提供了安装过程中可能遇到的问题及其解决方案。
Elasticsearch入门-环境安装ES和Kibana以及ES-Head可视化插件和浏览器插件es-client
|
3月前
|
存储 关系型数据库 MySQL
浅谈Elasticsearch的入门与实践
本文主要围绕ES核心特性:分布式存储特性和分析检索能力,介绍了概念、原理与实践案例,希望让读者快速理解ES的核心特性与应用场景。
101 12
|
21天前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
38 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
18天前
|
Java 数据库连接 数据库
从入门到精通---深入剖析Spring DAO
在Java企业级开发中,Spring框架以其强大的功能和灵活性,成为众多开发者的首选。Spring DAO(Data Access Object)作为Spring框架中处理数据访问的重要模块,对JDBC进行了抽象封装,极大地简化了数据访问异常的处理,并能统一管理JDBC事务。本文将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring DAO,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
21 1
|
22天前
|
监控 Java 数据安全/隐私保护
如何用Spring Boot实现拦截器:从入门到实践
如何用Spring Boot实现拦截器:从入门到实践
38 5
|
1月前
|
存储 JSON Java
ELK 圣经:Elasticsearch、Logstash、Kibana 从入门到精通
ELK是一套强大的日志管理和分析工具,广泛应用于日志监控、故障排查、业务分析等场景。本文档将详细介绍ELK的各个组件及其配置方法,帮助读者从零开始掌握ELK的使用。
|
2月前
|
存储 Java API
如何使用 Java 记录简化 Spring Data 中的数据实体
如何使用 Java 记录简化 Spring Data 中的数据实体
42 9
|
2月前
|
Java API Spring
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中拦截器的入门教程和实战项目场景实现的详细指南。
34 0
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
|
2月前
|
Java API Spring
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中过滤器的基础知识和实战项目应用的教程。
36 0
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现