sourcefilter documentation.

Original Pull Request #2258
Closes #2257
This commit is contained in:
Peter-Josef Meisch 2022-08-07 12:22:46 +02:00 committed by GitHub
parent 44a79093ce
commit df5fd0b97c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 59 additions and 45 deletions

View File

@ -53,7 +53,7 @@ interface BookRepository extends Repository<Book, String> {
@HighlightField(name = "name"),
@HighlightField(name = "summary")
})
List<SearchHit<Book>> findByNameOrSummary(String text, String summary);
SearchHits<Book> findByNameOrSummary(String text, String summary);
}
----
====
@ -62,6 +62,30 @@ It is possible to define multiple fields to be highlighted like above, and both
In the search results the highlight data can be retrieved from the `SearchHit` class.
=== @SourceFilters
Sometimes the user does not need to have all the properties of an entity returned from a search but only a subset.
Elasticsearch provides source filtering to reduce the amount of data that is transferred across the network to the
application.
When working with `Query` implementations and the `ElasticsearchOperations` this is easily possible by setting a
source filter on the query.
When using repository methods there is the `@SourceFilters` annotation:
====
[source,java]
----
interface BookRepository extends Repository<Book, String> {
@SourceFilters(includes = "name")
SearchHits<Book> findByName(String text);
}
----
====
In this example, all the properties of the returned `Book` objects would be `null` except the name.
[[elasticsearch.annotation]]
== Annotation based configuration

View File

@ -16,11 +16,11 @@
package org.springframework.data.elasticsearch.annotations;
/**
* Values based on reference doc - https://www.elastic.co/guide/reference/mapping/date-format/. The patterns are taken
* from this documentation and slightly adapted so that a Java {@link java.time.format.DateTimeFormatter} produces the
* same values as the Elasticsearch formatter. Use <code>format = {}</code> to disable built-in date * formats in
* the @Field annotation. If you want to use only a custom date format pattern, you must set the <code>format</code> *
* property to empty <code>{}</code>.
* Values based on <a href="https://www.elastic.co/guide/reference/mapping/date-format/">Elasticsearch reference
* documentation</a>. The patterns are taken from this documentation and slightly adapted so that a Java
* {@link java.time.format.DateTimeFormatter} produces the same values as the Elasticsearch formatter. Use
* <code>format = {}</code> to disable built-in date formats in the {@link Field} annotation. If you want to use only a
* custom date format pattern, you must set the <code>format</code> property to empty <code>{}</code>.
*
* @author Jakub Vavrik
* @author Tim te Beek
@ -49,7 +49,7 @@ public enum DateFormat {
date_hour_minute_second_millis("uuuu-MM-dd'T'HH:mm:ss.SSS"), //
date_optional_time("uuuu-MM-dd['T'HH:mm:ss.SSSXXX]"), //
date_time("uuuu-MM-dd'T'HH:mm:ss.SSSXXX"), //
date_time_no_millis("uuuu-MM-dd'T'HH:mm:ssVV"), // here Elasticsearch uses the zone-id in it's implementation
date_time_no_millis("uuuu-MM-dd'T'HH:mm:ssVV"), // here Elasticsearch uses the zone-id in its implementation
epoch_millis("epoch_millis"), //
epoch_second("epoch_second"), //
hour("HH"), //

View File

@ -53,9 +53,8 @@ public @interface Field {
String value() default "";
/**
* The <em>name</em> to be used to store the field inside the document.
* <p>
* 5 If not set, the name of the annotated property is used.
* The <em>name</em> to be used to store the field inside the document. If not set, the name of the annotated property
* is used.
*
* @since 3.2
*/

View File

