diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/FetchPhase.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/FetchPhase.java index 19db87e1e00..3968d88b5f0 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/FetchPhase.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/FetchPhase.java @@ -135,7 +135,7 @@ public class FetchPhase implements SearchPhase { hitField.values().add(value); } - if (context.scriptFields() != null) { + if (context.hasScriptFields()) { sameDocCache.clear(); int readerIndex = context.searcher().readerIndex(docId); IndexReader subReader = context.searcher().subReaders()[readerIndex]; @@ -203,12 +203,12 @@ public class FetchPhase implements SearchPhase { } private FieldSelector buildFieldSelectors(SearchContext context) { - if (context.scriptFields() != null && context.fieldNames() == null) { + if (context.hasScriptFields() && !context.hasFieldNames()) { // we ask for script fields, and no field names, don't load the source return UidFieldSelector.INSTANCE; } - if (context.fieldNames() == null) { + if (!context.hasFieldNames()) { return new UidAndSourceFieldSelector(); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/FieldsParseElement.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/FieldsParseElement.java index 282c678f016..9567791ea55 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/FieldsParseElement.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/FieldsParseElement.java @@ -19,13 +19,12 @@ package org.elasticsearch.search.fetch; -import org.elasticsearch.common.collect.ImmutableList; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.field.function.script.ScriptFieldsFunction; import org.elasticsearch.search.SearchParseElement; +import org.elasticsearch.search.fetch.script.ScriptFieldsContext; import org.elasticsearch.search.internal.SearchContext; -import java.util.ArrayList; - /** * @author kimchy (shay.banon) */ @@ -34,17 +33,28 @@ public class FieldsParseElement implements SearchParseElement { @Override public void parse(XContentParser parser, SearchContext context) throws Exception { XContentParser.Token token = parser.currentToken(); if (token == XContentParser.Token.START_ARRAY) { - ArrayList fieldNames = new ArrayList(); + boolean added = false; while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { - fieldNames.add(parser.text()); + added = true; + String name = parser.text(); + if (name.contains("_source.") || name.contains("doc[")) { + // script field to load from source + context.scriptFields().add(new ScriptFieldsContext.ScriptField(name, new ScriptFieldsFunction(name, context.scriptService(), context.mapperService(), context.fieldDataCache()), null)); + } else { + context.fieldNames().add(name); + } } - if (fieldNames.isEmpty()) { - context.fieldNames(ImmutableList.of()); - } else { - context.fieldNames(fieldNames); + if (!added) { + context.emptyFieldNames(); } } else if (token == XContentParser.Token.VALUE_STRING) { - context.fieldNames(ImmutableList.of(parser.text())); + String name = parser.text(); + if (name.contains("_source.") || name.contains("doc[")) { + // script field to load from source + context.scriptFields().add(new ScriptFieldsContext.ScriptField(name, new ScriptFieldsFunction(name, context.scriptService(), context.mapperService(), context.fieldDataCache()), null)); + } else { + context.fieldNames().add(name); + } } } } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/script/ScriptFieldsContext.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/script/ScriptFieldsContext.java index 7a626a8f6c7..66f103ef899 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/script/ScriptFieldsContext.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/script/ScriptFieldsContext.java @@ -19,6 +19,7 @@ package org.elasticsearch.search.fetch.script; +import org.elasticsearch.common.collect.Lists; import org.elasticsearch.index.field.function.script.ScriptFieldsFunction; import java.util.List; @@ -53,10 +54,13 @@ public class ScriptFieldsContext { } } - private List fields; + private List fields = Lists.newArrayList(); - public ScriptFieldsContext(List fields) { - this.fields = fields; + public ScriptFieldsContext() { + } + + public void add(ScriptField field) { + this.fields.add(field); } public List fields() { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/script/ScriptFieldsParseElement.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/script/ScriptFieldsParseElement.java index 2c4838e9f60..6fa7458d671 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/script/ScriptFieldsParseElement.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/fetch/script/ScriptFieldsParseElement.java @@ -19,14 +19,11 @@ package org.elasticsearch.search.fetch.script; -import org.elasticsearch.common.collect.Lists; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.field.function.script.ScriptFieldsFunction; import org.elasticsearch.search.SearchParseElement; import org.elasticsearch.search.internal.SearchContext; -import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -48,7 +45,6 @@ public class ScriptFieldsParseElement implements SearchParseElement { @Override public void parse(XContentParser parser, SearchContext context) throws Exception { XContentParser.Token token; String currentFieldName = null; - List scriptFields = Lists.newArrayList(); while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); @@ -65,11 +61,8 @@ public class ScriptFieldsParseElement implements SearchParseElement { script = parser.text(); } } - scriptFields.add(new ScriptFieldsContext.ScriptField(fieldName, - new ScriptFieldsFunction(script, context.scriptService(), context.mapperService(), context.fieldDataCache()), - params == null ? new HashMap() : params)); + context.scriptFields().add(new ScriptFieldsContext.ScriptField(fieldName, new ScriptFieldsFunction(script, context.scriptService(), context.mapperService(), context.fieldDataCache()), params)); } } - context.scriptFields(new ScriptFieldsContext(scriptFields)); } } \ No newline at end of file diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/internal/SearchContext.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/internal/SearchContext.java index 66062fd85ca..1d905fc6c95 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/internal/SearchContext.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/internal/SearchContext.java @@ -22,6 +22,8 @@ package org.elasticsearch.search.internal; import org.apache.lucene.search.Query; import org.apache.lucene.search.Sort; import org.elasticsearch.ElasticSearchException; +import org.elasticsearch.common.collect.ImmutableList; +import org.elasticsearch.common.collect.Lists; import org.elasticsearch.common.lease.Releasable; import org.elasticsearch.common.timer.Timeout; import org.elasticsearch.common.unit.TimeValue; @@ -198,12 +200,15 @@ public class SearchContext implements Releasable { this.highlight = highlight; } - public ScriptFieldsContext scriptFields() { - return this.scriptFields; + public boolean hasScriptFields() { + return scriptFields != null; } - public void scriptFields(ScriptFieldsContext scriptFields) { - this.scriptFields = scriptFields; + public ScriptFieldsContext scriptFields() { + if (scriptFields == null) { + scriptFields = new ScriptFieldsContext(); + } + return this.scriptFields; } public ContextIndexSearcher searcher() { @@ -322,13 +327,19 @@ public class SearchContext implements Releasable { return this; } + public boolean hasFieldNames() { + return fieldNames != null; + } + public List fieldNames() { + if (fieldNames == null) { + fieldNames = Lists.newArrayList(); + } return fieldNames; } - public SearchContext fieldNames(List fieldNames) { - this.fieldNames = fieldNames; - return this; + public void emptyFieldNames() { + this.fieldNames = ImmutableList.of(); } public boolean explain() { diff --git a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/scriptfield/ScriptFieldSearchTests.java b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/scriptfield/ScriptFieldSearchTests.java index 62e155206fd..1e0fe09f7aa 100644 --- a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/scriptfield/ScriptFieldSearchTests.java +++ b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/scriptfield/ScriptFieldSearchTests.java @@ -126,13 +126,18 @@ public class ScriptFieldSearchTests extends AbstractNodesTests { SearchResponse response = client.prepareSearch() .setQuery(matchAllQuery()) + .addField("_source.obj1") // we also automatically detect _source in fields .addScriptField("s_obj1", "_source.obj1") .addScriptField("s_obj1_test", "_source.obj1.test") .addScriptField("s_obj2", "_source.obj2") .addScriptField("s_obj2_arr2", "_source.obj2.arr2") .execute().actionGet(); - Map sObj1 = (Map) response.hits().getAt(0).field("s_obj1").value(); + Map sObj1 = (Map) response.hits().getAt(0).field("_source.obj1").value(); + assertThat(sObj1.get("test").toString(), equalTo("something")); + assertThat(response.hits().getAt(0).field("s_obj1_test").value().toString(), equalTo("something")); + + sObj1 = (Map) response.hits().getAt(0).field("s_obj1").value(); assertThat(sObj1.get("test").toString(), equalTo("something")); assertThat(response.hits().getAt(0).field("s_obj1_test").value().toString(), equalTo("something"));