DATAES-50 - Added scripted field functionality

This commit is contained in:
Ryan Murfitt
2014-02-11 16:13:55 +10:00
committed by Artur Konczak
parent 727cb5eb09
commit d6603f8edf
9 changed files with 285 additions and 2 deletions

View File

@@ -0,0 +1,19 @@
package org.springframework.data.elasticsearch.annotations;
import java.lang.annotation.*;
/**
* @author Ryan Murfitt
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface ScriptedField {
/**
* (Optional) The name of the scripted field. Defaults to
* the field name.
*/
String name() default "";
}

View File

@@ -37,7 +37,9 @@ import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHitField;
import org.elasticsearch.search.facet.Facet;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.ElasticsearchException;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.ScriptedField;
import org.springframework.data.elasticsearch.core.facet.DefaultFacetMapper;
import org.springframework.data.elasticsearch.core.facet.FacetResult;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
@@ -85,6 +87,7 @@ public class DefaultResultMapper extends AbstractResultMapper {
result = mapEntity(hit.getFields().values(), clazz);
}
setPersistentEntityId(result, hit.getId(), clazz);
populateScriptFields(result, hit);
results.add(result);
}
}
@@ -101,7 +104,31 @@ public class DefaultResultMapper extends AbstractResultMapper {
return new FacetedPageImpl<T>(results, pageable, totalHits, facets);
}
private <T> T mapEntity(Collection<SearchHitField> values, Class<T> clazz) {
private <T> void populateScriptFields(T result, SearchHit hit) {
if (hit.getFields() != null && !hit.getFields().isEmpty() && result != null) {
for (java.lang.reflect.Field field : result.getClass().getDeclaredFields()) {
ScriptedField scriptedField = field.getAnnotation(ScriptedField.class);
if (scriptedField != null) {
String name = scriptedField.name().isEmpty() ? field.getName() : scriptedField.name();
SearchHitField searchHitField = hit.getFields().get(name);
if (searchHitField != null) {
field.setAccessible(true);
try {
field.set(result, searchHitField.getValue());
} catch (IllegalArgumentException e) {
throw new ElasticsearchException("failed to set scripted field: " + name + " with value: "
+ searchHitField.getValue(), e);
} catch (IllegalAccessException e) {
throw new ElasticsearchException("failed to access scripted field: " + name, e);
}
}
}
}
}
}
private <T> T mapEntity(Collection<SearchHitField> values, Class<T> clazz) {
return mapEntity(buildJSONFromFields(values), clazz);
}

View File

@@ -87,6 +87,7 @@ import org.springframework.data.elasticsearch.ElasticsearchException;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Mapping;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.annotations.ScriptedField;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
@@ -841,7 +842,15 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
}
}
if (CollectionUtils.isNotEmpty(searchQuery.getFacets())) {
if (!searchQuery.getScriptFields().isEmpty()) {
searchRequest.addField("_source");
}
for (ScriptField scriptedField : searchQuery.getScriptFields()) {
searchRequest.addScriptField(scriptedField.fieldName(), scriptedField.script(), scriptedField.params());
}
if (CollectionUtils.isNotEmpty(searchQuery.getFacets())) {
for (FacetRequest facetRequest : searchQuery.getFacets()) {
FacetBuilder facet = facetRequest.getFacet();
if (facetRequest.applyQueryFilter() && searchQuery.getFilter() != null) {

View File

@@ -15,6 +15,9 @@
*/
package org.springframework.data.elasticsearch.core.query;
import java.util.ArrayList;
import java.util.List;
import org.elasticsearch.index.query.FilterBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
@@ -23,6 +26,7 @@ import org.elasticsearch.search.sort.SortBuilder;
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@@ -37,6 +41,7 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery {
private QueryBuilder query;
private FilterBuilder filter;
private List<SortBuilder> sorts;
private final List<ScriptField> scriptFields = new ArrayList<ScriptField>();
private List<FacetRequest> facets;
private List<AbstractAggregationBuilder> aggregations;
private HighlightBuilder.Field[] highlightFields;
@@ -81,6 +86,17 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery {
return highlightFields;
}
@Override
public List<ScriptField> getScriptFields() { return scriptFields; }
public void setScriptFields(List<ScriptField> scriptFields) {
this.scriptFields.addAll(scriptFields);
}
public void addScriptField(ScriptField... scriptField) {
scriptFields.addAll(Arrays.asList(scriptField));
}
public void addFacet(FacetRequest facetRequest) {
if (facets == null) {
facets = new ArrayList<FacetRequest>();

View File

@@ -41,6 +41,7 @@ public class NativeSearchQueryBuilder {
private QueryBuilder queryBuilder;
private FilterBuilder filterBuilder;
private List<ScriptField> scriptFields = new ArrayList<ScriptField>();
private List<SortBuilder> sortBuilders = new ArrayList<SortBuilder>();
private List<FacetRequest> facetRequests = new ArrayList<FacetRequest>();
private List<AbstractAggregationBuilder> aggregationBuilders = new ArrayList<AbstractAggregationBuilder>();
@@ -69,6 +70,11 @@ public class NativeSearchQueryBuilder {
return this;
}
public NativeSearchQueryBuilder withScriptField(ScriptField scriptField) {
this.scriptFields.add(scriptField);
return this;
}
public NativeSearchQueryBuilder addAggregation(AbstractAggregationBuilder aggregationBuilder) {
this.aggregationBuilders.add(aggregationBuilder);
return this;
@@ -141,6 +147,9 @@ public class NativeSearchQueryBuilder {
if (fields != null) {
nativeSearchQuery.addFields(fields);
}
if (CollectionUtils.isNotEmpty(scriptFields)) {
nativeSearchQuery.setScriptFields(scriptFields);
}
if (CollectionUtils.isNotEmpty(facetRequests)) {
nativeSearchQuery.setFacets(facetRequests);

View File

@@ -0,0 +1,31 @@
package org.springframework.data.elasticsearch.core.query;
import java.util.Map;
/**
* @author Ryan Murfitt
*/
public class ScriptField {
private final String fieldName;
private final String script;
private final Map<String, Object> params;
public ScriptField(String fieldName, String script, Map<String, Object> params) {
this.fieldName = fieldName;
this.script = script;
this.params = params;
}
public String fieldName() {
return fieldName;
}
public String script() {
return script;
}
public Map<String, Object> params() {
return params;
}
}

View File

@@ -44,4 +44,7 @@ public interface SearchQuery extends Query {
List<AbstractAggregationBuilder> getAggregations();
HighlightBuilder.Field[] getHighlightFields();
List<ScriptField> getScriptFields();
}