1
ElasticON Global
Peter-Josef Meisch
Spring Data Elasticsearch Project Lead
2
This presentation and the accompanying oral presentation contain forward-looking statements, including statements
concerning plans for future offerings; the expected strength, performance or benefits of our offerings; and our future
operations and expected performance. These forward-looking statements are subject to the safe harbor provisions
under the Private Securities Litigation Reform Act of 1995. Our expectations and beliefs in light of currently
available information regarding these matters may not materialize. Actual outcomes and results may differ materially
from those contemplated by these forward-looking statements due to uncertainties, risks, and changes in
circumstances, including, but not limited to those related to: the impact of the COVID-19 pandemic on our business
and our customers and partners; our ability to continue to deliver and improve our offerings and successfully
develop new offerings, including security-related product offerings and SaaS offerings; customer acceptance and
purchase of our existing offerings and new offerings, including the expansion and adoption of our SaaS offerings;
our ability to realize value from investments in the business, including R&D investments; our ability to maintain and
expand our user and customer base; our international expansion strategy; our ability to successfully execute our
go-to-market strategy and expand in our existing markets and into new markets, and our ability to forecast customer
retention and expansion; and general market, political, economic and business conditions.
Additional risks and uncertainties that could cause actual outcomes and results to differ materially are included in
our filings with the Securities and Exchange Commission (the “SEC”), including our Annual Report on Form 10-K for
the most recent fiscal year, our quarterly report on Form 10-Q for the most recent fiscal quarter, and any
subsequent reports filed with the SEC. SEC filings are available on the Investor Relations section of Elastic’s
website at ir.elastic.co and the SEC’s website at www.sec.gov.
Any features or functions of services or products referenced in this presentation, or in any presentations, press
releases or public statements, which are not currently available or not currently available as a general availability
release, may not be delivered on time or at all. The development, release, and timing of any features or functionality
described for our products remains at our sole discretion. Customers who purchase our products and services
should make the purchase decisions based upon services and product features and functions that are currently
available.
All statements are made only as of the date of the presentation, and Elastic assumes no obligation to, and does not
currently intend to, update any forward-looking statements or statements relating to features or functions of services
or products, except as required by law.
Forward-Looking Statements
3
Nothing will stop you being creative more
effectively as the fear of making a mistake.
John Cleese
4
Next Level
Elasticsearch
Integration with Spring
Data Elasticsearch
What is Spring Data
Elasticsearch?
“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.”
Configure the connection
to Elasticsearch
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();
}
}
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();
}
}
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();
}
}
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();
}
}
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();
}
}
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();
Entity definition
Entity definition
public class Person {
@Id
private String id;
private String lastName;
private String firstName;
private LocalDate birthDate;
}
Entity definition
@Document(indexName = "person")
public class Person {
@Id
private String id;
private String lastName;
private String firstName;
private LocalDate birthDate;
}
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;
}
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;
}
ElasticsearchOperations
IndexOperations
● index creation and deletion
● index settings
● index mappings
● index templates
● alias management
● refresh operation
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);
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);
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);
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) ;
DocumentOperations
● save
● get
● delete
● exists
● update
SearchOperations
● count
● search
Query based operations
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);
StringQuery
Query query = new StringQuery( "{" +
" "bool": {" +
" "must": [" +
" {" +
" "match": {" +
" "lastName": "Smith"" +
" }" +
" }" +
" ]" +
" }" +
"}");
SearchHits<Person> searchHits = operations.search(query,
Person.class);
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);
Return types
SearchHit<T
● id
● index name
● the entity of type T
● score
● sort values
● highlight fields
● inner hits
SearchHits<T
● number of total hits
● total hits relation (eq, gte)
● list of SearchHit<T> objects
● max score
● aggregations
ElasticsearchRepository
Repository
interface PersonRepository extends
ElasticsearchRepository< Person, String > {
}
// ElasticsearchRepository
// +PagingAndSortingRepository
// + CrudRepository
// + Repository
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)
Repository methods
interface PersonRepository extends
ElasticsearchRepository< Person, String > {
List<Person> searchByFirstName(String name);
List<Person> findByFirstNameOrderByLastNameAsc(String name);
List<Person> queryByBirthDateBefore(LocalDate date);
}
Repository methods
interface PersonRepository extends
ElasticsearchRepository<Person, String> {
@Query(value = "{"fuzzy":{"lastName":"?0"}}")
List<Person> findByLastNameFuzzy(String lastName);
}
Repository method return types
interface PersonRepository extends
ElasticsearchRepository<Person, String> {
List<Person> searchByFirstName(String name);
}
Repository method return types
interface PersonRepository extends
ElasticsearchRepository<Person, String> {
Stream<Person> searchByFirstName(String name);
}
Repository method return types
interface PersonRepository extends
ElasticsearchRepository<Person, String> {
List<SearchHit<Person>> searchByFirstName(String name);
}
Repository method return types
interface PersonRepository extends
ElasticsearchRepository<Person, String> {
Stream<SearchHit<Person>> searchByFirstName(String name);
}
Repository method return types
interface PersonRepository extends
ElasticsearchRepository<Person, String> {
SearchHits<Person> searchByFirstName(String name);
}
Repository method return types
interface PersonRepository extends
ElasticsearchRepository<Person, String> {
SearchPage<Person> searchByFirstName(String name, Pageable page);
}
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) ;
}
}
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");
// ...
});
What else?
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;
}
}
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);
}
}
We need contributors!
Spring Data Elasticsearch is a
community-driven project
50
Thank You!
https://spring.io/projects/spring-data-elasticsearch
https://github.com/spring-projects/spring-data-elasticsearch
@sothawo
pj.meisch@sothawo.com

