mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-24 04:52:12 +00:00
parent
b4ebca7ab5
commit
d864ff1292
@ -362,16 +362,19 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate
|
||||
|
||||
@Override
|
||||
public <T> T queryForObject(CriteriaQuery query, Class<T> clazz) {
|
||||
Page<T> page = queryForPage(query, clazz);
|
||||
Assert.isTrue(page.getTotalElements() < 2, "Expected 1 but found " + page.getTotalElements() + " results");
|
||||
return page.getTotalElements() > 0 ? page.getContent().get(0) : null;
|
||||
return getObjectFromPage(queryForPage(query, clazz));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T queryForObject(StringQuery query, Class<T> clazz) {
|
||||
Page<T> page = queryForPage(query, clazz);
|
||||
Assert.isTrue(page.getTotalElements() < 2, "Expected 1 but found " + page.getTotalElements() + " results");
|
||||
return page.getTotalElements() > 0 ? page.getContent().get(0) : null;
|
||||
return getObjectFromPage(queryForPage(query, clazz));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T> T getObjectFromPage(Page<T> page) {
|
||||
int contentSize = page.getContent().size();
|
||||
Assert.isTrue(contentSize < 2, "Expected 1 but found " + contentSize + " results");
|
||||
return contentSize > 0 ? page.getContent().get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -492,19 +495,24 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate
|
||||
QueryBuilder elasticsearchFilter = new CriteriaFilterProcessor()
|
||||
.createFilterFromCriteria(criteriaQuery.getCriteria());
|
||||
SearchRequest request = prepareSearch(criteriaQuery, clazz);
|
||||
SearchSourceBuilder sourceBuilder = request.source();
|
||||
|
||||
if (elasticsearchQuery != null) {
|
||||
request.source().query(elasticsearchQuery);
|
||||
sourceBuilder.query(elasticsearchQuery);
|
||||
} else {
|
||||
request.source().query(QueryBuilders.matchAllQuery());
|
||||
sourceBuilder.query(QueryBuilders.matchAllQuery());
|
||||
}
|
||||
|
||||
if (criteriaQuery.isLimiting()) {
|
||||
sourceBuilder.size(criteriaQuery.getMaxResults());
|
||||
}
|
||||
|
||||
if (criteriaQuery.getMinScore() > 0) {
|
||||
request.source().minScore(criteriaQuery.getMinScore());
|
||||
sourceBuilder.minScore(criteriaQuery.getMinScore());
|
||||
}
|
||||
|
||||
if (elasticsearchFilter != null)
|
||||
request.source().postFilter(elasticsearchFilter);
|
||||
sourceBuilder.postFilter(elasticsearchFilter);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("doSearch query:\n" + request.toString());
|
||||
}
|
||||
|
@ -294,16 +294,19 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate impleme
|
||||
|
||||
@Override
|
||||
public <T> T queryForObject(CriteriaQuery query, Class<T> clazz) {
|
||||
Page<T> page = queryForPage(query, clazz);
|
||||
Assert.isTrue(page.getTotalElements() < 2, "Expected 1 but found " + page.getTotalElements() + " results");
|
||||
return page.getTotalElements() > 0 ? page.getContent().get(0) : null;
|
||||
return getObjectFromPage(queryForPage(query, clazz));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T queryForObject(StringQuery query, Class<T> clazz) {
|
||||
Page<T> page = queryForPage(query, clazz);
|
||||
Assert.isTrue(page.getTotalElements() < 2, "Expected 1 but found " + page.getTotalElements() + " results");
|
||||
return page.getTotalElements() > 0 ? page.getContent().get(0) : null;
|
||||
return getObjectFromPage(queryForPage(query, clazz));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T> T getObjectFromPage(Page<T> page) {
|
||||
int contentSize = page.getContent().size();
|
||||
Assert.isTrue(contentSize < 2, "Expected 1 but found " + contentSize + " results");
|
||||
return contentSize > 0 ? page.getContent().get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -423,6 +426,10 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate impleme
|
||||
searchRequestBuilder.setQuery(QueryBuilders.matchAllQuery());
|
||||
}
|
||||
|
||||
if (criteriaQuery.isLimiting()) {
|
||||
searchRequestBuilder.setSize(criteriaQuery.getMaxResults());
|
||||
}
|
||||
|
||||
if (criteriaQuery.getMinScore() > 0) {
|
||||
searchRequestBuilder.setMinScore(criteriaQuery.getMinScore());
|
||||
}
|
||||
|
@ -294,7 +294,12 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
||||
|
||||
request.source(searchSourceBuilder);
|
||||
return doFind(prepareSearchRequest(request));
|
||||
} else if (query.isLimiting()) {
|
||||
searchSourceBuilder.from(0);
|
||||
searchSourceBuilder.size(query.getMaxResults());
|
||||
|
||||
request.source(searchSourceBuilder);
|
||||
return doFind(prepareSearchRequest(request));
|
||||
} else {
|
||||
|
||||
request.source(searchSourceBuilder);
|
||||
@ -657,9 +662,7 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
||||
elasticsearchQuery = new WrapperQueryBuilder(((StringQuery) query).getSource());
|
||||
} else if (query instanceof NativeSearchQuery) {
|
||||
elasticsearchQuery = ((NativeSearchQuery) query).getQuery();
|
||||
}
|
||||
|
||||
else {
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("Unknown query type '%s'.", query.getClass()));
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ import org.springframework.util.Assert;
|
||||
* @author Alen Turkovic
|
||||
* @author Sascha Woo
|
||||
* @author Farid Azaza
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
abstract class AbstractQuery implements Query {
|
||||
|
||||
@ -52,6 +53,7 @@ abstract class AbstractQuery implements Query {
|
||||
protected IndicesOptions indicesOptions;
|
||||
protected boolean trackScores;
|
||||
protected String preference;
|
||||
protected Integer maxResults;
|
||||
|
||||
@Override
|
||||
public Sort getSort() {
|
||||
@ -112,6 +114,7 @@ abstract class AbstractQuery implements Query {
|
||||
return sourceFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T extends Query> T addSort(Sort sort) {
|
||||
if (sort == null) {
|
||||
@ -127,6 +130,7 @@ abstract class AbstractQuery implements Query {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinScore() {
|
||||
return minScore;
|
||||
}
|
||||
@ -135,6 +139,7 @@ abstract class AbstractQuery implements Query {
|
||||
this.minScore = minScore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getIds() {
|
||||
return ids;
|
||||
}
|
||||
@ -143,6 +148,7 @@ abstract class AbstractQuery implements Query {
|
||||
this.ids = ids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRoute() {
|
||||
return route;
|
||||
}
|
||||
@ -155,10 +161,12 @@ abstract class AbstractQuery implements Query {
|
||||
this.searchType = searchType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchType getSearchType() {
|
||||
return searchType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndicesOptions getIndicesOptions() {
|
||||
return indicesOptions;
|
||||
}
|
||||
@ -178,7 +186,7 @@ abstract class AbstractQuery implements Query {
|
||||
|
||||
/**
|
||||
* Configures whether to track scores.
|
||||
*
|
||||
*
|
||||
* @param trackScores
|
||||
* @since 3.1
|
||||
*/
|
||||
@ -195,4 +203,18 @@ abstract class AbstractQuery implements Query {
|
||||
public void setPreference(String preference) {
|
||||
this.preference = preference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLimiting() {
|
||||
return maxResults != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxResults() {
|
||||
return maxResults;
|
||||
}
|
||||
|
||||
public void setMaxResults(Integer maxResults) {
|
||||
this.maxResults = maxResults;
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import org.springframework.data.domain.Sort;
|
||||
* @author Sascha Woo
|
||||
* @author Christoph Strobl
|
||||
* @author Farid Azaza
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
public interface Query {
|
||||
|
||||
@ -145,7 +146,7 @@ public interface Query {
|
||||
|
||||
/**
|
||||
* Get if scores will be computed and tracked, regardless of whether sorting on a field. Defaults to <tt>false</tt>.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @since 3.1
|
||||
*/
|
||||
@ -194,4 +195,22 @@ public interface Query {
|
||||
* @since 3.2
|
||||
*/
|
||||
void setPreference(String preference);
|
||||
|
||||
/**
|
||||
* @return true if the query has a limit on the max number of results.
|
||||
* @since 4.0
|
||||
*/
|
||||
default boolean isLimiting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the max of results. Must not return null when {@link #isLimiting()} returns true.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
default Integer getMaxResults() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -58,6 +58,10 @@ public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery
|
||||
CriteriaQuery query = createQuery(accessor);
|
||||
Assert.notNull(query, "unsupported query");
|
||||
|
||||
if (tree.isLimiting()) {
|
||||
query.setMaxResults(tree.getMaxResults());
|
||||
}
|
||||
|
||||
if (tree.isDelete()) {
|
||||
Object result = countOrGetDocumentsForDelete(query, accessor);
|
||||
elasticsearchOperations.delete(query, queryMethod.getEntityInformation().getJavaType());
|
||||
|
@ -16,6 +16,7 @@
|
||||
package org.springframework.data.elasticsearch.repository.query;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator;
|
||||
import org.springframework.data.repository.query.ResultProcessor;
|
||||
@ -23,6 +24,7 @@ import org.springframework.data.repository.query.parser.PartTree;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 3.2
|
||||
*/
|
||||
public class ReactivePartTreeElasticsearchQuery extends AbstractReactiveElasticsearchRepositoryQuery {
|
||||
@ -40,7 +42,12 @@ public class ReactivePartTreeElasticsearchQuery extends AbstractReactiveElastics
|
||||
|
||||
@Override
|
||||
protected Query createQuery(ElasticsearchParameterAccessor accessor) {
|
||||
return new ElasticsearchQueryCreator(tree, accessor, getMappingContext()).createQuery();
|
||||
CriteriaQuery query = new ElasticsearchQueryCreator(tree, accessor, getMappingContext()).createQuery();
|
||||
|
||||
if (tree.isLimiting()) {
|
||||
query.setMaxResults(tree.getMaxResults());
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,7 +88,6 @@ public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuer
|
||||
protected CriteriaQuery complete(@Nullable CriteriaQuery query, Sort sort) {
|
||||
|
||||
if (query == null) {
|
||||
|
||||
// this is the case in a findAllByOrderByField method, add empty criteria
|
||||
query = new CriteriaQuery(new Criteria());
|
||||
}
|
||||
|
@ -61,15 +61,15 @@ abstract class QueryKeywordsTests {
|
||||
|
||||
IndexInitializer.init(elasticsearchTemplate, Product.class);
|
||||
|
||||
Product product1 = Product.builder().id("1").name("Sugar").text("Cane sugar").price(1.0f).available(false)
|
||||
Product product1 = Product.builder().id("1").name("Sugar").text("Cane sugar").price(1.0f).available(false)
|
||||
.sortName("sort5").build();
|
||||
Product product2 = Product.builder().id("2").name("Sugar").text("Cane sugar").price(1.2f).available(true)
|
||||
Product product2 = Product.builder().id("2").name("Sugar").text("Cane sugar").price(1.2f).available(true)
|
||||
.sortName("sort4").build();
|
||||
Product product3 = Product.builder().id("3").name("Sugar").text("Beet sugar").price(1.1f).available(true)
|
||||
Product product3 = Product.builder().id("3").name("Sugar").text("Beet sugar").price(1.1f).available(true)
|
||||
.sortName("sort3").build();
|
||||
Product product4 = Product.builder().id("4").name("Salt").text("Rock salt").price(1.9f).available(true)
|
||||
Product product4 = Product.builder().id("4").name("Salt").text("Rock salt").price(1.9f).available(true)
|
||||
.sortName("sort2").build();
|
||||
Product product5 = Product.builder().id("5").name("Salt").text("Sea salt").price(2.1f).available(false)
|
||||
Product product5 = Product.builder().id("5").name("Salt").text("Sea salt").price(2.1f).available(false)
|
||||
.sortName("sort1").build();
|
||||
|
||||
repository.saveAll(Arrays.asList(product1, product2, product3, product4, product5));
|
||||
@ -165,7 +165,7 @@ abstract class QueryKeywordsTests {
|
||||
|
||||
@Test // DATAES-615
|
||||
public void shouldSupportSortOnStandardFieldWithCriteria() {
|
||||
List<String> sortedIds = repository.findAllByNameOrderByText("Salt").stream() //
|
||||
List<String> sortedIds = repository.findAllByNameOrderByText("Salt").stream() //
|
||||
.map(it -> it.id).collect(Collectors.toList());
|
||||
|
||||
assertThat(sortedIds).containsExactly("4", "5");
|
||||
@ -174,7 +174,7 @@ abstract class QueryKeywordsTests {
|
||||
@Test // DATAES-615
|
||||
public void shouldSupportSortOnFieldWithCustomFieldNameWithCriteria() {
|
||||
|
||||
List<String> sortedIds = repository.findAllByNameOrderBySortName("Sugar").stream() //
|
||||
List<String> sortedIds = repository.findAllByNameOrderBySortName("Sugar").stream() //
|
||||
.map(it -> it.id).collect(Collectors.toList());
|
||||
|
||||
assertThat(sortedIds).containsExactly("3", "2", "1");
|
||||
@ -182,7 +182,7 @@ abstract class QueryKeywordsTests {
|
||||
|
||||
@Test // DATAES-615
|
||||
public void shouldSupportSortOnStandardFieldWithoutCriteria() {
|
||||
List<String> sortedIds = repository.findAllByOrderByText().stream() //
|
||||
List<String> sortedIds = repository.findAllByOrderByText().stream() //
|
||||
.map(it -> it.text).collect(Collectors.toList());
|
||||
|
||||
assertThat(sortedIds).containsExactly("Beet sugar", "Cane sugar", "Cane sugar", "Rock salt", "Sea salt");
|
||||
@ -191,12 +191,46 @@ abstract class QueryKeywordsTests {
|
||||
@Test // DATAES-615
|
||||
public void shouldSupportSortOnFieldWithCustomFieldNameWithoutCriteria() {
|
||||
|
||||
List<String> sortedIds = repository.findAllByOrderBySortName().stream() //
|
||||
List<String> sortedIds = repository.findAllByOrderBySortName().stream() //
|
||||
.map(it -> it.id).collect(Collectors.toList());
|
||||
|
||||
assertThat(sortedIds).containsExactly("5", "4", "3", "2", "1");
|
||||
}
|
||||
|
||||
@Test // DATAES-178
|
||||
public void shouldReturnOneWithFindFirst() {
|
||||
|
||||
Product product = repository.findFirstByName("Sugar");
|
||||
|
||||
assertThat(product.name).isEqualTo("Sugar");
|
||||
}
|
||||
|
||||
@Test // DATAES-178
|
||||
public void shouldReturnOneWithFindTop() {
|
||||
|
||||
Product product = repository.findTopByName("Sugar");
|
||||
|
||||
assertThat(product.name).isEqualTo("Sugar");
|
||||
}
|
||||
|
||||
@Test // DATAES-178
|
||||
public void shouldReturnTwoWithFindFirst2() {
|
||||
|
||||
List<Product> products = repository.findFirst2ByName("Sugar");
|
||||
|
||||
assertThat(products).hasSize(2);
|
||||
products.forEach(product -> assertThat(product.name).isEqualTo("Sugar"));
|
||||
}
|
||||
|
||||
@Test // DATAES-178
|
||||
public void shouldReturnTwoWithFindTop2() {
|
||||
|
||||
List<Product> products = repository.findTop2ByName("Sugar");
|
||||
|
||||
assertThat(products).hasSize(2);
|
||||
products.forEach(product -> assertThat(product.name).isEqualTo("Sugar"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
@ -279,6 +313,14 @@ abstract class QueryKeywordsTests {
|
||||
List<Product> findAllByOrderByText();
|
||||
|
||||
List<Product> findAllByOrderBySortName();
|
||||
|
||||
Product findFirstByName(String name);
|
||||
|
||||
Product findTopByName(String name);
|
||||
|
||||
List<Product> findFirst2ByName(String name);
|
||||
|
||||
List<Product> findTop2ByName(String name);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user