Add test cases with different query types

This commit is contained in:
Dmitry Zinkevich 2016-02-23 12:44:13 +03:00
parent f1d304ce81
commit 8c90c74483
4 changed files with 248 additions and 31 deletions

View File

@ -1,5 +1,6 @@
package com.baeldung.spring.data.es.config; package com.baeldung.spring.data.es.config;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.node.NodeBuilder; import org.elasticsearch.node.NodeBuilder;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -17,20 +18,14 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
@Configuration @Configuration
@EnableElasticsearchRepositories(basePackages = "com.baeldung.repository") @EnableElasticsearchRepositories(basePackages = "com.baeldung.spring.data.es.repository")
@ComponentScan(basePackages = {"com.baeldung.spring.data.es.service"}) @ComponentScan(basePackages = {"com.baeldung.spring.data.es.service"})
public class Config { public class Config {
private static Logger logger = LoggerFactory.getLogger(Config.class); private static Logger logger = LoggerFactory.getLogger(Config.class);
@Bean @Bean
public NodeBuilder nodeBuilder() { public Client client() {
return new NodeBuilder();
}
@Bean
public ElasticsearchOperations elasticsearchTemplate() {
try { try {
Path tmpDir = Files.createTempDirectory(Paths.get(System.getProperty("java.io.tmpdir")), "elasticsearch_data"); Path tmpDir = Files.createTempDirectory(Paths.get(System.getProperty("java.io.tmpdir")), "elasticsearch_data");
@ -40,14 +35,19 @@ public class Config {
logger.debug(tmpDir.toAbsolutePath().toString()); logger.debug(tmpDir.toAbsolutePath().toString());
return new ElasticsearchTemplate(nodeBuilder() return new NodeBuilder()
.local(true) .local(true)
.settings(elasticsearchSettings.build()) .settings(elasticsearchSettings.build())
.node() .node()
.client()); .client();
} catch (IOException ioex) { } catch (IOException ioex) {
logger.error("Cannot create temp dir", ioex); logger.error("Cannot create temp dir", ioex);
throw new RuntimeException(); throw new RuntimeException();
} }
} }
@Bean
public ElasticsearchOperations elasticsearchTemplate() {
return new ElasticsearchTemplate(client());
}
} }

View File

@ -1,15 +0,0 @@
package com.baeldung.spring.data.es.dao;
import com.baeldung.spring.data.es.model.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface ArticleRepository extends ElasticsearchRepository<Article, String> {
Page<Article> findByAuthorsName(String name, Pageable pageable);
@Query("{\"bool\": {\"must\": [{\"match\": {\"authors.name\": \"?0\"}}]}}")
Page<Article> findByAuthorsNameUsingCustomQuery(String name, Pageable pageable);
}

View File

@ -1,23 +1,35 @@
package com.baeldung.spring.data.es.model; package com.baeldung.spring.data.es.model;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.*;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldIndex;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.util.Arrays;
import java.util.List; import java.util.List;
import static org.springframework.data.elasticsearch.annotations.FieldIndex.not_analyzed;
import static org.springframework.data.elasticsearch.annotations.FieldType.Nested;
import static org.springframework.data.elasticsearch.annotations.FieldType.String;
@Document(indexName = "blog", type = "article") @Document(indexName = "blog", type = "article")
public class Article { public class Article {
@Id @Id
private String id; private String id;
@Field(type = FieldType.String, index = FieldIndex.not_analyzed)
@MultiField(
mainField = @Field(type = String),
otherFields = {
@NestedField(index = not_analyzed, dotSuffix = "verbatim", type = String)
}
)
private String title; private String title;
@Field(type = FieldType.Nested)
@Field(type = Nested)
private List<Author> authors; private List<Author> authors;
@Field(type = String, index = not_analyzed)
private String[] tags;
public Article() { public Article() {
} }
@ -49,12 +61,21 @@ public class Article {
this.authors = authors; this.authors = authors;
} }
public String[] getTags() {
return tags;
}
public void setTags(String... tags) {
this.tags = tags;
}
@Override @Override
public String toString() { public String toString() {
return "Article{" + return "Article{" +
"id='" + id + '\'' + "id='" + id + '\'' +
", title='" + title + '\'' + ", title='" + title + '\'' +
", authors=" + authors + ", authors=" + authors +
", tags=" + Arrays.toString(tags) +
'}'; '}';
} }
} }

View File

