Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Next Level Elasticsearch Integration with Spring Data Elasticsearch

Next Level Elasticsearch Integration with Spring Data Elasticsearch

The slides for my session at ElasticON Global on October 14th and 15th 2020

Peter-Josef Meisch

October 15, 2020
Tweet

Other Decks in Programming

Transcript

  1. 2 Nothing will stop you being creative more effectively as

    the fear of making a mistake. John Cleese
  2. “Spring Data’s mission is to provide a familiar and consistent,

    Spring-based programming model for data access while still retaining the special traits of the underlying data store.”
  3. Configure the connection to Elasticsearch @Configuration public class RestClientConfig extends

    AbstractElasticsearchConfiguration { @Override @Bean public RestHighLevelClient elasticsearchClient() { ClientConfiguration clientConfiguration = ClientConfiguration.builder() .connectedTo("localhost:9200") .build(); return RestClients.create(clientConfiguration).rest(); } }
  4. Configure the connection to Elasticsearch @Configuration public class RestClientConfig extends

    AbstractElasticsearchConfiguration { @Override @Bean public RestHighLevelClient elasticsearchClient() { ClientConfiguration clientConfiguration = ClientConfiguration.builder() .connectedTo("localhost:9200") .withProxy("localhost:8080") .build(); return RestClients.create(clientConfiguration).rest(); } }
  5. Configure the connection to Elasticsearch @Configuration public class RestClientConfig extends

    AbstractElasticsearchConfiguration { @Override @Bean public RestHighLevelClient elasticsearchClient() { ClientConfiguration clientConfiguration = ClientConfiguration.builder() .connectedTo("localhost:9200") .usingSsl() .build(); return RestClients.create(clientConfiguration).rest(); } }
  6. Configure the connection to Elasticsearch @Configuration public class RestClientConfig extends

    AbstractElasticsearchConfiguration { @Override @Bean public RestHighLevelClient elasticsearchClient() { ClientConfiguration clientConfiguration = ClientConfiguration.builder() .connectedTo("localhost:9200") .withBasicAuth("myuser", "mypassword") .build(); return RestClients.create(clientConfiguration).rest(); } }
  7. Configure the connection to Elasticsearch @Configuration public class RestClientConfig extends

    AbstractElasticsearchConfiguration { @Override @Bean public RestHighLevelClient elasticsearchClient() { ClientConfiguration clientConfiguration = ClientConfiguration.builder() .connectedTo("localhost:9200") .withPathPrefix("customer1") .build(); return RestClients.create(clientConfiguration).rest(); } }
  8. Configure the connection to Elasticsearch Supplier<HttpHeaders> currentTimeHeaders = () ->

    { HttpHeaders headers = new HttpHeaders(); headers.add("currentTime", LocalDateTime.now() .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); return headers; }; ClientConfiguration clientConfiguration = ClientConfiguration.builder() .connectedTo("localhost:9200") .withHeaders(currentTimeHeaders) .build();
  9. Entity definition public class Person { @Id private String id;

    private String lastName; private String firstName; private LocalDate birthDate; }
  10. Entity definition @Document(indexName = "person") public class Person { @Id

    private String id; private String lastName; private String firstName; private LocalDate birthDate; }
  11. Entity definition @Document(indexName = "person") public class Person { @Id

    private String id; @Field(type = FieldType.Text) private String lastName; @Field(type = FieldType.Text) private String firstName; private LocalDate birthDate; }
  12. Entity definition @Document(indexName = "person") public class Person { @Id

    private String id; @Field(type = FieldType.Text) private String lastName; @Field(type = FieldType.Text) private String firstName; @Field(type = FieldType.Date, format = DateFormat.basic_date) private LocalDate birthDate; }
  13. IndexOperations • index creation and deletion • index settings •

    index mappings • index templates • alias management • refresh operation
  14. IndexOperations private ElasticsearchOperations operations ; // injected by Spring IndexOperations

    indexOps = operations.indexOps(Person.class); indexOps.create(); indexOps.putMapping(); PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("template-name", "log-*") .withSettings(settings) .withMappings(mapping) .withAliasActions(aliasActions) .build(); indexOps.putTemplate(putTemplateRequest);
  15. IndexOperations private ElasticsearchOperations operations; // injected by Spring IndexOperations indexOps

    = operations.indexOps(Person.class) ; indexOps.create(); indexOps.putMapping(); PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("template-name", "log-*") .withSettings(settings) .withMappings(mapping) .withAliasActions(aliasActions) .build(); indexOps.putTemplate(putTemplateRequest);
  16. IndexOperations private ElasticsearchOperations operations; // injected by Spring IndexOperations indexOps

    = operations.indexOps(Person.class); indexOps.create(); indexOps.putMapping(); PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("template-name", "log-*") .withSettings(settings) .withMappings(mapping) .withAliasActions(aliasActions) .build(); indexOps.putTemplate(putTemplateRequest);
  17. IndexOperations private ElasticsearchOperations operations; // injected by Spring IndexOperations indexOps

    = operations.indexOps(Person.class); indexOps.create(); indexOps.putMapping(); PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("template-name", "log-*") .withSettings(settings) .withMappings(mapping) .withAliasActions(aliasActions) .build(); indexOps.putTemplate(putTemplateRequest) ;
  18. NativeSearchQuery import static org.elasticsearch.index.query.QueryBuilders.*; import static org.elasticsearch.search.aggregations.AggregationBuilders.*; Query query =

    new NativeSearchQueryBuilder() .addAggregation( terms("lastNames").field("lastName").size(10) ) .withQuery( matchQuery("firstName", firstName) ) .build(); SearchHits<Person> searchHits = operations.search(query, Person.class);
  19. StringQuery Query query = new StringQuery( "{" + " \"bool\":

    {" + " \"must\": [" + " {" + " \"match\": {" + " \"lastName\": \"Smith\"" + " }" + " }" + " ]" + " }" + "}"); SearchHits<Person> searchHits = operations.search(query, Person.class);
  20. CriteriaQuery Criteria criteria = new Criteria("lastName").is("Smith") .and("firstName").is("James"); Query query =

    new CriteriaQuery(criteria); SearchHits<Person> searchHits = operations.search(query, Person.class);
  21. SearchHit<T • id • index name • the entity of

    type T • score • sort values • highlight fields • inner hits
  22. SearchHits<T • number of total hits • total hits relation

    (eq, gte) • list of SearchHit<T> objects • max score • aggregations
  23. Repository interface PersonRepository extends ElasticsearchRepository< Person, String > { }

    // ElasticsearchRepository // +PagingAndSortingRepository // + CrudRepository // + Repository
  24. Repository count() delete(T) deleteAll() deleteAll(Iterable<? extends T) deleteById(ID) existsById(ID) findAll()

    findAll(Pageable) findAll(Sort) findAllById(Iterable<ID>) findById(ID) save(T) saveAll(Iterable<T>) searchSimilar(T entity, String[] fields, Pageable pageable)
  25. Repository methods interface PersonRepository extends ElasticsearchRepository< Person, String > {

    List<Person> searchByFirstName(String name); List<Person> findByFirstNameOrderByLastNameAsc(String name); List<Person> queryByBirthDateBefore(LocalDate date); }
  26. Repository methods interface PersonRepository extends ElasticsearchRepository<Person, String> { @Query(value =

    "{\"fuzzy\":{\"lastName\":\"?0\"}}") List<Person> findByLastNameFuzzy(String lastName); }
  27. Repository usage @RestController @RequestMapping(”/persons”) public class PersonController { private PersonRepository

    repository; public PersonController(PersonRepository repository) { this.repository = repository; } @GetMapping(”/firstName/{name}”) List<Person> byFirstName( @PathVariable(”name”) String name) { return repository.searchByFirstName(name) ; } }
  28. Repository method with highlight definition interface PersonRepository extends ElasticsearchRepository<Person, String>

    { @Highlight(fields = { @HighlightField(name = "firstName") }) SearchHits<Person> searchByFirstName(String name); } repository.searchByFirstName(”James”) .forEach(searchHit -> { List<String> highlights = searchHit.getHighlightField("firstName"); // ... });
  29. Lifecycle events @Component public class PersonBeforeConvertCallback implements BeforeConvertCallback<Person> { @Override

    public Person onBeforeConvert(Person person, IndexCoordinates indexCoordinates) { if (person.getId() == null) { person.setId(UUID.randomUUID().toString()); } return person; } }
  30. Auditable Entity @Document(indexName = "person") public class Person implements Persistable<String>

    { @Id private String id; @CreatedDate @Field(type = FieldType.Date, format = DateFormat.basic_date_time) private Instant created; @CreatedBy private String createdBy; @Override public boolean isNew() { return id == null || (createdBy == null && created == null); } }