Support specifying multiple templates (#22139)
Problem: We introduced the ability to shorten the rank eval request by using a template in #20231. When playing with the API it turned out that there might be use cases where - e.g. due to various heuristics - folks might want to translate the original user query into more than just one type of Elasticsearch query. Solution: Give each template an id that can later be referenced in the actual requests. Closes #21257
This commit is contained in:
parent
b1e0d698ac
commit
bdc32be8b7
|
@ -80,12 +80,14 @@ GET /twitter/tweet/_rank_eval
|
|||
--------------------------------
|
||||
GET /twitter/tweet/_rank_eval
|
||||
{
|
||||
"templates": [{
|
||||
"id": "match_query",
|
||||
"template": {
|
||||
"inline": {
|
||||
"query": {
|
||||
"match": {
|
||||
"{{field}}": {
|
||||
"query": "{{query_string}}"}}}}}, <1>
|
||||
"query": "{{query_string}}"}}}}}}], <1>
|
||||
"requests": [
|
||||
{
|
||||
"id": "JFK query",
|
||||
|
@ -105,7 +107,8 @@ GET /twitter/tweet/_rank_eval
|
|||
"params": {
|
||||
"query_string": "JFK", <2>
|
||||
"field": "opening_text" <2>
|
||||
}
|
||||
},
|
||||
"template_id": "match_query"
|
||||
}],
|
||||
"metric": {
|
||||
"precision": {
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
package org.elasticsearch.index.rankeval;
|
||||
|
||||
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.io.stream.StreamInput;
|
||||
|
@ -34,6 +33,9 @@ import org.elasticsearch.script.Script;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
@ -49,10 +51,9 @@ public class RankEvalSpec extends ToXContentToBytes implements Writeable {
|
|||
/** Definition of the quality metric, e.g. precision at N */
|
||||
private RankedListQualityMetric metric;
|
||||
/** optional: Template to base test requests on */
|
||||
@Nullable
|
||||
private Script template;
|
||||
private Map<String, Script> templates = new HashMap<>();
|
||||
|
||||
public RankEvalSpec(Collection<RatedRequest> ratedRequests, RankedListQualityMetric metric, Script template) {
|
||||
public RankEvalSpec(Collection<RatedRequest> ratedRequests, RankedListQualityMetric metric, Collection<ScriptWithId> templates) {
|
||||
if (ratedRequests == null || ratedRequests.size() < 1) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot evaluate ranking if no search requests with rated results are provided. Seen: " + ratedRequests);
|
||||
|
@ -61,7 +62,7 @@ public class RankEvalSpec extends ToXContentToBytes implements Writeable {
|
|||
throw new IllegalStateException(
|
||||
"Cannot evaluate ranking if no evaluation metric is provided.");
|
||||
}
|
||||
if (template == null) {
|
||||
if (templates == null || templates.size() < 1) {
|
||||
for (RatedRequest request : ratedRequests) {
|
||||
if (request.getTestRequest() == null) {
|
||||
throw new IllegalStateException(
|
||||
|
@ -72,7 +73,11 @@ public class RankEvalSpec extends ToXContentToBytes implements Writeable {
|
|||
}
|
||||
this.ratedRequests = ratedRequests;
|
||||
this.metric = metric;
|
||||
this.template = template;
|
||||
if (templates != null) {
|
||||
for (ScriptWithId idScript : templates) {
|
||||
this.templates.put(idScript.id, idScript.script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RankEvalSpec(Collection<RatedRequest> ratedRequests, RankedListQualityMetric metric) {
|
||||
|
@ -80,29 +85,31 @@ public class RankEvalSpec extends ToXContentToBytes implements Writeable {
|
|||
}
|
||||
|
||||
public RankEvalSpec(StreamInput in) throws IOException {
|
||||
int specSize = in.readInt();
|
||||
int specSize = in.readVInt();
|
||||
ratedRequests = new ArrayList<>(specSize);
|
||||
for (int i = 0; i < specSize; i++) {
|
||||
ratedRequests.add(new RatedRequest(in));
|
||||
}
|
||||
metric = in.readNamedWriteable(RankedListQualityMetric.class);
|
||||
if (in.readBoolean()) {
|
||||
template = new Script(in);
|
||||
int size = in.readVInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
String key = in.readString();
|
||||
Script value = new Script(in);
|
||||
this.templates.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeInt(ratedRequests.size());
|
||||
out.writeVInt(ratedRequests.size());
|
||||
for (RatedRequest spec : ratedRequests) {
|
||||
spec.writeTo(out);
|
||||
}
|
||||
out.writeNamedWriteable(metric);
|
||||
if (template != null) {
|
||||
out.writeBoolean(true);
|
||||
template.writeTo(out);
|
||||
} else {
|
||||
out.writeBoolean(false);
|
||||
out.writeVInt(templates.size());
|
||||
for (Entry<String, Script> entry : templates.entrySet()) {
|
||||
out.writeString(entry.getKey());
|
||||
entry.getValue().writeTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,17 +124,17 @@ public class RankEvalSpec extends ToXContentToBytes implements Writeable {
|
|||
}
|
||||
|
||||
/** Returns the template to base test requests on. */
|
||||
public Script getTemplate() {
|
||||
return this.template;
|
||||
public Map<String, Script> getTemplates() {
|
||||
return this.templates;
|
||||
}
|
||||
|
||||
private static final ParseField TEMPLATE_FIELD = new ParseField("template");
|
||||
private static final ParseField TEMPLATES_FIELD = new ParseField("templates");
|
||||
private static final ParseField METRIC_FIELD = new ParseField("metric");
|
||||
private static final ParseField REQUESTS_FIELD = new ParseField("requests");
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final ConstructingObjectParser<RankEvalSpec, RankEvalContext> PARSER =
|
||||
new ConstructingObjectParser<>("rank_eval",
|
||||
a -> new RankEvalSpec((Collection<RatedRequest>) a[0], (RankedListQualityMetric) a[1], (Script) a[2]));
|
||||
a -> new RankEvalSpec((Collection<RatedRequest>) a[0], (RankedListQualityMetric) a[1], (Collection<ScriptWithId>) a[2]));
|
||||
|
||||
static {
|
||||
PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), (p, c) -> {
|
||||
|
@ -144,7 +151,41 @@ public class RankEvalSpec extends ToXContentToBytes implements Writeable {
|
|||
throw new ParsingException(p.getTokenLocation(), "error parsing rank request", ex);
|
||||
}
|
||||
} , METRIC_FIELD);
|
||||
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> {
|
||||
PARSER.declareObjectArray(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> {
|
||||
try {
|
||||
return ScriptWithId.fromXContent(p, c);
|
||||
} catch (IOException ex) {
|
||||
throw new ParsingException(p.getTokenLocation(), "error parsing rank request", ex);
|
||||
}
|
||||
}, TEMPLATES_FIELD);
|
||||
}
|
||||
|
||||
public static RankEvalSpec parse(XContentParser parser, RankEvalContext context) throws IOException {
|
||||
return PARSER.apply(parser, context);
|
||||
}
|
||||
|
||||
public static class ScriptWithId {
|
||||
private Script script;
|
||||
private String id;
|
||||
|
||||
private static final ParseField TEMPLATE_FIELD = new ParseField("template");
|
||||
private static final ParseField TEMPLATE_ID_FIELD = new ParseField("id");
|
||||
|
||||
public ScriptWithId(String id, Script script) {
|
||||
this.id = id;
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
private static final ConstructingObjectParser<ScriptWithId, RankEvalContext> PARSER =
|
||||
new ConstructingObjectParser<>("script_with_id", a -> new ScriptWithId((String) a[0], (Script) a[1]));
|
||||
|
||||
public static ScriptWithId fromXContent(XContentParser parser, RankEvalContext context) throws IOException {
|
||||
return PARSER.apply(parser, context);
|
||||
}
|
||||
|
||||
static {
|
||||
PARSER.declareString(ConstructingObjectParser.constructorArg(), TEMPLATE_ID_FIELD);
|
||||
PARSER.declareObject(ConstructingObjectParser.constructorArg(), (p, c) -> {
|
||||
try {
|
||||
return Script.parse(p, c.getParseFieldMatcher(), "mustache");
|
||||
} catch (IOException ex) {
|
||||
|
@ -152,17 +193,20 @@ public class RankEvalSpec extends ToXContentToBytes implements Writeable {
|
|||
}
|
||||
}, TEMPLATE_FIELD);
|
||||
}
|
||||
|
||||
public static RankEvalSpec parse(XContentParser parser, RankEvalContext context) throws IOException {
|
||||
return PARSER.apply(parser, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
if (this.template != null) {
|
||||
builder.field(TEMPLATE_FIELD.getPreferredName(), this.template);
|
||||
builder.startArray(TEMPLATES_FIELD.getPreferredName());
|
||||
for (Entry<String, Script> entry : templates.entrySet()) {
|
||||
builder.startObject();
|
||||
builder.field(ScriptWithId.TEMPLATE_ID_FIELD.getPreferredName(), entry.getKey());
|
||||
builder.field(ScriptWithId.TEMPLATE_FIELD.getPreferredName(), entry.getValue());
|
||||
builder.endObject();
|
||||
}
|
||||
builder.endArray();
|
||||
|
||||
builder.startArray(REQUESTS_FIELD.getPreferredName());
|
||||
for (RatedRequest spec : this.ratedRequests) {
|
||||
spec.toXContent(builder, params);
|
||||
|
@ -185,11 +229,11 @@ public class RankEvalSpec extends ToXContentToBytes implements Writeable {
|
|||
|
||||
return Objects.equals(ratedRequests, other.ratedRequests) &&
|
||||
Objects.equals(metric, other.metric) &&
|
||||
Objects.equals(template, other.template);
|
||||
Objects.equals(templates, other.templates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return Objects.hash(ratedRequests, metric, template);
|
||||
return Objects.hash(ratedRequests, metric, templates);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,16 +60,27 @@ public class RatedRequest extends ToXContentToBytes implements Writeable {
|
|||
private SearchSourceBuilder testRequest;
|
||||
/** Map of parameters to use for filling a query template, can be used instead of providing testRequest. */
|
||||
private Map<String, Object> params = new HashMap<>();
|
||||
@Nullable
|
||||
private String templateId;
|
||||
|
||||
public RatedRequest(String id, List<RatedDocument> ratedDocs, SearchSourceBuilder testRequest, Map<String, Object> params) {
|
||||
public RatedRequest(
|
||||
String id, List<RatedDocument> ratedDocs, SearchSourceBuilder testRequest, Map<String, Object> params, String templateId) {
|
||||
if (params != null && (params.size() > 0 && testRequest != null)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Ambiguous rated request: Set both, verbatim test request and test request template parameters.");
|
||||
}
|
||||
if (templateId != null && testRequest != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Ambiguous rated request: Set both, verbatim test request and test request template parameters.");
|
||||
}
|
||||
if ((params == null || params.size() < 1) && testRequest == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Need to set at least test request or test request template parameters.");
|
||||
}
|
||||
if ((params != null && params.size() > 0) && templateId == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"If template parameters are supplied need to set id of template to apply them to too.");
|
||||
}
|
||||
// No documents with same _index/_type/id allowed.
|
||||
Set<DocumentKey> docKeys = new HashSet<>();
|
||||
for (RatedDocument doc : ratedDocs) {
|
||||
|
@ -86,14 +97,15 @@ public class RatedRequest extends ToXContentToBytes implements Writeable {
|
|||
if (params != null) {
|
||||
this.params = params;
|
||||
}
|
||||
this.templateId = templateId;
|
||||
}
|
||||
|
||||
public RatedRequest(String id, List<RatedDocument> ratedDocs, Map<String, Object> params) {
|
||||
this(id, ratedDocs, null, params);
|
||||
public RatedRequest(String id, List<RatedDocument> ratedDocs, Map<String, Object> params, String templateId) {
|
||||
this(id, ratedDocs, null, params, templateId);
|
||||
}
|
||||
|
||||
public RatedRequest(String id, List<RatedDocument> ratedDocs, SearchSourceBuilder testRequest) {
|
||||
this(id, ratedDocs, testRequest, new HashMap<>());
|
||||
this(id, ratedDocs, testRequest, new HashMap<>(), null);
|
||||
}
|
||||
|
||||
public RatedRequest(StreamInput in) throws IOException {
|
||||
|
@ -121,6 +133,7 @@ public class RatedRequest extends ToXContentToBytes implements Writeable {
|
|||
for (int i = 0; i < summaryFieldsSize; i++) {
|
||||
this.summaryFields.add(in.readString());
|
||||
}
|
||||
this.templateId = in.readOptionalString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -145,6 +158,7 @@ public class RatedRequest extends ToXContentToBytes implements Writeable {
|
|||
for (String fieldName : summaryFields) {
|
||||
out.writeString(fieldName);
|
||||
}
|
||||
out.writeOptionalString(this.templateId);
|
||||
}
|
||||
|
||||
public SearchSourceBuilder getTestRequest() {
|
||||
|
@ -181,6 +195,10 @@ public class RatedRequest extends ToXContentToBytes implements Writeable {
|
|||
return this.params;
|
||||
}
|
||||
|
||||
public String getTemplateId() {
|
||||
return this.templateId;
|
||||
}
|
||||
|
||||
/** Returns a list of fields that are included in the docs summary of matched documents. */
|
||||
public List<String> getSummaryFields() {
|
||||
return summaryFields;
|
||||
|
@ -198,10 +216,11 @@ public class RatedRequest extends ToXContentToBytes implements Writeable {
|
|||
private static final ParseField RATINGS_FIELD = new ParseField("ratings");
|
||||
private static final ParseField PARAMS_FIELD = new ParseField("params");
|
||||
private static final ParseField FIELDS_FIELD = new ParseField("summary_fields");
|
||||
private static final ParseField TEMPLATE_ID_FIELD = new ParseField("template_id");
|
||||
|
||||
private static final ConstructingObjectParser<RatedRequest, RankEvalContext> PARSER =
|
||||
new ConstructingObjectParser<>("requests", a -> new RatedRequest(
|
||||
(String) a[0], (List<RatedDocument>) a[1], (SearchSourceBuilder) a[2], (Map<String, Object>) a[3]));
|
||||
(String) a[0], (List<RatedDocument>) a[1], (SearchSourceBuilder) a[2], (Map<String, Object>) a[3], (String) a[4]));
|
||||
|
||||
static {
|
||||
PARSER.declareString(ConstructingObjectParser.constructorArg(), ID_FIELD);
|
||||
|
@ -227,6 +246,7 @@ public class RatedRequest extends ToXContentToBytes implements Writeable {
|
|||
}
|
||||
}, PARAMS_FIELD);
|
||||
PARSER.declareStringArray(RatedRequest::setSummaryFields, FIELDS_FIELD);
|
||||
PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), TEMPLATE_ID_FIELD);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -278,6 +298,9 @@ public class RatedRequest extends ToXContentToBytes implements Writeable {
|
|||
}
|
||||
builder.endArray();
|
||||
}
|
||||
if (this.templateId != null) {
|
||||
builder.field(TEMPLATE_ID_FIELD.getPreferredName(), this.templateId);
|
||||
}
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
@ -299,11 +322,12 @@ public class RatedRequest extends ToXContentToBytes implements Writeable {
|
|||
Objects.equals(types, other.types) &&
|
||||
Objects.equals(summaryFields, other.summaryFields) &&
|
||||
Objects.equals(ratedDocs, other.ratedDocs) &&
|
||||
Objects.equals(params, other.params);
|
||||
Objects.equals(params, other.params) &&
|
||||
Objects.equals(templateId, other.templateId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return Objects.hash(id, testRequest, indices, types, summaryFields, ratedDocs, params);
|
||||
return Objects.hash(id, testRequest, indices, types, summaryFields, ratedDocs, params, templateId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,16 +21,13 @@ package org.elasticsearch.index.rankeval;
|
|||
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.common.Strings;
|
||||
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.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.RestActions;
|
||||
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.search.SearchRequestParsers;
|
||||
|
|
|
@ -33,6 +33,7 @@ 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.Script;
|
||||
import org.elasticsearch.script.ScriptContext;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
|
@ -46,6 +47,7 @@ import java.util.Collection;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
@ -84,9 +86,11 @@ 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<>());
|
||||
Map<String, CompiledScript> scriptsWithoutParams = new HashMap<>();
|
||||
for (Entry<String, Script> entry : qualityTask.getTemplates().entrySet()) {
|
||||
scriptsWithoutParams.put(
|
||||
entry.getKey(),
|
||||
scriptService.compile(entry.getValue(), ScriptContext.Standard.SEARCH, new HashMap<>()));
|
||||
}
|
||||
for (RatedRequest ratedRequest : specifications) {
|
||||
final RankEvalActionListener searchListener = new RankEvalActionListener(listener, qualityTask.getMetric(), ratedRequest,
|
||||
|
@ -94,7 +98,9 @@ public class TransportRankEvalAction extends HandledTransportAction<RankEvalRequ
|
|||
SearchSourceBuilder ratedSearchSource = ratedRequest.getTestRequest();
|
||||
if (ratedSearchSource == null) {
|
||||
Map<String, Object> params = ratedRequest.getParams();
|
||||
String resolvedRequest = ((BytesReference) (scriptService.executable(scriptWithoutParams, params).run())).utf8ToString();
|
||||
String templateId = ratedRequest.getTemplateId();
|
||||
CompiledScript compiled = scriptsWithoutParams.get(templateId);
|
||||
String resolvedRequest = ((BytesReference) (scriptService.executable(compiled, params).run())).utf8ToString();
|
||||
try (XContentParser subParser = XContentFactory.xContent(resolvedRequest).createParser(resolvedRequest)) {
|
||||
QueryParseContext parseContext = new QueryParseContext(searchRequestParsers.queryParsers, subParser, parseFieldMatcher);
|
||||
ratedSearchSource = SearchSourceBuilder.fromXContent(parseContext, searchRequestParsers.aggParsers,
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.elasticsearch.common.xcontent.XContentFactory;
|
|||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.index.rankeval.RankEvalSpec.ScriptWithId;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptType;
|
||||
|
@ -43,8 +44,10 @@ import org.junit.BeforeClass;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
@ -91,8 +94,9 @@ public class RankEvalSpecTests extends ESTestCase {
|
|||
metric = DiscountedCumulativeGainTests.createTestItem();
|
||||
}
|
||||
|
||||
Script template = null;
|
||||
List<RatedRequest> ratedRequests = null;
|
||||
Collection<ScriptWithId> templates = null;
|
||||
|
||||
if (randomBoolean()) {
|
||||
final Map<String, Object> params = randomBoolean() ? Collections.emptyMap() : Collections.singletonMap("key", "value");
|
||||
ScriptType scriptType = randomFrom(ScriptType.values());
|
||||
|
@ -108,20 +112,21 @@ public class RankEvalSpecTests extends ESTestCase {
|
|||
script = randomAsciiOfLengthBetween(1, 5);
|
||||
}
|
||||
|
||||
template = new Script(scriptType, randomFrom("_lang1", "_lang2"), script, params);
|
||||
templates = new HashSet<>();
|
||||
templates.add(
|
||||
new ScriptWithId("templateId", new Script(scriptType, randomFrom("_lang1", "_lang2"), script, params)));
|
||||
|
||||
Map<String, Object> templateParams = new HashMap<>();
|
||||
templateParams.put("key", "value");
|
||||
RatedRequest ratedRequest = new RatedRequest(
|
||||
"id", Arrays.asList(RatedDocumentTests.createRatedDocument()), templateParams);
|
||||
"id", Arrays.asList(RatedDocumentTests.createRatedDocument()), templateParams, "templateId");
|
||||
ratedRequests = Arrays.asList(ratedRequest);
|
||||
} else {
|
||||
RatedRequest ratedRequest = new RatedRequest(
|
||||
"id", Arrays.asList(RatedDocumentTests.createRatedDocument()), new SearchSourceBuilder());
|
||||
ratedRequests = Arrays.asList(ratedRequest);
|
||||
}
|
||||
|
||||
return new RankEvalSpec(ratedRequests, metric, template);
|
||||
return new RankEvalSpec(ratedRequests, metric, templates);
|
||||
}
|
||||
|
||||
public void testRoundtripping() throws IOException {
|
||||
|
@ -159,7 +164,7 @@ public class RankEvalSpecTests extends ESTestCase {
|
|||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("key", "value");
|
||||
|
||||
RatedRequest request = new RatedRequest("id", ratedDocs, params);
|
||||
RatedRequest request = new RatedRequest("id", ratedDocs, params, "templateId");
|
||||
List<RatedRequest> ratedRequests = Arrays.asList(request);
|
||||
|
||||
expectThrows(IllegalStateException.class, () -> new RankEvalSpec(ratedRequests, new Precision()));
|
||||
|
|
|
@ -107,7 +107,7 @@ public class RatedRequestsTests extends ESTestCase {
|
|||
ratedRequest.setTypes(types);
|
||||
ratedRequest.setSummaryFields(summaryFields);
|
||||
} else {
|
||||
ratedRequest = new RatedRequest(requestId, ratedDocs, params);
|
||||
ratedRequest = new RatedRequest(requestId, ratedDocs, params, randomAsciiOfLength(5));
|
||||
ratedRequest.setIndices(indices);
|
||||
ratedRequest.setTypes(types);
|
||||
ratedRequest.setSummaryFields(summaryFields);
|
||||
|
@ -200,8 +200,9 @@ public class RatedRequestsTests extends ESTestCase {
|
|||
List<String> types = original.getTypes();
|
||||
Map<String, Object> params = original.getParams();
|
||||
List<String> summaryFields = original.getSummaryFields();
|
||||
String templateId = original.getTemplateId();
|
||||
|
||||
int mutate = randomIntBetween(0, 6);
|
||||
int mutate = randomIntBetween(0, 7);
|
||||
switch (mutate) {
|
||||
case 0:
|
||||
id = randomValueOtherThan(id, () -> randomAsciiOfLength(10));
|
||||
|
@ -230,11 +231,14 @@ public class RatedRequestsTests extends ESTestCase {
|
|||
case 6:
|
||||
summaryFields = Arrays.asList(randomValueOtherThanMany(summaryFields::contains, () -> randomAsciiOfLength(10)));
|
||||
break;
|
||||
case 7:
|
||||
templateId = randomValueOtherThan(templateId, () -> randomAsciiOfLength(5));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Requested to modify more than available parameters.");
|
||||
}
|
||||
|
||||
RatedRequest ratedRequest = new RatedRequest(id, ratedDocs, testRequest, params);
|
||||
RatedRequest ratedRequest = new RatedRequest(id, ratedDocs, testRequest, params, templateId);
|
||||
ratedRequest.setIndices(indices);
|
||||
ratedRequest.setTypes(types);
|
||||
ratedRequest.setSummaryFields(summaryFields);
|
||||
|
@ -258,7 +262,7 @@ public class RatedRequestsTests extends ESTestCase {
|
|||
params.put("key", "value");
|
||||
ex = expectThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> new RatedRequest("id", ratedDocs, params));
|
||||
() -> new RatedRequest("id", ratedDocs, params, "templateId"));
|
||||
assertEquals(
|
||||
"Found duplicate rated document key [{ \"_index\" : \"index1\", \"_type\" : \"type1\", \"_id\" : \"id1\"}]",
|
||||
ex.getMessage());
|
||||
|
@ -272,7 +276,7 @@ public class RatedRequestsTests extends ESTestCase {
|
|||
|
||||
public void testNullParamsTreatment() {
|
||||
List<RatedDocument> ratedDocs = Arrays.asList(new RatedDocument(new DocumentKey("index1", "type1", "id1"), 1));
|
||||
RatedRequest request = new RatedRequest("id", ratedDocs, new SearchSourceBuilder(), null);
|
||||
RatedRequest request = new RatedRequest("id", ratedDocs, new SearchSourceBuilder(), null, null);
|
||||
assertNotNull(request.getParams());
|
||||
}
|
||||
|
||||
|
@ -281,13 +285,33 @@ public class RatedRequestsTests extends ESTestCase {
|
|||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("key", "value");
|
||||
expectThrows(IllegalArgumentException.class,
|
||||
() -> new RatedRequest("id", ratedDocs, new SearchSourceBuilder(), params));
|
||||
() -> new RatedRequest("id", ratedDocs, new SearchSourceBuilder(), params, null));
|
||||
}
|
||||
|
||||
public void testSettingNeitherParamsNorRequestThrows() {
|
||||
List<RatedDocument> ratedDocs = Arrays.asList(new RatedDocument(new DocumentKey("index1", "type1", "id1"), 1));
|
||||
expectThrows(IllegalArgumentException.class, () -> new RatedRequest("id", ratedDocs, null, null));
|
||||
expectThrows(IllegalArgumentException.class, () -> new RatedRequest("id", ratedDocs, null, new HashMap<>()));
|
||||
expectThrows(IllegalArgumentException.class, () -> new RatedRequest("id", ratedDocs, null, new HashMap<>(), "templateId"));
|
||||
}
|
||||
|
||||
public void testSettingParamsWithoutTemplateIdThrows() {
|
||||
List<RatedDocument> ratedDocs = Arrays.asList(new RatedDocument(new DocumentKey("index1", "type1", "id1"), 1));
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("key", "value");
|
||||
expectThrows(IllegalArgumentException.class,
|
||||
() -> new RatedRequest("id", ratedDocs, null, params, null));
|
||||
}
|
||||
|
||||
public void testSettingTemplateIdAndRequestThrows() {
|
||||
List<RatedDocument> ratedDocs = Arrays.asList(new RatedDocument(new DocumentKey("index1", "type1", "id1"), 1));
|
||||
expectThrows(IllegalArgumentException.class,
|
||||
() -> new RatedRequest("id", ratedDocs, new SearchSourceBuilder(), null, "templateId"));
|
||||
}
|
||||
|
||||
public void testSettingTemplateIdNoParamsThrows() {
|
||||
List<RatedDocument> ratedDocs = Arrays.asList(new RatedDocument(new DocumentKey("index1", "type1", "id1"), 1));
|
||||
expectThrows(IllegalArgumentException.class,
|
||||
() -> new RatedRequest("id", ratedDocs, null, null, "templateId"));
|
||||
}
|
||||
|
||||
public void testParseFromXContent() throws IOException {
|
||||
|
|
|
@ -28,6 +28,7 @@ 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.index.rankeval.RankEvalSpec.ScriptWithId;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptType;
|
||||
|
@ -39,12 +40,16 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class SmokeMultipleTemplatesIT extends ESIntegTestCase {
|
||||
|
||||
private static final String MATCH_TEMPLATE = "match_template";
|
||||
|
||||
@Override
|
||||
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
|
||||
return Arrays.asList(RankEvalPlugin.class);
|
||||
|
@ -82,7 +87,8 @@ public class SmokeMultipleTemplatesIT extends ESIntegTestCase {
|
|||
List<RatedRequest> specifications = new ArrayList<>();
|
||||
Map<String, Object> ams_params = new HashMap<>();
|
||||
ams_params.put("querystring", "amsterdam");
|
||||
RatedRequest amsterdamRequest = new RatedRequest("amsterdam_query", createRelevant("2", "3", "4", "5"), ams_params);
|
||||
RatedRequest amsterdamRequest = new RatedRequest(
|
||||
"amsterdam_query", createRelevant("2", "3", "4", "5"), ams_params, MATCH_TEMPLATE);
|
||||
amsterdamRequest.setIndices(indices);
|
||||
amsterdamRequest.setTypes(types);
|
||||
|
||||
|
@ -90,19 +96,24 @@ public class SmokeMultipleTemplatesIT extends ESIntegTestCase {
|
|||
|
||||
Map<String, Object> berlin_params = new HashMap<>();
|
||||
berlin_params.put("querystring", "berlin");
|
||||
RatedRequest berlinRequest = new RatedRequest("berlin_query", createRelevant("1"), berlin_params);
|
||||
RatedRequest berlinRequest = new RatedRequest(
|
||||
"berlin_query", createRelevant("1"), berlin_params, MATCH_TEMPLATE);
|
||||
berlinRequest.setIndices(indices);
|
||||
berlinRequest.setTypes(types);
|
||||
specifications.add(berlinRequest);
|
||||
|
||||
Precision metric = new Precision();
|
||||
|
||||
Script template =
|
||||
ScriptWithId template =
|
||||
new ScriptWithId(
|
||||
MATCH_TEMPLATE,
|
||||
new Script(
|
||||
ScriptType.INLINE,
|
||||
"mustache", "{\"query\": {\"match\": {\"text\": \"{{querystring}}\"}}}",
|
||||
new HashMap<>());
|
||||
RankEvalSpec task = new RankEvalSpec(specifications, metric, template);
|
||||
new HashMap<>()));
|
||||
Set<ScriptWithId> templates = new HashSet<>();
|
||||
templates.add(template);
|
||||
RankEvalSpec task = new RankEvalSpec(specifications, metric, templates);
|
||||
RankEvalRequestBuilder builder = new RankEvalRequestBuilder(client(), RankEvalAction.INSTANCE, new RankEvalRequest());
|
||||
builder.setRankEvalSpec(task);
|
||||
|
||||
|
|
|
@ -41,13 +41,12 @@
|
|||
- do:
|
||||
rank_eval:
|
||||
body: {
|
||||
"template": {
|
||||
"inline": "{\"query\": { \"match\" : {\"text\" : \"{{query_string}}\" }}}"
|
||||
},
|
||||
"templates": [ { "id": "match", "template": {"inline": "{\"query\": { \"match\" : {\"text\" : \"{{query_string}}\" }}}" }} ],
|
||||
"requests" : [
|
||||
{
|
||||
"id": "amsterdam_query",
|
||||
"params": { "query_string": "amsterdam" },
|
||||
"template_id": "match",
|
||||
"ratings": [
|
||||
{"_index": "foo", "_type": "bar", "_id": "doc1", "rating": 0},
|
||||
{"_index": "foo", "_type": "bar", "_id": "doc2", "rating": 1},
|
||||
|
@ -56,6 +55,7 @@
|
|||
{
|
||||
"id" : "berlin_query",
|
||||
"params": { "query_string": "berlin" },
|
||||
"template_id": "match",
|
||||
"ratings": [{"_index": "foo", "_type": "bar", "_id": "doc1", "rating": 1}]
|
||||
}
|
||||
],
|
||||
|
|
Loading…
Reference in New Issue