DATAES-722 - Return total count relation in the SearchHits object.

Original PR: #369
This commit is contained in:
Peter-Josef Meisch 2019-12-31 13:55:56 +01:00 committed by GitHub
parent 90d29994f1
commit 5c862e80bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 25 deletions

View File

@ -39,38 +39,50 @@ public class SearchHits<T> implements Streamable<SearchHit<T>> {
private final String scrollId;
private final List<? extends SearchHit<T>> searchHits;
private final Aggregations aggregations;
private final TotalHitsRelation totalHitsRelation;
/**
* @param totalHits
* @param maxScore
* @param totalHits the number of total hits for the search
* @param totalHitsRelation the relation {@see TotalHitsRelation}, must not be {@literal null}
* @param maxScore the maximum score
* @param scrollId the scroll id if available
* @param searchHits must not be {@literal null}
* @param aggregations
* @param aggregations the aggregations if available
*/
public SearchHits(long totalHits, float maxScore, @Nullable String scrollId, List<? extends SearchHit<T>> searchHits,
@Nullable Aggregations aggregations) {
public SearchHits(long totalHits, TotalHitsRelation totalHitsRelation, float maxScore, @Nullable String scrollId,
List<? extends SearchHit<T>> searchHits, @Nullable Aggregations aggregations) {
Assert.notNull(searchHits, "searchHits must not be null");
this.totalHits = totalHits;
this.totalHitsRelation = totalHitsRelation;
this.maxScore = maxScore;
this.scrollId = scrollId;
this.searchHits = searchHits;
this.aggregations = aggregations;
}
@SuppressWarnings("unchecked")
@Override
public Iterator<SearchHit<T>> iterator() {
return (Iterator<SearchHit<T>>) searchHits.iterator();
}
// region getter
/**
* @return the number of total hits.
*/
// region getter
public long getTotalHits() {
return totalHits;
}
/**
* @return the relation for the total hits
*/
public TotalHitsRelation getTotalHitsRelation() {
return totalHitsRelation;
}
/**
* @return the maximum score
*/
@ -107,19 +119,20 @@ public class SearchHits<T> implements Streamable<SearchHit<T>> {
@Override
public String toString() {
return "SearchHits{" +
"totalHits=" + totalHits +
", maxScore=" + maxScore +
", scrollId='" + scrollId + '\'' +
", searchHits=" + StringUtils.collectionToCommaDelimitedString(searchHits) +
", aggregations=" + aggregations +
return "SearchHits{" + //
"totalHits=" + totalHits + //
", totalHitsRelation=" + totalHitsRelation + //
", maxScore=" + maxScore + //
", scrollId='" + scrollId + '\'' + //
", searchHits={" + searchHits.size() + " elements}" + //
", aggregations=" + aggregations + //
'}';
}
// region aggregations
/**
* @return true if aggregations are available
*/
// region aggregations
public boolean hasAggregations() {
return aggregations != null;
}
@ -133,4 +146,12 @@ public class SearchHits<T> implements Streamable<SearchHit<T>> {
}
// endregion
/**
* Enum to represent the relation that Elasticsearch returns for the totalHits value {@see <a href=
* "https://www.elastic.co/guide/en/elasticsearch/reference/7.5/search-request-body.html#request-body-search-track-total-hits">Ekasticsearch
* docs</a>}
*/
public enum TotalHitsRelation {
EQUAL_TO, GREATER_THAN_OR_EQUAL_TO
}
}

View File

@ -169,7 +169,10 @@ public class MappingElasticsearchConverter
.map(searchDocument -> read(type, searchDocument)) //
.collect(Collectors.toList());
Aggregations aggregations = searchDocumentResponse.getAggregations();
return new SearchHits<>(totalHits, maxScore, scrollId, searchHits, aggregations);
SearchHits.TotalHitsRelation totalHitsRelation = SearchHits.TotalHitsRelation
.valueOf(searchDocumentResponse.getTotalHitsRelation());
return new SearchHits<>(totalHits, totalHitsRelation, maxScore, scrollId, searchHits, aggregations);
}
@Override

View File

@ -20,14 +20,14 @@ import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.aggregations.Aggregations;
import org.springframework.data.elasticsearch.support.SearchHitsUtil;
import org.springframework.util.Assert;
/**
* This represents the complete search response from Elasticsearch, including the returned documents. Instances must be
* created with the {@link #from(org.elasticsearch.action.search.SearchResponse)} method.
* created with the {@link #from(SearchResponse)} method.
*
* @author Peter-Josef Meisch
* @since 4.0
@ -35,14 +35,16 @@ import org.springframework.util.Assert;
public class SearchDocumentResponse {
private long totalHits;
private String totalHitsRelation;
private float maxScore;
private final String scrollId;
private final List<SearchDocument> searchDocuments;
private final Aggregations aggregations;
private SearchDocumentResponse(long totalHits, float maxScore, String scrollId, List<SearchDocument> searchDocuments,
Aggregations aggregations) {
private SearchDocumentResponse(long totalHits, String totalHitsRelation, float maxScore, String scrollId,
List<SearchDocument> searchDocuments, Aggregations aggregations) {
this.totalHits = totalHits;
this.totalHitsRelation = totalHitsRelation;
this.maxScore = maxScore;
this.scrollId = scrollId;
this.searchDocuments = searchDocuments;
@ -53,6 +55,10 @@ public class SearchDocumentResponse {
return totalHits;
}
public String getTotalHitsRelation() {
return totalHitsRelation;
}
public float getMaxScore() {
return maxScore;
}
@ -70,23 +76,29 @@ public class SearchDocumentResponse {
}
/**
* creates a SearchDocumentResponse from the {@link org.elasticsearch.action.search.SearchResponse}
* creates a SearchDocumentResponse from the {@link SearchResponse}
*
* @param searchResponse must not be {@literal null}
* @return
* @param searchResponse
* must not be {@literal null}
* @return the SearchDocumentResponse
*/
public static SearchDocumentResponse from(SearchResponse searchResponse) {
Assert.notNull(searchResponse, "searchResponse must not be null");
long totalHits = SearchHitsUtil.getTotalCount(searchResponse.getHits());
TotalHits responseTotalHits = searchResponse.getHits().getTotalHits();
long totalHits = responseTotalHits.value;
String totalHitsRelation = responseTotalHits.relation.name();
float maxScore = searchResponse.getHits().getMaxScore();
String scrollId = searchResponse.getScrollId();
List<SearchDocument> searchDocuments = StreamSupport.stream(searchResponse.getHits().spliterator(), false) //
.filter(Objects::nonNull) //
.map(DocumentAdapters::from) //
.collect(Collectors.toList());
Aggregations aggregations = searchResponse.getAggregations();
return new SearchDocumentResponse(totalHits, maxScore, scrollId, searchDocuments, aggregations);
return new SearchDocumentResponse(totalHits, totalHitsRelation, maxScore, scrollId, searchDocuments, aggregations);
}
}

View File

@ -192,7 +192,7 @@ public abstract class ElasticsearchTemplateTests {
assertThat(count).isEqualTo(1);
}
@Test
@Test // DATAES-722
public void shouldReturnObjectForGivenId() {
// given
@ -289,7 +289,8 @@ public abstract class ElasticsearchTemplateTests {
// then
assertThat(searchHits).isNotNull();
assertThat(searchHits.getTotalHits()).isGreaterThanOrEqualTo(1);
assertThat(searchHits.getTotalHits()).isEqualTo(1);
assertThat(searchHits.getTotalHitsRelation()).isEqualByComparingTo(SearchHits.TotalHitsRelation.EQUAL_TO);
}
@Test // DATAES-595