@ -1031,6 +1031,7 @@ class RequestConverter {
Assert.notNull(query, "query must not be null");
Assert.notNull(indexCoordinates, "indexCoordinates must not be null");
elasticsearchConverter.updateQuery(query, clazz);
SearchRequest.Builder builder = new SearchRequest.Builder();
prepareSearchRequest(query, clazz, indexCoordinates, builder, forCount, useScroll);

View File

@ -15,19 +15,29 @@
*/
package org.springframework.data.elasticsearch.core.query;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.lang.Nullable;
/**
* SourceFilter for providing includes and excludes.
* SourceFilter for providing includes and excludes. Using these helps in reducing the amount of data that is returned
* from Elasticsearch especially when the stored docuements are large and only some fields from these documents are
* needed. If the SourceFilter includes the name of a property that has a different name mapped in Elasticsearch (see
* {@link Field#name()} this will automatically be mapped.
*
* @author Jon Tsiros
* @author Peter-Josef Meisch
*/
public interface SourceFilter {
/**
* @return the name of the fields to include in a response.
*/
@Nullable
String[] getIncludes();
/**
* @return the names of the fields to exclude from a response.
*/
@Nullable
String[] getExcludes();
}

View File

@ -57,7 +57,6 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository
protected void prepareQuery(Query query, Class<?> clazz, ParameterAccessor parameterAccessor) {
elasticsearchConverter.updateQuery(query, clazz);
if (queryMethod.hasAnnotatedHighlight()) {
query.setHighlightQuery(queryMethod.getAnnotatedHighlightQuery());
@ -68,5 +67,7 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository
if (sourceFilter != null) {
query.addSourceFilter(sourceFilter);
}
elasticsearchConverter.updateQuery(query, clazz);
}
}

View File

@ -131,6 +131,9 @@ public class ElasticsearchQueryMethod extends QueryMethod {
}
private HighlightQuery createAnnotatedHighlightQuery() {
Assert.notNull(highlightAnnotation, "highlightAnnotation must not be null");
return new HighlightQuery(
org.springframework.data.elasticsearch.core.query.highlight.Highlight.of(highlightAnnotation),
getDomainClass());
@ -140,6 +143,7 @@ public class ElasticsearchQueryMethod extends QueryMethod {
* @return the {@link ElasticsearchEntityMetadata} for the query methods {@link #getReturnedObjectType() return type}.
* @since 3.2
*/
@SuppressWarnings("unchecked")
@Override
public ElasticsearchEntityMetadata<?> getEntityInformation() {
@ -260,23 +264,6 @@ public class ElasticsearchQueryMethod extends QueryMethod {
return queryAnnotation != null && queryAnnotation.count();
}
/**
* @return {@literal true} if the method is annotated with {@link SourceFilters}.
* @since 5.0
*/
public boolean hasSourceFilters() {
return sourceFilters != null;
}
/**
* @return the {@link SourceFilters} annotation for this method.
* @since 5.0
*/
@Nullable
public SourceFilters getSourceFilters() {
return sourceFilters;
}
/**
* Uses the sourceFilters property to create a {@link SourceFilter} to be added to a
* {@link org.springframework.data.elasticsearch.core.query.Query}
@ -295,29 +282,25 @@ public class ElasticsearchQueryMethod extends QueryMethod {
return null;
}
ElasticsearchPersistentEntity<?> persistentEntity = converter.getMappingContext()
.getPersistentEntity(getEntityInformation().getJavaType());
StringQueryUtil stringQueryUtil = new StringQueryUtil(converter.getConversionService());
FetchSourceFilterBuilder fetchSourceFilterBuilder = new FetchSourceFilterBuilder();
if (sourceFilters.includes().length > 0) {
fetchSourceFilterBuilder
.withIncludes(mapParameters(sourceFilters.includes(), parameterAccessor, stringQueryUtil, persistentEntity));
.withIncludes(mapParameters(sourceFilters.includes(), parameterAccessor, stringQueryUtil));
}
if (sourceFilters.excludes().length > 0) {
fetchSourceFilterBuilder
.withExcludes(mapParameters(sourceFilters.excludes(), parameterAccessor, stringQueryUtil, persistentEntity));
.withExcludes(mapParameters(sourceFilters.excludes(), parameterAccessor, stringQueryUtil));
}
return fetchSourceFilterBuilder.build();
}
private String[] mapParameters(String[] source, ParameterAccessor parameterAccessor, StringQueryUtil stringQueryUtil,
@Nullable ElasticsearchPersistentEntity<?> persistentEntity) {
private String[] mapParameters(String[] source, ParameterAccessor parameterAccessor, StringQueryUtil stringQueryUtil) {
List<String> unmappedFieldNames = new ArrayList<>();
List<String> fieldNames = new ArrayList<>();
for (String s : source) {
@ -325,21 +308,17 @@ public class ElasticsearchQueryMethod extends QueryMethod {
String fieldName = stringQueryUtil.replacePlaceholders(s, parameterAccessor);
// this could be "[\"foo\",\"bar\"]", must be split
if (fieldName.startsWith("[") && fieldName.endsWith("]")) {
unmappedFieldNames.addAll( //
//noinspection RegExpRedundantEscape
fieldNames.addAll( //
Arrays.asList(fieldName.substring(1, fieldName.length() - 2) //
.replaceAll("\\\"", "") //
.split(","))); //
} else {
unmappedFieldNames.add(fieldName);
fieldNames.add(fieldName);
}
}
}
return unmappedFieldNames.stream().map(fieldName -> {
ElasticsearchPersistentProperty property = persistentEntity != null
? persistentEntity.getPersistentProperty(fieldName)
: null;
return property != null ? property.getFieldName() : fieldName;
}).toArray(String[]::new);
return fieldNames.toArray(new String[0]);
}
}