mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-07-12 21:33:27 +00:00
DATAES-749 - Introduce SearchPage as return type for repository methods.
Original PR: #397
This commit is contained in:
parent
dc795eb7ee
commit
6a4a7483aa
@ -21,9 +21,12 @@ import java.util.List;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.springframework.data.domain.PageImpl;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
|
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
|
||||||
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
|
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
|
||||||
|
import org.springframework.data.elasticsearch.support.ReactiveSupport;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class with helper methods for working with {@link SearchHit}.
|
* Utility class with helper methods for working with {@link SearchHit}.
|
||||||
@ -75,9 +78,12 @@ public final class SearchHitSupport {
|
|||||||
return unwrapSearchHits(searchHits.getSearchHits());
|
return unwrapSearchHits(searchHits.getSearchHits());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result instanceof Flux) {
|
if (ReactiveSupport.isReactorAvailable()) {
|
||||||
Flux<?> flux = (Flux<?>) result;
|
|
||||||
return flux.map(SearchHitSupport::unwrapSearchHits);
|
if (result instanceof Flux) {
|
||||||
|
Flux<?> flux = (Flux<?>) result;
|
||||||
|
return flux.map(SearchHitSupport::unwrapSearchHits);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -94,4 +100,28 @@ public final class SearchHitSupport {
|
|||||||
return new AggregatedPageImpl<>(searchHits.getSearchHits(), pageable, searchHits.getTotalHits(),
|
return new AggregatedPageImpl<>(searchHits.getSearchHits(), pageable, searchHits.getTotalHits(),
|
||||||
searchHits.getAggregations(), searchHits.getScrollId(), searchHits.getMaxScore());
|
searchHits.getAggregations(), searchHits.getScrollId(), searchHits.getMaxScore());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> SearchPage<T> searchPageFor(SearchHits<T> searchHits, @Nullable Pageable pageable) {
|
||||||
|
return new SearchPageImpl<>(searchHits, (pageable != null) ? pageable : Pageable.unpaged());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SearchPage implementation.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
|
static class SearchPageImpl<T> extends PageImpl<SearchHit<T>> implements SearchPage<T> {
|
||||||
|
|
||||||
|
private final SearchHits<T> searchHits;
|
||||||
|
|
||||||
|
public SearchPageImpl(SearchHits<T> searchHits, Pageable pageable) {
|
||||||
|
super(searchHits.getSearchHits(), pageable, searchHits.getTotalHits());
|
||||||
|
this.searchHits = searchHits;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SearchHits<T> getSearchHits() {
|
||||||
|
return searchHits;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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 org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page definition for repositories that need to return a paged SearchHits.
|
||||||
|
*
|
||||||
|
* @author Peter-Josef Meisch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public interface SearchPage<T> extends Page<SearchHit<T>> {
|
||||||
|
SearchHits<T> getSearchHits();
|
||||||
|
}
|
@ -86,7 +86,11 @@ public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery
|
|||||||
} else if (queryMethod.isPageQuery()) {
|
} else if (queryMethod.isPageQuery()) {
|
||||||
query.setPageable(accessor.getPageable());
|
query.setPageable(accessor.getPageable());
|
||||||
SearchHits<?> searchHits = elasticsearchOperations.search(query, clazz, index);
|
SearchHits<?> searchHits = elasticsearchOperations.search(query, clazz, index);
|
||||||
result = SearchHitSupport.page(searchHits, query.getPageable());
|
if (queryMethod.isSearchPageMethod()) {
|
||||||
|
result = SearchHitSupport.searchPageFor(searchHits, query.getPageable());
|
||||||
|
} else {
|
||||||
|
result = SearchHitSupport.page(searchHits, query.getPageable());
|
||||||
|
}
|
||||||
} else if (queryMethod.isStreamQuery()) {
|
} else if (queryMethod.isStreamQuery()) {
|
||||||
if (accessor.getPageable().isUnpaged()) {
|
if (accessor.getPageable().isUnpaged()) {
|
||||||
query.setPageable(PageRequest.of(0, DEFAULT_STREAM_BATCH_SIZE));
|
query.setPageable(PageRequest.of(0, DEFAULT_STREAM_BATCH_SIZE));
|
||||||
|
@ -25,6 +25,7 @@ import org.springframework.data.elasticsearch.annotations.Highlight;
|
|||||||
import org.springframework.data.elasticsearch.annotations.Query;
|
import org.springframework.data.elasticsearch.annotations.Query;
|
||||||
import org.springframework.data.elasticsearch.core.SearchHit;
|
import org.springframework.data.elasticsearch.core.SearchHit;
|
||||||
import org.springframework.data.elasticsearch.core.SearchHits;
|
import org.springframework.data.elasticsearch.core.SearchHits;
|
||||||
|
import org.springframework.data.elasticsearch.core.SearchPage;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||||
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
|
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
|
||||||
@ -171,6 +172,25 @@ public class ElasticsearchQueryMethod extends QueryMethod {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if the return type is {@link SearchPage}.
|
||||||
|
*
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public boolean isSearchPageMethod() {
|
||||||
|
return SearchPage.class.isAssignableFrom(methodReturnType());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retusn the declared return type for this method.
|
||||||
|
*
|
||||||
|
* @return the return type
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public Class<?> methodReturnType() {
|
||||||
|
return method.getReturnType();
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean isAllowedGenericType(ParameterizedType methodGenericReturnType) {
|
protected boolean isAllowedGenericType(ParameterizedType methodGenericReturnType) {
|
||||||
return Collection.class.isAssignableFrom((Class<?>) methodGenericReturnType.getRawType())
|
return Collection.class.isAssignableFrom((Class<?>) methodGenericReturnType.getRawType())
|
||||||
|| Stream.class.isAssignableFrom((Class<?>) methodGenericReturnType.getRawType());
|
|| Stream.class.isAssignableFrom((Class<?>) methodGenericReturnType.getRawType());
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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 org.springframework.data.elasticsearch.support;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.util.ClassUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Peter-Josef Meisch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public final class ReactiveSupport {
|
||||||
|
private ReactiveSupport() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if project reactor is on the classpath
|
||||||
|
*/
|
||||||
|
public static boolean isReactorAvailable() {
|
||||||
|
AtomicBoolean available = new AtomicBoolean(false);
|
||||||
|
ClassUtils.ifPresent("reactor.core.publisher.Flux", null, aClass -> {
|
||||||
|
available.set(true);
|
||||||
|
});
|
||||||
|
return available.get();
|
||||||
|
}
|
||||||
|
}
|
@ -53,6 +53,7 @@ import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
|||||||
import org.springframework.data.elasticsearch.core.IndexOperations;
|
import org.springframework.data.elasticsearch.core.IndexOperations;
|
||||||
import org.springframework.data.elasticsearch.core.SearchHit;
|
import org.springframework.data.elasticsearch.core.SearchHit;
|
||||||
import org.springframework.data.elasticsearch.core.SearchHits;
|
import org.springframework.data.elasticsearch.core.SearchHits;
|
||||||
|
import org.springframework.data.elasticsearch.core.SearchPage;
|
||||||
import org.springframework.data.elasticsearch.core.geo.GeoBox;
|
import org.springframework.data.elasticsearch.core.geo.GeoBox;
|
||||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||||
import org.springframework.data.elasticsearch.core.query.GeoDistanceOrder;
|
import org.springframework.data.elasticsearch.core.query.GeoDistanceOrder;
|
||||||
@ -1479,6 +1480,23 @@ public abstract class CustomMethodRepositoryBaseTests {
|
|||||||
assertThat(searchHits.getSearchHit(2).getId()).isEqualTo("oslo");
|
assertThat(searchHits.getSearchHit(2).getId()).isEqualTo("oslo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // DATAES-749
|
||||||
|
void shouldReturnSearchPage() {
|
||||||
|
List<SampleEntity> entities = createSampleEntities("abc", 20);
|
||||||
|
repository.saveAll(entities);
|
||||||
|
|
||||||
|
// when
|
||||||
|
SearchPage<SampleEntity> searchPage = repository.searchByMessage("Message", PageRequest.of(0, 10));
|
||||||
|
|
||||||
|
assertThat(searchPage).isNotNull();
|
||||||
|
SearchHits<SampleEntity> searchHits = searchPage.getSearchHits();
|
||||||
|
assertThat(searchHits).isNotNull();
|
||||||
|
assertThat((searchHits.getTotalHits())).isEqualTo(20);
|
||||||
|
assertThat(searchHits.getSearchHits()).hasSize(10);
|
||||||
|
Pageable nextPageable = searchPage.nextPageable();
|
||||||
|
assertThat((nextPageable.getPageNumber())).isEqualTo(1);
|
||||||
|
}
|
||||||
|
|
||||||
private List<SampleEntity> createSampleEntities(String type, int numberOfEntities) {
|
private List<SampleEntity> createSampleEntities(String type, int numberOfEntities) {
|
||||||
|
|
||||||
List<SampleEntity> entities = new ArrayList<>();
|
List<SampleEntity> entities = new ArrayList<>();
|
||||||
@ -1627,6 +1645,8 @@ public abstract class CustomMethodRepositoryBaseTests {
|
|||||||
Stream<SearchHit<SampleEntity>> readByMessage(String message);
|
Stream<SearchHit<SampleEntity>> readByMessage(String message);
|
||||||
|
|
||||||
SearchHits<SampleEntity> searchBy(Sort sort);
|
SearchHits<SampleEntity> searchBy(Sort sort);
|
||||||
|
|
||||||
|
SearchPage<SampleEntity> searchByMessage(String message, Pageable pageable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user