improve logic of when to load fields from source, only if they actually have mappings, otherwise, ignore them (as was the previous behavior)

This commit is contained in:
kimchy 2010-12-21 13:02:15 +02:00
parent 3035254885
commit a1df3c637c
6 changed files with 90 additions and 19 deletions

View File

@ -0,0 +1,40 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search licenses this
* file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.FieldSelector;
import org.apache.lucene.document.FieldSelectorResult;
/**
* An optimized field selector that loads just the uid and the source.
*
* @author kimchy (shay.banon)
*/
public class AllButSourceFieldSelector implements FieldSelector {
public static AllButSourceFieldSelector INSTANCE = new AllButSourceFieldSelector();
@Override public FieldSelectorResult accept(String fieldName) {
if (SourceFieldMapper.NAME.equals(fieldName)) {
return FieldSelectorResult.NO_LOAD;
}
return FieldSelectorResult.LOAD;
}
}

View File

@ -189,8 +189,9 @@ public class FetchPhase implements SearchPhase {
}
// asked for all stored fields, just return null so all of them will be loaded
// don't load the source field in this case, makes little sense to get it with all stored fields
if (context.fieldNames().get(0).equals("*")) {
return null;
return AllButSourceFieldSelector.INSTANCE;
}
FieldMappersFieldSelector fieldSelector = new FieldMappersFieldSelector();

View File

@ -36,20 +36,26 @@ public class FieldsParseElement implements SearchParseElement {
if (token == XContentParser.Token.START_ARRAY) {
boolean added = false;
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
added = true;
String name = parser.text();
if (name.contains("_source.") || name.contains("doc[")) {
// script field to load from source
SearchScript searchScript = new SearchScript(context.lookup(), null, name, null, context.scriptService());
context.scriptFields().add(new ScriptFieldsContext.ScriptField(name, searchScript));
context.scriptFields().add(new ScriptFieldsContext.ScriptField(name, searchScript, true));
} else {
FieldMapper fieldMapper = context.mapperService().smartNameFieldMapper(name);
if (!"*".equals(name) && (fieldMapper == null || !fieldMapper.stored())) {
// script field to load from source
SearchScript searchScript = new SearchScript(context.lookup(), null, "_source." + name, null, context.scriptService());
context.scriptFields().add(new ScriptFieldsContext.ScriptField(name, searchScript));
if ("*".equals(name)) {
added = true;
context.fieldNames().add("*");
} else {
context.fieldNames().add(name);
FieldMapper fieldMapper = context.mapperService().smartNameFieldMapper(name);
if (fieldMapper != null) {
if (fieldMapper.stored()) {
added = true;
context.fieldNames().add(name);
} else {
SearchScript searchScript = new SearchScript(context.lookup(), "mvel", "_source." + fieldMapper.names().fullName(), null, context.scriptService());
context.scriptFields().add(new ScriptFieldsContext.ScriptField(name, searchScript, true));
}
}
}
}
}
@ -61,15 +67,22 @@ public class FieldsParseElement implements SearchParseElement {
if (name.contains("_source.") || name.contains("doc[")) {
// script field to load from source
SearchScript searchScript = new SearchScript(context.lookup(), null, name, null, context.scriptService());
context.scriptFields().add(new ScriptFieldsContext.ScriptField(name, searchScript));
context.scriptFields().add(new ScriptFieldsContext.ScriptField(name, searchScript, true));
} else {
FieldMapper fieldMapper = context.mapperService().smartNameFieldMapper(name);
if (!"*".equals(name) && (fieldMapper == null || !fieldMapper.stored())) {
// script field to load from source
SearchScript searchScript = new SearchScript(context.lookup(), null, "_source." + name, null, context.scriptService());
context.scriptFields().add(new ScriptFieldsContext.ScriptField(name, searchScript));
if ("*".equals(name)) {
context.fieldNames().add("*");
} else {
context.fieldNames().add(name);
FieldMapper fieldMapper = context.mapperService().smartNameFieldMapper(name);
if (fieldMapper != null) {
if (fieldMapper.stored()) {
context.fieldNames().add(name);
} else {
SearchScript searchScript = new SearchScript(context.lookup(), "mvel", "_source." + fieldMapper.names().fullName(), null, context.scriptService());
context.scriptFields().add(new ScriptFieldsContext.ScriptField(name, searchScript, true));
}
} else {
context.emptyFieldNames(); // don't load anything if we can't find mapping
}
}
}
}

View File

@ -32,10 +32,12 @@ public class ScriptFieldsContext {
public static class ScriptField {
private final String name;
private final SearchScript script;
private final boolean ignoreException;
public ScriptField(String name, SearchScript script) {
public ScriptField(String name, SearchScript script, boolean ignoreException) {
this.name = name;
this.script = script;
this.ignoreException = ignoreException;
}
public String name() {
@ -45,6 +47,10 @@ public class ScriptFieldsContext {
public SearchScript script() {
return this.script;
}
public boolean ignoreException() {
return ignoreException;
}
}
private List<ScriptField> fields = Lists.newArrayList();

View File

@ -53,6 +53,7 @@ public class ScriptFieldsParseElement implements SearchParseElement {
String script = null;
String scriptLang = null;
Map<String, Object> params = null;
boolean ignoreException = false;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
@ -63,11 +64,13 @@ public class ScriptFieldsParseElement implements SearchParseElement {
script = parser.text();
} else if ("lang".equals(currentFieldName)) {
scriptLang = parser.text();
} else if ("ignore_failure".equals(currentFieldName)) {
ignoreException = parser.booleanValue();
}
}
}
SearchScript searchScript = new SearchScript(context.lookup(), scriptLang, script, params, context.scriptService());
context.scriptFields().add(new ScriptFieldsContext.ScriptField(fieldName, searchScript));
context.scriptFields().add(new ScriptFieldsContext.ScriptField(fieldName, searchScript, ignoreException));
}
}
}

View File

@ -58,7 +58,15 @@ public class ScriptFieldsSearchHitPhase implements SearchHitPhase {
for (ScriptFieldsContext.ScriptField scriptField : context.scriptFields().fields()) {
scriptField.script().setNextReader(reader);
Object value = scriptField.script().execute(docId);
Object value;
try {
value = scriptField.script().execute(docId);
} catch (RuntimeException e) {
if (scriptField.ignoreException()) {
continue;
}
throw e;
}
if (hit.fieldsOrNull() == null) {
hit.fields(new HashMap<String, SearchHitField>(2));