From 2bf08bf2008ca8f1325d1785bcc2e1878471b719 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Thu, 8 Aug 2019 14:36:17 +0200 Subject: [PATCH] #497 - Add Example for Elasticsearch High Level REST Client. --- README.md | 1 + elasticsearch/example/README.md | 4 +- elasticsearch/example/pom.xml | 2 +- elasticsearch/pom.xml | 5 +- elasticsearch/rest/.gitignore | 13 ++++ elasticsearch/rest/README.md | 53 +++++++++++++ elasticsearch/rest/pom.xml | 43 +++++++++++ .../conference/ApplicationConfiguration.java | 74 +++++++++++++++++++ .../elasticsearch/conference/Conference.java | 59 +++++++++++++++ .../conference/ConferenceRepository.java | 23 ++++++ .../src/main/resources/application.properties | 3 + .../ElasticsearchOperationsTest.java | 69 +++++++++++++++++ .../util/ElasticsearchAvailable.java | 70 ++++++++++++++++++ 13 files changed, 415 insertions(+), 4 deletions(-) create mode 100644 elasticsearch/rest/.gitignore create mode 100644 elasticsearch/rest/README.md create mode 100644 elasticsearch/rest/pom.xml create mode 100644 elasticsearch/rest/src/main/java/example/springdata/elasticsearch/conference/ApplicationConfiguration.java create mode 100644 elasticsearch/rest/src/main/java/example/springdata/elasticsearch/conference/Conference.java create mode 100644 elasticsearch/rest/src/main/java/example/springdata/elasticsearch/conference/ConferenceRepository.java create mode 100644 elasticsearch/rest/src/main/resources/application.properties create mode 100644 elasticsearch/rest/src/test/java/example/springdata/elasticsearch/conference/ElasticsearchOperationsTest.java create mode 100644 elasticsearch/rest/src/test/java/example/springdata/elasticsearch/util/ElasticsearchAvailable.java diff --git a/README.md b/README.md index 4e6294ec..8090c670 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ We have separate folders for the samples of individual modules: ## Spring Data Elasticsearch * `example` - Example how to use basic text search, geo-spatial search and facets. +* `rest` - Example how to use the High Level REST Client backing template and repository. * `reactive` - Example how to use reactive client, template and repository features. ## Spring Data Neo4j diff --git a/elasticsearch/example/README.md b/elasticsearch/example/README.md index 01b4c6ff..b898f615 100644 --- a/elasticsearch/example/README.md +++ b/elasticsearch/example/README.md @@ -1,5 +1,8 @@ # Spring Data Elasticsearch - Examples + +**NOTE**: Elastic recommends usage of the [High Level REST Client](https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-high.html). Please check out the [rest](https://github.com/spring-projects/spring-data-examples/tree/master/elasticsearch/rest) example. + Requirements: * [Maven](http://maven.apache.org/download.cgi) - required. @@ -11,4 +14,3 @@ To use local elasticsearch cluster: * install elasticsearch * uncomment both properties in file 'application.properties' - \ No newline at end of file diff --git a/elasticsearch/example/pom.xml b/elasticsearch/example/pom.xml index e4e3c457..de0c7ef6 100644 --- a/elasticsearch/example/pom.xml +++ b/elasticsearch/example/pom.xml @@ -6,7 +6,7 @@ org.springframework spring-data-elasticsearch-example - Spring Data Elasticsearch - Example + Spring Data Elasticsearch - Node Client Example Sample projects for Spring Data Elasticsearch https://github.com/spring-projects/spring-data-elasticsearch diff --git a/elasticsearch/pom.xml b/elasticsearch/pom.xml index 3dd6360b..38331df4 100644 --- a/elasticsearch/pom.xml +++ b/elasticsearch/pom.xml @@ -17,6 +17,7 @@ example + rest reactive @@ -31,13 +32,13 @@ spring-data-next-releasetrain - 6.6.1 + 6.8.2 spring-data-next-releasetrain-released - 6.6.1 + 6.8.2 diff --git a/elasticsearch/rest/.gitignore b/elasticsearch/rest/.gitignore new file mode 100644 index 00000000..e50bef9c --- /dev/null +++ b/elasticsearch/rest/.gitignore @@ -0,0 +1,13 @@ +.project +.classpath +.springBeans +.settings/ +target/ + +#IntelliJ Stuff +.idea +*.iml + +##ignore local node data files for unit tests +/data +/.DS_Store diff --git a/elasticsearch/rest/README.md b/elasticsearch/rest/README.md new file mode 100644 index 00000000..fb760a70 --- /dev/null +++ b/elasticsearch/rest/README.md @@ -0,0 +1,53 @@ +# Spring Data Elasticsearch - High Level REST Client Examples + +````java +class ApplicationConfiguration extends AbstractElasticsearchConfiguration { + + @Bean + @Override + public RestHighLevelClient elasticsearchClient() { + return RestClients.create(ClientConfiguration.localhost()).rest(); + } +} +```` + +The `RestHighLevelClient` can be used with the `ElasticsearchOperations` and `ElasticsearchRepository`. + +```java +@Autowired ElasticsearchOperations operations; + +// ... + +CriteriaQuery query = new CriteriaQuery("keywords").contains("java"); + +List result = operations.find(query, Conference.class); +``` + +```java +interface ConferenceRepository extends ElasticsearchRepository { + + List findAllByKeywordsContains(String keyword); +} + +// ... + +@Autowired ConferenceRepository repository; + +// ... + +List result = repository.findAllByKeywordsContains("java"); +``` + + +**Requirements:** + + * [Maven](http://maven.apache.org/download.cgi) + * [Elasticsearch](https://www.elastic.co/de/downloads/elasticsearch) + +**Running Elasticsearch** + +```bash +$ cd elasticsearch +$ ./bin/elasticsearch +``` + diff --git a/elasticsearch/rest/pom.xml b/elasticsearch/rest/pom.xml new file mode 100644 index 00000000..bf623974 --- /dev/null +++ b/elasticsearch/rest/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + org.springframework + spring-data-elasticsearch-rest-client-example + + Spring Data Elasticsearch - Rest Client Example + Sample projects for Spring Data Elasticsearch using the Rest High Level Client + https://github.com/spring-projects/spring-data-elasticsearch + + + org.springframework.data.examples + spring-data-elasticsearch-examples + 2.0.0.BUILD-SNAPSHOT + + + + + + org.springframework.boot + spring-boot-starter-data-elasticsearch + + + org.springframework.boot + spring-boot-starter-logging + + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + org.springframework + spring-web + + + + + diff --git a/elasticsearch/rest/src/main/java/example/springdata/elasticsearch/conference/ApplicationConfiguration.java b/elasticsearch/rest/src/main/java/example/springdata/elasticsearch/conference/ApplicationConfiguration.java new file mode 100644 index 00000000..f04017df --- /dev/null +++ b/elasticsearch/rest/src/main/java/example/springdata/elasticsearch/conference/ApplicationConfiguration.java @@ -0,0 +1,74 @@ +/* + * Copyright 2014-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example.springdata.elasticsearch.conference; + +import java.util.Arrays; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.elasticsearch.client.RestHighLevelClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.elasticsearch.client.ClientConfiguration; +import org.springframework.data.elasticsearch.client.RestClients; +import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration; +import org.springframework.data.elasticsearch.core.ElasticsearchOperations; +import org.springframework.data.elasticsearch.core.geo.GeoPoint; +import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; + +/** + * @author Artur Konczak + * @author Oliver Gierke + * @author Christoph Strobl + */ +@Configuration +@EnableElasticsearchRepositories +class ApplicationConfiguration extends AbstractElasticsearchConfiguration { + + @Override + public RestHighLevelClient elasticsearchClient() { + return RestClients.create(ClientConfiguration.localhost()).rest(); + } + + @Autowired ElasticsearchOperations elasticsearchOperations; + @Autowired ConferenceRepository repository; + + @PreDestroy + public void deleteIndex() { + elasticsearchOperations.deleteIndex(Conference.class); + } + + @PostConstruct + public void insertDataSample() { + + repository.deleteAll(); + elasticsearchOperations.refresh(Conference.class); + + // Save data sample + repository.save(Conference.builder().date("2014-11-06").name("Spring eXchange 2014 - London") + .keywords(Arrays.asList("java", "spring")).location(new GeoPoint(51.500152D, -0.126236D)).build()); + repository.save(Conference.builder().date("2014-12-07").name("Scala eXchange 2014 - London") + .keywords(Arrays.asList("scala", "play", "java")).location(new GeoPoint(51.500152D, -0.126236D)).build()); + repository.save(Conference.builder().date("2014-11-20").name("Elasticsearch 2014 - Berlin") + .keywords(Arrays.asList("java", "elasticsearch", "kibana")).location(new GeoPoint(52.5234051D, 13.4113999)) + .build()); + repository.save(Conference.builder().date("2014-11-12").name("AWS London 2014") + .keywords(Arrays.asList("cloud", "aws")).location(new GeoPoint(51.500152D, -0.126236D)).build()); + repository.save(Conference.builder().date("2014-10-04").name("JDD14 - Cracow") + .keywords(Arrays.asList("java", "spring")).location(new GeoPoint(50.0646501D, 19.9449799)).build()); + } +} diff --git a/elasticsearch/rest/src/main/java/example/springdata/elasticsearch/conference/Conference.java b/elasticsearch/rest/src/main/java/example/springdata/elasticsearch/conference/Conference.java new file mode 100644 index 00000000..21717490 --- /dev/null +++ b/elasticsearch/rest/src/main/java/example/springdata/elasticsearch/conference/Conference.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example.springdata.elasticsearch.conference; + +import static org.springframework.data.elasticsearch.annotations.FieldType.*; + +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.core.geo.GeoPoint; + +/** + * @author Artur Konczak + * @author Oliver Gierke + * @auhtor Christoph Strobl + */ +@Data +@Builder +@Document(indexName = "conference-index", type = "geo-class-point-type", shards = 1, replicas = 0, + refreshInterval = "-1") +public class Conference { + + private @Id String id; + private String name; + private @Field(type = Date) String date; + private GeoPoint location; + private List keywords; + + // do not remove it + public Conference() {} + + // do not remove it - work around for lombok generated constructor for all params + public Conference(String id, String name, String date, GeoPoint location, List keywords) { + + this.id = id; + this.name = name; + this.date = date; + this.location = location; + this.keywords = keywords; + } +} diff --git a/elasticsearch/rest/src/main/java/example/springdata/elasticsearch/conference/ConferenceRepository.java b/elasticsearch/rest/src/main/java/example/springdata/elasticsearch/conference/ConferenceRepository.java new file mode 100644 index 00000000..21deb357 --- /dev/null +++ b/elasticsearch/rest/src/main/java/example/springdata/elasticsearch/conference/ConferenceRepository.java @@ -0,0 +1,23 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example.springdata.elasticsearch.conference; + +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; + +/** + * @author Christoph Strobl + */ +interface ConferenceRepository extends ElasticsearchRepository {} diff --git a/elasticsearch/rest/src/main/resources/application.properties b/elasticsearch/rest/src/main/resources/application.properties new file mode 100644 index 00000000..1982f98a --- /dev/null +++ b/elasticsearch/rest/src/main/resources/application.properties @@ -0,0 +1,3 @@ +# Uncomment both entries to connect with local elasticsearch cluster +#spring.data.elasticsearch.clusterName=elasticsearch +#spring.data.elasticsearch.clusterNodes=localhost:9300 diff --git a/elasticsearch/rest/src/test/java/example/springdata/elasticsearch/conference/ElasticsearchOperationsTest.java b/elasticsearch/rest/src/test/java/example/springdata/elasticsearch/conference/ElasticsearchOperationsTest.java new file mode 100644 index 00000000..a6d45275 --- /dev/null +++ b/elasticsearch/rest/src/test/java/example/springdata/elasticsearch/conference/ElasticsearchOperationsTest.java @@ -0,0 +1,69 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example.springdata.elasticsearch.conference; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import example.springdata.elasticsearch.util.ElasticsearchAvailable; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.List; + +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.elasticsearch.core.ElasticsearchOperations; +import org.springframework.data.elasticsearch.core.query.Criteria; +import org.springframework.data.elasticsearch.core.query.CriteriaQuery; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Test case to show Spring Data Elasticsearch functionality. + * + * @author Christoph Strobl + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ApplicationConfiguration.class) +public class ElasticsearchOperationsTest { + + public static @ClassRule ElasticsearchAvailable elasticsearchAvailable = ElasticsearchAvailable.onLocalhost(); + + private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + + @Autowired ElasticsearchOperations operations; + + @Test + public void textSearch() throws ParseException { + + String expectedDate = "2014-10-29"; + String expectedWord = "java"; + CriteriaQuery query = new CriteriaQuery( + new Criteria("keywords").contains(expectedWord).and(new Criteria("date").greaterThanEqual(expectedDate))); + + List result = operations.queryForList(query, Conference.class); + + assertThat(result, hasSize(3)); + + for (Conference conference : result) { + assertThat(conference.getKeywords(), hasItem(expectedWord)); + assertThat(format.parse(conference.getDate()), greaterThan(format.parse(expectedDate))); + } + } +} diff --git a/elasticsearch/rest/src/test/java/example/springdata/elasticsearch/util/ElasticsearchAvailable.java b/elasticsearch/rest/src/test/java/example/springdata/elasticsearch/util/ElasticsearchAvailable.java new file mode 100644 index 00000000..fc1375b8 --- /dev/null +++ b/elasticsearch/rest/src/test/java/example/springdata/elasticsearch/util/ElasticsearchAvailable.java @@ -0,0 +1,70 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example.springdata.elasticsearch.util; + +import java.io.IOException; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpHead; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.assertj.core.api.Assumptions; +import org.junit.AssumptionViolatedException; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * @author Christoph Strobl + */ +public class ElasticsearchAvailable implements TestRule { + + private final String url; + + private ElasticsearchAvailable(String url) { + this.url = url; + } + + public static ElasticsearchAvailable onLocalhost() { + return new ElasticsearchAvailable("http://localhost:9200"); + } + + @Override + public Statement apply(Statement base, Description description) { + + return new Statement() { + + @Override + public void evaluate() throws Throwable { + + checkServerRunning(); + base.evaluate(); + } + }; + } + + private void checkServerRunning() { + + try (CloseableHttpClient client = HttpClientBuilder.create().build()) { + CloseableHttpResponse response = client.execute(new HttpHead(url)); + if (response != null && response.getStatusLine() != null) { + Assumptions.assumeThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + } + } catch (IOException e) { + throw new AssumptionViolatedException(String.format("Elasticsearch Server seems to be down. %s", e.getMessage())); + } + } +}