earch API: Automatically identify "script" fields on the field elements in search, close #357.

This commit is contained in:
kimchy 2010-09-06 11:51:31 +03:00
parent 243b7455e8
commit f270fc00d2
6 changed files with 55 additions and 32 deletions

View File

@ -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();
}

View File

@ -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<String> fieldNames = new ArrayList<String>();
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.<String>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);
}
}
}
}

View File

@ -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<ScriptField> fields;
private List<ScriptField> fields = Lists.newArrayList();
public ScriptFieldsContext(List<ScriptField> fields) {
this.fields = fields;
public ScriptFieldsContext() {
}
public void add(ScriptField field) {
this.fields.add(field);
}
public List<ScriptField> fields() {

View File

@ -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<ScriptFieldsContext.ScriptField> 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<String, Object>() : params));
context.scriptFields().add(new ScriptFieldsContext.ScriptField(fieldName, new ScriptFieldsFunction(script, context.scriptService(), context.mapperService(), context.fieldDataCache()), params));
}
}
context.scriptFields(new ScriptFieldsContext(scriptFields));
}
}

View File

@ -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<String> fieldNames() {
if (fieldNames == null) {
fieldNames = Lists.newArrayList();
}
return fieldNames;
}
public SearchContext fieldNames(List<String> fieldNames) {
this.fieldNames = fieldNames;
return this;
public void emptyFieldNames() {
this.fieldNames = ImmutableList.of();
}
public boolean explain() {

View File

@ -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<String, Object> sObj1 = (Map<String, Object>) response.hits().getAt(0).field("s_obj1").value();
Map<String, Object> sObj1 = (Map<String, Object>) 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<String, Object>) 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"));