@ -0,0 +1,211 @@
package com.baeldung.spring.data.es;
import com.baeldung.spring.data.es.config.Config;
import com.baeldung.spring.data.es.model.Article;
import com.baeldung.spring.data.es.model.Author;
import com.baeldung.spring.data.es.service.ArticleService;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static org.elasticsearch.index.query.MatchQueryBuilder.Operator.AND;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.junit.Assert.assertEquals;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {Config.class}, loader = AnnotationConfigContextLoader.class)
public class ElasticSearchQueryTest {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Autowired
private ArticleService articleService;
@Autowired
private Client client;
private final Author johnSmith = new Author("John Smith");
private final Author johnDoe = new Author("John Doe");
@Before
public void before() {
elasticsearchTemplate.deleteIndex(Article.class);
elasticsearchTemplate.createIndex(Article.class);
elasticsearchTemplate.putMapping(Article.class);
elasticsearchTemplate.refresh(Article.class, true);
Article article = new Article("Spring Data Elasticsearch");
article.setAuthors(asList(johnSmith, johnDoe));
article.setTags("elasticsearch", "spring data");
articleService.save(article);
article = new Article("Search engines");
article.setAuthors(asList(johnDoe));
article.setTags("search engines", "tutorial");
articleService.save(article);
article = new Article("Second Article About Elasticsearch");
article.setAuthors(asList(johnSmith));
article.setTags("elasticsearch", "spring data");
articleService.save(article);
article = new Article("Elasticsearch Tutorial");
article.setAuthors(asList(johnDoe));
article.setTags("elasticsearch");
articleService.save(article);
}
@Test
public void givenFullTitle_whenRunMatchQuery_thenDocIsFound() {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", "Search engines").operator(AND))
.build();
List<Article> articles = elasticsearchTemplate
.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
}
@Test
public void givenOneTermFromTitle_whenRunMatchQuery_thenDocIsFound() {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", "Engines Solutions"))
.build();
List<Article> articles = elasticsearchTemplate
.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
assertEquals("Search engines", articles.get(0).getTitle());
}
@Test
public void givenPartTitle_whenRunMatchQuery_thenDocIsFound() {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", "elasticsearch data"))
.build();
List<Article> articles = elasticsearchTemplate
.queryForList(searchQuery, Article.class);
assertEquals(3, articles.size());
}
@Test
public void givenFullTitle_whenRunMatchQueryOnVerbatimField_thenDocIsFound() {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title.verbatim", "Second Article About Elasticsearch"))
.build();
List<Article> articles = elasticsearchTemplate
.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title.verbatim", "Second Article About"))
.build();
articles = elasticsearchTemplate
.queryForList(searchQuery, Article.class);
assertEquals(0, articles.size());
}
@Test
public void givenNestedObject_whenQueryByAuthorsName_thenFoundArticlesByThatAuthor() {
QueryBuilder builder = nestedQuery("authors",
boolQuery().must(termQuery("authors.name", "smith")));
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder).build();
List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(2, articles.size());
}
@Test
public void givenAnalyzedQuery_whenMakeAggregationOnTermCount_thenEachTokenCountsSeparately() {
TermsBuilder aggregation = AggregationBuilders.terms("top_tags").field("title");
SearchResponse response = client.prepareSearch("blog").setTypes("article")
.addAggregation(aggregation).execute().actionGet();
Map<String, Aggregation> results = response.getAggregations().asMap();
StringTerms topTags = (StringTerms) results.get("top_tags");
List<String> keys = topTags.getBuckets().stream().map(b -> b.getKey()).collect(toList());
Collections.sort(keys);
assertEquals(asList("about", "article", "data", "elasticsearch",
"engines", "search", "second", "spring", "tutorial"), keys);
}
@Test
public void givenNotAnalyzedQuery_whenMakeAggregationOnTermCount_thenEachTermCountsIndividually() {
TermsBuilder aggregation = AggregationBuilders.terms("top_tags").field("tags")
.order(Terms.Order.aggregation("_count", false));
SearchResponse response = client.prepareSearch("blog").setTypes("article")
.addAggregation(aggregation).execute().actionGet();
Map<String, Aggregation> results = response.getAggregations().asMap();
StringTerms topTags = (StringTerms) results.get("top_tags");
List<String> keys = topTags.getBuckets().stream().map(b -> b.getKey()).collect(toList());
assertEquals(asList("elasticsearch", "spring data", "search engines", "tutorial"), keys);
}
@Test
public void givenNotExactPhrase_whenUseSlop_thenQueryMatches() {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchPhraseQuery("title", "spring elasticsearch").slop(1))
.build();
List<Article> articles = elasticsearchTemplate
.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
}
@Test
public void givenPhraseWithType_whenUseFuzziness_thenQueryMatches() {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", "spring date elasticserch")
.operator(AND)
.fuzziness(Fuzziness.ONE)
.prefixLength(3))
.build();
List<Article> articles = elasticsearchTemplate
.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
}
@Test
public void givenMultimatchQuery_whenDoSearch_thenAllProvidedFieldsMatch() {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(multiMatchQuery("tutorial")
.field("title")
.field("tags")
.type(MultiMatchQueryBuilder.Type.BEST_FIELDS))
.build();
List<Article> articles = elasticsearchTemplate
.queryForList(searchQuery, Article.class);
assertEquals(2, articles.size());
}
}