Move rank-eval template compilation down to TransportRankEvalAction (#21855)

Move rank-eval template compilation down to TransportRankEvalAction

Closes #21777 and #21465

Search templates for rank_eval endpoint so far only worked when sent through
REST end point

However we also allow templates to be set through a Java API call to
"setTemplate" on that same spec. This doesn't go through template execution so
fails further down the line.

To make this work, moved template execution further down, probably to
TransportRankEvalAction.

* Add template IT test for Java API
* Move template compilation to TransportRankEvalAction
This commit is contained in:
Isabel Drost-Fromm 2016-12-06 10:30:25 +01:00 committed by GitHub
parent 5601049014
commit e0b15eafb0
5 changed files with 163 additions and 31 deletions

View File

@ -23,23 +23,17 @@ import org.elasticsearch.action.support.ToXContentToBytes;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
/**
@ -154,24 +148,7 @@ public class RankEvalSpec extends ToXContentToBytes implements Writeable {
}
public static RankEvalSpec parse(XContentParser parser, RankEvalContext context, boolean templated) throws IOException {
RankEvalSpec spec = PARSER.parse(parser, context);
if (templated) {
for (RatedRequest query_spec : spec.getSpecifications()) {
Map<String, Object> params = query_spec.getParams();
Script scriptWithParams = new Script(spec.template.getType(), spec.template.getLang(), spec.template.getIdOrCode(), params);
String resolvedRequest = ((BytesReference) (context.getScriptService()
.executable(scriptWithParams, ScriptContext.Standard.SEARCH).run())).utf8ToString();
try (XContentParser subParser = XContentFactory.xContent(resolvedRequest).createParser(resolvedRequest)) {
QueryParseContext parseContext = new QueryParseContext(context.getSearchRequestParsers().queryParsers, subParser,
context.getParseFieldMatcher());
SearchSourceBuilder templateResult = SearchSourceBuilder.fromXContent(parseContext, context.getAggs(),
context.getSuggesters(), context.getSearchExtParsers());
query_spec.setTestRequest(templateResult);
}
}
}
return spec;
return PARSER.parse(parser, context);
}
@Override

View File

@ -74,7 +74,8 @@ public class RatedRequest extends ToXContentToBytes implements Writeable {
public RatedRequest(StreamInput in) throws IOException {
this.specId = in.readString();
testRequest = new SearchSourceBuilder(in);
testRequest = in.readOptionalWriteable(SearchSourceBuilder::new);
int indicesSize = in.readInt();
indices = new ArrayList<>(indicesSize);
for (int i = 0; i < indicesSize; i++) {
@ -101,7 +102,8 @@ public class RatedRequest extends ToXContentToBytes implements Writeable {
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(specId);
testRequest.writeTo(out);
out.writeOptionalWriteable(testRequest);
out.writeInt(indices.size());
for (String index : indices) {
out.writeString(index);
@ -255,8 +257,9 @@ public class RatedRequest extends ToXContentToBytes implements Writeable {
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(ID_FIELD.getPreferredName(), this.specId);
if (testRequest != null)
if (testRequest != null) {
builder.field(REQUEST_FIELD.getPreferredName(), this.testRequest);
}
builder.startObject(PARAMS_FIELD.getPreferredName());
for (Entry<String, Object> entry : this.params.entrySet()) {
builder.field(entry.getKey(), entry.getValue());

View File

@ -26,14 +26,24 @@ import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.HandledTransportAction;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchRequestParsers;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -51,12 +61,17 @@ import java.util.concurrent.atomic.AtomicInteger;
* */
public class TransportRankEvalAction extends HandledTransportAction<RankEvalRequest, RankEvalResponse> {
private Client client;
private ScriptService scriptService;
private SearchRequestParsers searchRequestParsers;
@Inject
public TransportRankEvalAction(Settings settings, ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver, Client client, TransportService transportService) {
IndexNameExpressionResolver indexNameExpressionResolver, Client client, TransportService transportService,
SearchRequestParsers searchRequestParsers, ScriptService scriptService) {
super(settings, RankEvalAction.NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver,
RankEvalRequest::new);
this.searchRequestParsers = searchRequestParsers;
this.scriptService = scriptService;
this.client = client;
}
@ -69,10 +84,25 @@ public class TransportRankEvalAction extends HandledTransportAction<RankEvalRequ
Map<String, EvalQueryQuality> partialResults = new ConcurrentHashMap<>(specifications.size());
Map<String, Exception> errors = new ConcurrentHashMap<>(specifications.size());
CompiledScript scriptWithoutParams = null;
if (qualityTask.getTemplate() != null) {
scriptWithoutParams = scriptService.compile(qualityTask.getTemplate(), ScriptContext.Standard.SEARCH, new HashMap<>());
}
for (RatedRequest querySpecification : specifications) {
final RankEvalActionListener searchListener = new RankEvalActionListener(listener, qualityTask.getMetric(), querySpecification,
partialResults, errors, responseCounter);
SearchSourceBuilder specRequest = querySpecification.getTestRequest();
if (specRequest == null) {
Map<String, Object> params = querySpecification.getParams();
String resolvedRequest = ((BytesReference) (scriptService.executable(scriptWithoutParams, params).run())).utf8ToString();
try (XContentParser subParser = XContentFactory.xContent(resolvedRequest).createParser(resolvedRequest)) {
QueryParseContext parseContext = new QueryParseContext(searchRequestParsers.queryParsers, subParser, parseFieldMatcher);
specRequest = SearchSourceBuilder.fromXContent(parseContext, searchRequestParsers.aggParsers,
searchRequestParsers.suggesters, searchRequestParsers.searchExtParsers);
} catch (IOException e) {
listener.onFailure(e);
}
}
List<String> summaryFields = querySpecification.getSummaryFields();
if (summaryFields.isEmpty()) {
specRequest.fetchSource(false);

View File

@ -19,9 +19,9 @@
apply plugin: 'elasticsearch.rest-test'
/*
dependencies {
testCompile project(path: ':modules:rank-eval', configuration: 'runtime')
testCompile project(path: ':modules:lang-mustache', configuration: 'runtime')
}
*/

View File

@ -0,0 +1,122 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.smoketest;
import org.elasticsearch.index.rankeval.Precision;
import org.elasticsearch.index.rankeval.RankEvalAction;
import org.elasticsearch.index.rankeval.RankEvalPlugin;
import org.elasticsearch.index.rankeval.RankEvalRequest;
import org.elasticsearch.index.rankeval.RankEvalRequestBuilder;
import org.elasticsearch.index.rankeval.RankEvalResponse;
import org.elasticsearch.index.rankeval.RankEvalSpec;
import org.elasticsearch.index.rankeval.RatedDocument;
import org.elasticsearch.index.rankeval.RatedRequest;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.test.ESIntegTestCase;
import org.junit.Before;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SmokeMultipleTemplatesIT extends ESIntegTestCase {
@Override
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
return Arrays.asList(RankEvalPlugin.class);
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(RankEvalPlugin.class);
}
@Before
public void setup() {
createIndex("test");
ensureGreen();
client().prepareIndex("test", "testtype").setId("1")
.setSource("text", "berlin", "title", "Berlin, Germany").get();
client().prepareIndex("test", "testtype").setId("2")
.setSource("text", "amsterdam").get();
client().prepareIndex("test", "testtype").setId("3")
.setSource("text", "amsterdam").get();
client().prepareIndex("test", "testtype").setId("4")
.setSource("text", "amsterdam").get();
client().prepareIndex("test", "testtype").setId("5")
.setSource("text", "amsterdam").get();
client().prepareIndex("test", "testtype").setId("6")
.setSource("text", "amsterdam").get();
refresh();
}
public void testPrecisionAtRequest() throws IOException {
List<String> indices = Arrays.asList(new String[] { "test" });
List<String> types = Arrays.asList(new String[] { "testtype" });
List<RatedRequest> specifications = new ArrayList<>();
RatedRequest amsterdamRequest = new RatedRequest("amsterdam_query", null, indices, types, createRelevant("2", "3", "4", "5"));
Map<String, Object> ams_params = new HashMap<>();
ams_params.put("querystring", "amsterdam");
amsterdamRequest.setParams(ams_params);
specifications.add(amsterdamRequest);
RatedRequest berlinRequest = new RatedRequest("berlin_query", null, indices, types, createRelevant("1"));
Map<String, Object> berlin_params = new HashMap<>();
berlin_params.put("querystring", "berlin");
berlinRequest.setParams(berlin_params);
specifications.add(berlinRequest);
Precision metric = new Precision();
RankEvalSpec task = new RankEvalSpec(specifications, metric);
task.setTemplate(
new Script(
ScriptType.INLINE,
"mustache", "{\"query\": {\"match\": {\"text\": \"{{querystring}}\"}}}",
new HashMap<>()));
RankEvalRequestBuilder builder = new RankEvalRequestBuilder(client(), RankEvalAction.INSTANCE, new RankEvalRequest());
builder.setRankEvalSpec(task);
RankEvalResponse response = client().execute(RankEvalAction.INSTANCE, builder.request()).actionGet();
assertEquals(0.9, response.getQualityLevel(), Double.MIN_VALUE);
}
private static List<RatedDocument> createRelevant(String... docs) {
List<RatedDocument> relevant = new ArrayList<>();
for (String doc : docs) {
relevant.add(new RatedDocument("test", "testtype", doc, Rating.RELEVANT.ordinal()));
}
return relevant;
}
public enum Rating {
IRRELEVANT, RELEVANT;
}
}