Next-level integration with Spring Data Elasticsearch

  • 1.
    1 ElasticON Global Peter-Josef Meisch SpringData Elasticsearch Project Lead
  • 2.
    2 This presentation andthe accompanying oral presentation contain forward-looking statements, including statements concerning plans for future offerings; the expected strength, performance or benefits of our offerings; and our future operations and expected performance. These forward-looking statements are subject to the safe harbor provisions under the Private Securities Litigation Reform Act of 1995. Our expectations and beliefs in light of currently available information regarding these matters may not materialize. Actual outcomes and results may differ materially from those contemplated by these forward-looking statements due to uncertainties, risks, and changes in circumstances, including, but not limited to those related to: the impact of the COVID-19 pandemic on our business and our customers and partners; our ability to continue to deliver and improve our offerings and successfully develop new offerings, including security-related product offerings and SaaS offerings; customer acceptance and purchase of our existing offerings and new offerings, including the expansion and adoption of our SaaS offerings; our ability to realize value from investments in the business, including R&D investments; our ability to maintain and expand our user and customer base; our international expansion strategy; our ability to successfully execute our go-to-market strategy and expand in our existing markets and into new markets, and our ability to forecast customer retention and expansion; and general market, political, economic and business conditions. Additional risks and uncertainties that could cause actual outcomes and results to differ materially are included in our filings with the Securities and Exchange Commission (the “SEC”), including our Annual Report on Form 10-K for the most recent fiscal year, our quarterly report on Form 10-Q for the most recent fiscal quarter, and any subsequent reports filed with the SEC. SEC filings are available on the Investor Relations section of Elastic’s website at ir.elastic.co and the SEC’s website at www.sec.gov. Any features or functions of services or products referenced in this presentation, or in any presentations, press releases or public statements, which are not currently available or not currently available as a general availability release, may not be delivered on time or at all. The development, release, and timing of any features or functionality described for our products remains at our sole discretion. Customers who purchase our products and services should make the purchase decisions based upon services and product features and functions that are currently available. All statements are made only as of the date of the presentation, and Elastic assumes no obligation to, and does not currently intend to, update any forward-looking statements or statements relating to features or functions of services or products, except as required by law. Forward-Looking Statements
  • 3.
    3 Nothing will stopyou being creative more effectively as the fear of making a mistake. John Cleese
  • 4.
  • 5.
    What is SpringData Elasticsearch?
  • 6.
    “Spring Data’s missionis to provide a familiar and consistent, Spring-based programming model for data access while still retaining the special traits of the underlying data store.”
  • 7.
  • 8.
    Configure the connectionto 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(); } }
  • 9.
    Configure the connectionto 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(); } }
  • 10.
    Configure the connectionto 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(); } }
  • 11.
    Configure the connectionto 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(); } }
  • 12.
    Configure the connectionto 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(); } }
  • 13.
    Configure the connectionto 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();
  • 14.
  • 15.
    Entity definition public classPerson { @Id private String id; private String lastName; private String firstName; private LocalDate birthDate; }
  • 16.
    Entity definition @Document(indexName ="person") public class Person { @Id private String id; private String lastName; private String firstName; private LocalDate birthDate; }
  • 17.
    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; }
  • 18.
    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; }
  • 19.
  • 20.
    IndexOperations ● index creationand deletion ● index settings ● index mappings ● index templates ● alias management ● refresh operation
  • 21.
    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);
  • 22.
    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);
  • 23.
    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);
  • 24.
    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) ;
  • 25.
    DocumentOperations ● save ● get ●delete ● exists ● update
  • 26.
  • 27.
    NativeSearchQuery import static org.elasticsearch.index.query.QueryBuilders.*; importstatic 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);
  • 28.
    StringQuery Query query =new StringQuery( "{" + " "bool": {" + " "must": [" + " {" + " "match": {" + " "lastName": "Smith"" + " }" + " }" + " ]" + " }" + "}"); SearchHits<Person> searchHits = operations.search(query, Person.class);
  • 29.
    CriteriaQuery Criteria criteria = newCriteria("lastName").is("Smith") .and("firstName").is("James"); Query query = new CriteriaQuery(criteria); SearchHits<Person> searchHits = operations.search(query, Person.class);
  • 30.
  • 31.
    SearchHit<T ● id ● indexname ● the entity of type T ● score ● sort values ● highlight fields ● inner hits
  • 32.
    SearchHits<T ● number oftotal hits ● total hits relation (eq, gte) ● list of SearchHit<T> objects ● max score ● aggregations
  • 33.
  • 34.
    Repository interface PersonRepository extends ElasticsearchRepository<Person, String > { } // ElasticsearchRepository // +PagingAndSortingRepository // + CrudRepository // + Repository
  • 35.
  • 36.
    Repository methods interface PersonRepositoryextends ElasticsearchRepository< Person, String > { List<Person> searchByFirstName(String name); List<Person> findByFirstNameOrderByLastNameAsc(String name); List<Person> queryByBirthDateBefore(LocalDate date); }
  • 37.
    Repository methods interface PersonRepositoryextends ElasticsearchRepository<Person, String> { @Query(value = "{"fuzzy":{"lastName":"?0"}}") List<Person> findByLastNameFuzzy(String lastName); }
  • 38.
    Repository method returntypes interface PersonRepository extends ElasticsearchRepository<Person, String> { List<Person> searchByFirstName(String name); }
  • 39.
    Repository method returntypes interface PersonRepository extends ElasticsearchRepository<Person, String> { Stream<Person> searchByFirstName(String name); }
  • 40.
    Repository method returntypes interface PersonRepository extends ElasticsearchRepository<Person, String> { List<SearchHit<Person>> searchByFirstName(String name); }
  • 41.
    Repository method returntypes interface PersonRepository extends ElasticsearchRepository<Person, String> { Stream<SearchHit<Person>> searchByFirstName(String name); }
  • 42.
    Repository method returntypes interface PersonRepository extends ElasticsearchRepository<Person, String> { SearchHits<Person> searchByFirstName(String name); }
  • 43.
    Repository method returntypes interface PersonRepository extends ElasticsearchRepository<Person, String> { SearchPage<Person> searchByFirstName(String name, Pageable page); }
  • 44.
    Repository usage @RestController @RequestMapping(”/persons”) publicclass 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) ; } }
  • 45.
    Repository method withhighlight 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"); // ... });
  • 46.
  • 47.
    Lifecycle events @Component public classPersonBeforeConvertCallback implements BeforeConvertCallback<Person> { @Override public Person onBeforeConvert(Person person, IndexCoordinates indexCoordinates) { if (person.getId() == null) { person.setId(UUID.randomUUID().toString()); } return person; } }
  • 48.
    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); } }
  • 49.
    We need contributors! SpringData Elasticsearch is a community-driven project
  • 50.