From 7dc1c3349d392eaae06ac9420a1e28579ca0de13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Mon, 12 Sep 2016 15:43:32 +0200 Subject: [PATCH] Remove nested `key` field for rated documents Every rated document needs an index/type/id parameter, so adding a "key" object like we currently do only leads to an additional unneeded level of nesting in the rest request. Closes #20417 --- .../index/rankeval/RankEvalResponse.java | 17 +++-- .../index/rankeval/RatedDocument.java | 65 ++++++++++--------- .../index/rankeval/RatedDocumentKey.java | 41 +----------- .../index/rankeval/RestRankEvalAction.java | 40 +++++------- .../DiscountedCumulativeGainAtTests.java | 6 +- .../index/rankeval/PrecisionAtNTests.java | 42 ++++++------ .../index/rankeval/RankEvalRequestTests.java | 2 +- .../index/rankeval/RankEvalResponseTests.java | 14 ++++ .../index/rankeval/RatedDocumentKeyTests.java | 41 +++++++++--- .../index/rankeval/RatedDocumentTests.java | 2 +- .../index/rankeval/RatedRequestsTests.java | 25 +++---- .../index/rankeval/ReciprocalRankTests.java | 26 +++----- .../test/rank_eval/10_basic.yaml | 20 +++--- .../rest-api-spec/test/rank_eval/20_dcg.yaml | 48 +++++++------- 14 files changed, 197 insertions(+), 192 deletions(-) diff --git a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalResponse.java b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalResponse.java index 9d58d47847f..48e1406b1f6 100644 --- a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalResponse.java +++ b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalResponse.java @@ -117,13 +117,20 @@ public class RankEvalResponse extends ActionResponse implements ToXContent { builder.startObject("rank_eval"); builder.field("spec_id", specId); builder.field("quality_level", qualityLevel); - builder.startArray("unknown_docs"); + builder.startObject("unknown_docs"); for (String key : unknownDocs.keySet()) { - builder.startObject(); - builder.field(key, unknownDocs.get(key)); - builder.endObject(); + Collection keys = unknownDocs.get(key); + builder.startArray(key); + for (RatedDocumentKey docKey : keys) { + builder.startObject(); + builder.field(RatedDocument.INDEX_FIELD.getPreferredName(), docKey.getIndex()); + builder.field(RatedDocument.TYPE_FIELD.getPreferredName(), docKey.getType()); + builder.field(RatedDocument.DOC_ID_FIELD.getPreferredName(), docKey.getDocID()); + builder.endObject(); + } + builder.endArray(); } - builder.endArray(); + builder.endObject(); builder.endObject(); return builder; } diff --git a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RatedDocument.java b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RatedDocument.java index 1cde3828507..d8af409445c 100644 --- a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RatedDocument.java +++ b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RatedDocument.java @@ -22,7 +22,6 @@ package org.elasticsearch.index.rankeval; import org.elasticsearch.action.support.ToXContentToBytes; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseFieldMatcherSupplier; -import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; @@ -39,41 +38,26 @@ import java.util.Objects; public class RatedDocument extends ToXContentToBytes implements Writeable { public static final ParseField RATING_FIELD = new ParseField("rating"); - public static final ParseField KEY_FIELD = new ParseField("key"); + public static final ParseField DOC_ID_FIELD = new ParseField("doc_id"); + public static final ParseField TYPE_FIELD = new ParseField("type"); + public static final ParseField INDEX_FIELD = new ParseField("index"); private static final ConstructingObjectParser PARSER = - new ConstructingObjectParser<>("rated_document", - a -> new RatedDocument((RatedDocumentKey) a[0], (Integer) a[1])); - + new ConstructingObjectParser<>("rated_document", + a -> new RatedDocument((String) a[0], (String) a[1], (String) a[2], (Integer) a[3])); + static { - PARSER.declareObject(ConstructingObjectParser.constructorArg(), (p, c) -> { - try { - return RatedDocumentKey.fromXContent(p, c); - } catch (IOException ex) { - throw new ParsingException(p.getTokenLocation(), "error parsing rank request", ex); - } - } , KEY_FIELD); + PARSER.declareString(ConstructingObjectParser.constructorArg(), INDEX_FIELD); + PARSER.declareString(ConstructingObjectParser.constructorArg(), TYPE_FIELD); + PARSER.declareString(ConstructingObjectParser.constructorArg(), DOC_ID_FIELD); PARSER.declareInt(ConstructingObjectParser.constructorArg(), RATING_FIELD); } - private RatedDocumentKey key; private int rating; + private RatedDocumentKey key; - void setRatedDocumentKey(RatedDocumentKey key) { - this.key = key; - } - - void setKey(RatedDocumentKey key) { - this.key = key; - } - - void setRating(int rating) { - this.rating = rating; - } - - public RatedDocument(RatedDocumentKey key, int rating) { - this.key = key; - this.rating = rating; + public RatedDocument(String index, String type, String docId, int rating) { + this(new RatedDocumentKey(index, type, docId), rating); } public RatedDocument(StreamInput in) throws IOException { @@ -81,10 +65,27 @@ public class RatedDocument extends ToXContentToBytes implements Writeable { this.rating = in.readVInt(); } + public RatedDocument(RatedDocumentKey ratedDocumentKey, int rating) { + this.key = ratedDocumentKey; + this.rating = rating; + } + public RatedDocumentKey getKey() { return this.key; } + public String getIndex() { + return key.getIndex(); + } + + public String getType() { + return key.getType(); + } + + public String getDocID() { + return key.getDocID(); + } + public int getRating() { return rating; } @@ -98,11 +99,13 @@ public class RatedDocument extends ToXContentToBytes implements Writeable { public static RatedDocument fromXContent(XContentParser parser, ParseFieldMatcherSupplier supplier) throws IOException { return PARSER.apply(parser, supplier); } - + @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); - builder.field(KEY_FIELD.getPreferredName(), key); + builder.field(INDEX_FIELD.getPreferredName(), key.getIndex()); + builder.field(TYPE_FIELD.getPreferredName(), key.getType()); + builder.field(DOC_ID_FIELD.getPreferredName(), key.getDocID()); builder.field(RATING_FIELD.getPreferredName(), rating); builder.endObject(); return builder; @@ -120,7 +123,7 @@ public class RatedDocument extends ToXContentToBytes implements Writeable { return Objects.equals(key, other.key) && Objects.equals(rating, other.rating); } - + @Override public final int hashCode() { return Objects.hash(key, rating); diff --git a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RatedDocumentKey.java b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RatedDocumentKey.java index 5e69f902dea..ee08cf018da 100644 --- a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RatedDocumentKey.java +++ b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RatedDocumentKey.java @@ -19,45 +19,15 @@ package org.elasticsearch.index.rankeval; -import org.elasticsearch.action.support.ToXContentToBytes; -import org.elasticsearch.common.ParseField; -import org.elasticsearch.common.ParseFieldMatcherSupplier; 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.ConstructingObjectParser; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; import java.util.Objects; -public class RatedDocumentKey extends ToXContentToBytes implements Writeable { - public static final ParseField DOC_ID_FIELD = new ParseField("doc_id"); - public static final ParseField TYPE_FIELD = new ParseField("type"); - public static final ParseField INDEX_FIELD = new ParseField("index"); +public class RatedDocumentKey implements Writeable { - private static final ConstructingObjectParser PARSER = - new ConstructingObjectParser<>("ratings", - a -> new RatedDocumentKey((String) a[0], (String) a[1], (String) a[2])); - - static { - PARSER.declareString(ConstructingObjectParser.constructorArg(), INDEX_FIELD); - PARSER.declareString(ConstructingObjectParser.constructorArg(), TYPE_FIELD); - PARSER.declareString(ConstructingObjectParser.constructorArg(), DOC_ID_FIELD); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.field(INDEX_FIELD.getPreferredName(), index); - builder.field(TYPE_FIELD.getPreferredName(), type); - builder.field(DOC_ID_FIELD.getPreferredName(), docId); - builder.endObject(); - return builder; - } - - // TODO instead of docId use path to id and id itself private String docId; private String type; private String index; @@ -69,7 +39,7 @@ public class RatedDocumentKey extends ToXContentToBytes implements Writeable { void setType(String type) { this.type = type; } - + void setDocId(String docId) { this.docId = docId; } @@ -105,11 +75,6 @@ public class RatedDocumentKey extends ToXContentToBytes implements Writeable { out.writeString(docId); } - public static RatedDocumentKey fromXContent( - XContentParser parser, ParseFieldMatcherSupplier context) throws IOException { - return PARSER.apply(parser, context); - } - @Override public final boolean equals(Object obj) { if (this == obj) { @@ -123,7 +88,7 @@ public class RatedDocumentKey extends ToXContentToBytes implements Writeable { Objects.equals(type, other.type) && Objects.equals(docId, other.docId); } - + @Override public final int hashCode() { return Objects.hash(index, type, docId); diff --git a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RestRankEvalAction.java b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RestRankEvalAction.java index e3e5941c969..aebede0ff50 100644 --- a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RestRankEvalAction.java +++ b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RestRankEvalAction.java @@ -69,7 +69,7 @@ import static org.elasticsearch.rest.RestRequest.Method.POST; "requests": [{ "id": "amsterdam_query", "request": { - "query": { + "query": { "bool": { "must": [ {"match": {"beverage": "coffee"}}, @@ -78,15 +78,12 @@ import static org.elasticsearch.rest.RestRequest.Method.POST; {"term": {"ip_location": {"value": "ams","boost": 10}}}]} }, "size": 10 - } }, - "ratings": { - "1": 1, - "2": 0, - "3": 1, - "4": 1 - } - } + "ratings": [ + {\"index\": \"test\", \"type\": \"my_type\", \"doc_id\": \"1\", \"rating\" : 1 }, + {\"index\": \"test\", \"type\": \"my_type\", \"doc_id\": \"2\", \"rating\" : 0 }, + {\"index\": \"test\", \"type\": \"my_type\", \"doc_id\": \"3\", \"rating\" : 1 } + ] }, { "id": "berlin_query", "request": { @@ -99,13 +96,8 @@ import static org.elasticsearch.rest.RestRequest.Method.POST; {"term": {"ip_location": {"value": "ber","boost": 10}}}]} }, "size": 10 - } }, - "ratings": { - "1": 0, - "5": 1, - "6": 1 - } + "ratings": [ ... ] }], "metric": { "precisionAtN": { @@ -129,7 +121,7 @@ import static org.elasticsearch.rest.RestRequest.Method.POST; "failed": 0 }, "quality_level": ... quality level ..., - "unknown_docs": [{"user_request_id": [... list of unknown docs ...]}] + "unknown_docs": {"user_request_id": [... list of unknown docs ...]} } * @@ -148,11 +140,17 @@ import static org.elasticsearch.rest.RestRequest.Method.POST; "rank_eval": [{ "spec_id": "huge_weight_on_location", "quality_level": 0.4, - "unknown_docs": [{ - "amsterdam_query": [5, 10, 23] + "unknown_docs": { + "amsterdam_query": [ + { "index" : "test", "type" : "my_type", "doc_id" : "21"}, + { "index" : "test", "type" : "my_type", "doc_id" : "5"}, + { "index" : "test", "type" : "my_type", "doc_id" : "9"} + ] }, { - "berlin_query": [42] - }] + "berlin_query": [ + { "index" : "test", "type" : "my_type", "doc_id" : "42"} + ] + } }] } @@ -189,8 +187,6 @@ public class RestRankEvalAction extends BaseRestHandler { client.execute(RankEvalAction.INSTANCE, rankEvalRequest, new RestToXContentListener(channel)); } - - public static void parseRankEvalRequest(RankEvalRequest rankEvalRequest, RestRequest request, RankEvalContext context) throws IOException { List indices = Arrays.asList(Strings.splitStringByCommaToArray(request.param("index"))); diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGainAtTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGainAtTests.java index 1ef63e16405..8ae55e314ac 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGainAtTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGainAtTests.java @@ -55,7 +55,7 @@ public class DiscountedCumulativeGainAtTests extends ESTestCase { int[] relevanceRatings = new int[] { 3, 2, 3, 0, 1, 2 }; InternalSearchHit[] hits = new InternalSearchHit[6]; for (int i = 0; i < 6; i++) { - rated.add(new RatedDocument(new RatedDocumentKey("index", "type", Integer.toString(i)), relevanceRatings[i])); + rated.add(new RatedDocument("index", "type", Integer.toString(i), relevanceRatings[i])); hits[i] = new InternalSearchHit(i, Integer.toString(i), new Text("type"), Collections.emptyMap()); hits[i].shard(new SearchShardTarget("testnode", new ShardId("index", "uuid", 0))); } @@ -100,7 +100,7 @@ public class DiscountedCumulativeGainAtTests extends ESTestCase { InternalSearchHit[] hits = new InternalSearchHit[6]; for (int i = 0; i < 6; i++) { if (i < relevanceRatings.length) { - rated.add(new RatedDocument(new RatedDocumentKey("index", "type", Integer.toString(i)), relevanceRatings[i])); + rated.add(new RatedDocument("index", "type", Integer.toString(i), relevanceRatings[i])); } hits[i] = new InternalSearchHit(i, Integer.toString(i), new Text("type"), Collections.emptyMap()); hits[i].shard(new SearchShardTarget("testnode", new ShardId("index", "uuid", 0))); @@ -121,7 +121,7 @@ public class DiscountedCumulativeGainAtTests extends ESTestCase { assertEquals(8, dcgAt.getPosition()); assertEquals(true, dcgAt.getNormalize()); } - + public static DiscountedCumulativeGainAt createTestItem() { int position = randomIntBetween(0, 1000); boolean normalize = randomBoolean(); diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/PrecisionAtNTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/PrecisionAtNTests.java index 14a4be5ec38..bc78484832f 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/PrecisionAtNTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/PrecisionAtNTests.java @@ -42,7 +42,7 @@ public class PrecisionAtNTests extends ESTestCase { public void testPrecisionAtFiveCalculation() throws IOException, InterruptedException, ExecutionException { List rated = new ArrayList<>(); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "0"), Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test", "testtype", "0", Rating.RELEVANT.ordinal())); InternalSearchHit[] hits = new InternalSearchHit[1]; hits[0] = new InternalSearchHit(0, "0", new Text("testtype"), Collections.emptyMap()); hits[0].shard(new SearchShardTarget("testnode", new Index("test", "uuid"), 0)); @@ -51,11 +51,11 @@ public class PrecisionAtNTests extends ESTestCase { public void testPrecisionAtFiveIgnoreOneResult() throws IOException, InterruptedException, ExecutionException { List rated = new ArrayList<>(); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "0"), Rating.RELEVANT.ordinal())); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "1"), Rating.RELEVANT.ordinal())); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "2"), Rating.RELEVANT.ordinal())); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "3"), Rating.RELEVANT.ordinal())); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "4"), Rating.IRRELEVANT.ordinal())); + rated.add(new RatedDocument("test", "testtype", "0", Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test", "testtype", "1", Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test", "testtype", "2", Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test", "testtype", "3", Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test", "testtype", "4", Rating.IRRELEVANT.ordinal())); InternalSearchHit[] hits = new InternalSearchHit[5]; for (int i = 0; i < 5; i++) { hits[i] = new InternalSearchHit(i, i+"", new Text("testtype"), Collections.emptyMap()); @@ -70,11 +70,11 @@ public class PrecisionAtNTests extends ESTestCase { */ public void testPrecisionAtFiveRelevanceThreshold() throws IOException, InterruptedException, ExecutionException { List rated = new ArrayList<>(); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "0"), 0)); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "1"), 1)); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "2"), 2)); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "3"), 3)); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "4"), 4)); + rated.add(new RatedDocument("test", "testtype", "0", 0)); + rated.add(new RatedDocument("test", "testtype", "1", 1)); + rated.add(new RatedDocument("test", "testtype", "2", 2)); + rated.add(new RatedDocument("test", "testtype", "3", 3)); + rated.add(new RatedDocument("test", "testtype", "4", 4)); InternalSearchHit[] hits = new InternalSearchHit[5]; for (int i = 0; i < 5; i++) { hits[i] = new InternalSearchHit(i, i+"", new Text("testtype"), Collections.emptyMap()); @@ -87,11 +87,11 @@ public class PrecisionAtNTests extends ESTestCase { public void testPrecisionAtFiveCorrectIndex() throws IOException, InterruptedException, ExecutionException { List rated = new ArrayList<>(); - rated.add(new RatedDocument(new RatedDocumentKey("test_other", "testtype", "0"), Rating.RELEVANT.ordinal())); - rated.add(new RatedDocument(new RatedDocumentKey("test_other", "testtype", "1"), Rating.RELEVANT.ordinal())); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "2"), Rating.RELEVANT.ordinal())); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "3"), Rating.RELEVANT.ordinal())); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "4"), Rating.IRRELEVANT.ordinal())); + rated.add(new RatedDocument("test_other", "testtype", "0", Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test_other", "testtype", "1", Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test", "testtype", "2", Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test", "testtype", "3", Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test", "testtype", "4", Rating.IRRELEVANT.ordinal())); InternalSearchHit[] hits = new InternalSearchHit[5]; for (int i = 0; i < 5; i++) { hits[i] = new InternalSearchHit(i, i+"", new Text("testtype"), Collections.emptyMap()); @@ -102,11 +102,11 @@ public class PrecisionAtNTests extends ESTestCase { public void testPrecisionAtFiveCorrectType() throws IOException, InterruptedException, ExecutionException { List rated = new ArrayList<>(); - rated.add(new RatedDocument(new RatedDocumentKey("test", "other_type", "0"), Rating.RELEVANT.ordinal())); - rated.add(new RatedDocument(new RatedDocumentKey("test", "other_type", "1"), Rating.RELEVANT.ordinal())); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "2"), Rating.RELEVANT.ordinal())); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "3"), Rating.RELEVANT.ordinal())); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "4"), Rating.IRRELEVANT.ordinal())); + rated.add(new RatedDocument("test", "other_type", "0", Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test", "other_type", "1", Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test", "testtype", "2", Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test", "testtype", "3", Rating.RELEVANT.ordinal())); + rated.add(new RatedDocument("test", "testtype", "4", Rating.IRRELEVANT.ordinal())); InternalSearchHit[] hits = new InternalSearchHit[5]; for (int i = 0; i < 5; i++) { hits[i] = new InternalSearchHit(i, i+"", new Text("testtype"), Collections.emptyMap()); diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalRequestTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalRequestTests.java index 3a61b3c98ec..bb49debf6fe 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalRequestTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalRequestTests.java @@ -125,7 +125,7 @@ public class RankEvalRequestTests extends ESIntegTestCase { private static List createRelevant(String... docs) { List relevant = new ArrayList<>(); for (String doc : docs) { - relevant.add(new RatedDocument(new RatedDocumentKey("test", "testtype", doc), Rating.RELEVANT.ordinal())); + relevant.add(new RatedDocument("test", "testtype", doc, Rating.RELEVANT.ordinal())); } return relevant; } diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java index 89e63b0b6f0..67119e2789f 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java @@ -21,6 +21,10 @@ package org.elasticsearch.index.rankeval; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.test.ESTestCase; import java.io.IOException; @@ -61,4 +65,14 @@ public class RankEvalResponseTests extends ESTestCase { } } + public void testToXContent() throws IOException { + RankEvalResponse randomResponse = createRandomResponse(); + XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON); + if (ESTestCase.randomBoolean()) { + builder.prettyPrint(); + } + builder.startObject(); + randomResponse.toXContent(builder, ToXContent.EMPTY_PARAMS); + builder.endObject(); + } } diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedDocumentKeyTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedDocumentKeyTests.java index 6c0bd766b35..26661c086a6 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedDocumentKeyTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedDocumentKeyTests.java @@ -19,24 +19,49 @@ package org.elasticsearch.index.rankeval; -import org.elasticsearch.common.ParseFieldMatcher; -import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.test.ESTestCase; import java.io.IOException; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; + public class RatedDocumentKeyTests extends ESTestCase { - public void testXContentRoundtrip() throws IOException { + public void testEqualsAndHash() throws IOException { String index = randomAsciiOfLengthBetween(0, 10); String type = randomAsciiOfLengthBetween(0, 10); String docId = randomAsciiOfLengthBetween(0, 10); RatedDocumentKey testItem = new RatedDocumentKey(index, type, docId); - XContentParser itemParser = XContentTestHelper.roundtrip(testItem); - RatedDocumentKey parsedItem = RatedDocumentKey.fromXContent(itemParser, () -> ParseFieldMatcher.STRICT); - assertNotSame(testItem, parsedItem); - assertEquals(testItem, parsedItem); - assertEquals(testItem.hashCode(), parsedItem.hashCode()); + + assertFalse("key is equal to null", testItem.equals(null)); + assertFalse("key is equal to incompatible type", testItem.equals("")); + assertTrue("key is not equal to self", testItem.equals(testItem)); + assertThat("same key's hashcode returns different values if called multiple times", testItem.hashCode(), + equalTo(testItem.hashCode())); + + RatedDocumentKey mutation; + switch (randomIntBetween(0, 2)) { + case 0: + mutation = new RatedDocumentKey(testItem.getIndex() + "_foo", testItem.getType(), testItem.getDocID()); + break; + case 1: + mutation = new RatedDocumentKey(testItem.getIndex(), testItem.getType() + "_foo", testItem.getDocID()); + break; + case 2: + mutation = new RatedDocumentKey(testItem.getIndex(), testItem.getType(), testItem.getDocID() + "_foo"); + break; + default: + throw new IllegalStateException("The test should only allow three parameters mutated"); + } + + assertThat("different keys should not be equal", mutation, not(equalTo(testItem))); + + RatedDocumentKey secondEqualKey = new RatedDocumentKey(index, type, docId); + assertTrue("key is not equal to its copy", testItem.equals(secondEqualKey)); + assertTrue("equals is not symmetric", secondEqualKey.equals(testItem)); + assertThat("key copy's hashcode is different from original hashcode", secondEqualKey.hashCode(), + equalTo(testItem.hashCode())); } } diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedDocumentTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedDocumentTests.java index 3084682ad75..b3af34423c7 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedDocumentTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedDocumentTests.java @@ -33,7 +33,7 @@ public class RatedDocumentTests extends ESTestCase { String docId = randomAsciiOfLength(10); int rating = randomInt(); - return new RatedDocument(new RatedDocumentKey(index, type, docId), rating); + return new RatedDocument(index, type, docId, rating); } public void testXContentParsing() throws IOException { diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedRequestsTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedRequestsTests.java index d8f901cfb33..dd7a7d02ac0 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedRequestsTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedRequestsTests.java @@ -112,6 +112,7 @@ public class RatedRequestsTests extends ESTestCase { } public void testParseFromXContent() throws IOException { + // we modify the order of index/type/docId to make sure it doesn't matter for parsing xContent String querySpecString = " {\n" + " \"id\": \"my_qa_query\",\n" + " \"request\": {\n" @@ -126,9 +127,9 @@ public class RatedRequestsTests extends ESTestCase { + " \"size\": 10\n" + " },\n" + " \"ratings\": [ " - + " {\"key\": {\"index\": \"test\", \"type\": \"testtype\", \"doc_id\": \"1\"}, \"rating\" : 1 }, " - + " {\"key\": {\"index\": \"test\", \"type\": \"testtype\", \"doc_id\": \"2\"}, \"rating\" : 0 }, " - + " {\"key\": {\"index\": \"test\", \"type\": \"testtype\", \"doc_id\": \"3\"}, \"rating\" : 1 }]\n" + + " {\"index\": \"test\", \"type\": \"testtype\", \"doc_id\": \"1\", \"rating\" : 1 }, " + + " {\"type\": \"testtype\", \"index\": \"test\", \"doc_id\": \"2\", \"rating\" : 0 }, " + + " {\"doc_id\": \"3\", \"index\": \"test\", \"type\": \"testtype\", \"rating\" : 1 }]\n" + "}"; XContentParser parser = XContentFactory.xContent(querySpecString).createParser(querySpecString); QueryParseContext queryContext = new QueryParseContext(searchRequestParsers.queryParsers, parser, ParseFieldMatcher.STRICT); @@ -139,13 +140,15 @@ public class RatedRequestsTests extends ESTestCase { assertNotNull(specification.getTestRequest()); List ratedDocs = specification.getRatedDocs(); assertEquals(3, ratedDocs.size()); - assertEquals("1", ratedDocs.get(0).getKey().getDocID()); - assertEquals(1, ratedDocs.get(0).getRating()); - assertEquals("2", ratedDocs.get(1).getKey().getDocID()); - assertEquals(0, ratedDocs.get(1).getRating()); - assertEquals("3", ratedDocs.get(2).getKey().getDocID()); - assertEquals(1, ratedDocs.get(2).getRating()); + for (int i = 0; i < 3; i++) { + assertEquals("" + (i + 1), ratedDocs.get(i).getDocID()); + assertEquals("test", ratedDocs.get(i).getIndex()); + assertEquals("testtype", ratedDocs.get(i).getType()); + if (i == 1) { + assertEquals(0, ratedDocs.get(i).getRating()); + } else { + assertEquals(1, ratedDocs.get(i).getRating()); + } + } } - - } diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/ReciprocalRankTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/ReciprocalRankTests.java index 40fb7a05eea..c3f951b09b4 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/ReciprocalRankTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/ReciprocalRankTests.java @@ -56,13 +56,9 @@ public class ReciprocalRankTests extends ESTestCase { int relevantAt = 5; for (int i = 0; i < 10; i++) { if (i == relevantAt) { - ratedDocs.add(new RatedDocument( - new RatedDocumentKey("test", "type", Integer.toString(i)), - Rating.RELEVANT.ordinal())); + ratedDocs.add(new RatedDocument("test", "type", Integer.toString(i), Rating.RELEVANT.ordinal())); } else { - ratedDocs.add(new RatedDocument( - new RatedDocumentKey("test", "type", Integer.toString(i)), - Rating.IRRELEVANT.ordinal())); + ratedDocs.add(new RatedDocument("test", "type", Integer.toString(i), Rating.IRRELEVANT.ordinal())); } } @@ -93,13 +89,9 @@ public class ReciprocalRankTests extends ESTestCase { int relevantAt = randomIntBetween(0, 9); for (int i = 0; i <= 20; i++) { if (i == relevantAt) { - ratedDocs.add(new RatedDocument( - new RatedDocumentKey("test", "type", Integer.toString(i)), - Rating.RELEVANT.ordinal())); + ratedDocs.add(new RatedDocument("test", "type", Integer.toString(i), Rating.RELEVANT.ordinal())); } else { - ratedDocs.add(new RatedDocument( - new RatedDocumentKey("test", "type", Integer.toString(i)), - Rating.IRRELEVANT.ordinal())); + ratedDocs.add(new RatedDocument("test", "type", Integer.toString(i), Rating.IRRELEVANT.ordinal())); } } @@ -114,11 +106,11 @@ public class ReciprocalRankTests extends ESTestCase { */ public void testPrecisionAtFiveRelevanceThreshold() throws IOException, InterruptedException, ExecutionException { List rated = new ArrayList<>(); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "0"), 0)); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "1"), 1)); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "2"), 2)); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "3"), 3)); - rated.add(new RatedDocument(new RatedDocumentKey("test", "testtype", "4"), 4)); + rated.add(new RatedDocument("test", "testtype", "0", 0)); + rated.add(new RatedDocument("test", "testtype", "1", 1)); + rated.add(new RatedDocument("test", "testtype", "2", 2)); + rated.add(new RatedDocument("test", "testtype", "3", 3)); + rated.add(new RatedDocument("test", "testtype", "4", 4)); InternalSearchHit[] hits = new InternalSearchHit[5]; for (int i = 0; i < 5; i++) { hits[i] = new InternalSearchHit(i, i+"", new Text("testtype"), Collections.emptyMap()); diff --git a/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/10_basic.yaml b/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/10_basic.yaml index 7dd41141b33..234dc827ebf 100644 --- a/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/10_basic.yaml +++ b/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/10_basic.yaml @@ -47,14 +47,14 @@ "id": "amsterdam_query", "request": { "query": { "match" : {"text" : "amsterdam" }}}, "ratings": [ - {"key": { "index": "foo", "type": "bar", "doc_id": "doc1"}, "rating": 0}, - {"key": { "index": "foo", "type": "bar", "doc_id": "doc2"}, "rating": 1}, - {"key": { "index": "foo", "type": "bar", "doc_id": "doc3"}, "rating": 1}] + {"index": "foo", "type": "bar", "doc_id": "doc1", "rating": 0}, + {"index": "foo", "type": "bar", "doc_id": "doc2", "rating": 1}, + {"index": "foo", "type": "bar", "doc_id": "doc3", "rating": 1}] }, { "id" : "berlin_query", "request": { "query": { "match" : { "text" : "berlin" } }, "size" : 10 }, - "ratings": [{"key": {"index": "foo", "type": "bar", "doc_id": "doc1"}, "rating": 1}] + "ratings": [{"index": "foo", "type": "bar", "doc_id": "doc1", "rating": 1}] } ], "metric" : { "precisionatn": { "size": 10}} @@ -62,8 +62,8 @@ - match: {rank_eval.spec_id: "cities_qa_queries"} - match: {rank_eval.quality_level: 1} - - match: {rank_eval.unknown_docs.0.amsterdam_query: [ {"index": "foo", "type": "bar", "doc_id": "doc4"}]} - - match: {rank_eval.unknown_docs.1.berlin_query: [ {"index": "foo", "type": "bar", "doc_id": "doc4"}]} + - match: {rank_eval.unknown_docs.amsterdam_query: [ {"index": "foo", "type": "bar", "doc_id": "doc4"}]} + - match: {rank_eval.unknown_docs.berlin_query: [ {"index": "foo", "type": "bar", "doc_id": "doc4"}]} --- "Reciprocal Rank": @@ -114,13 +114,13 @@ "id": "amsterdam_query", "request": { "query": { "match" : {"text" : "amsterdam" }}}, # doc4 should be returned in third position, so reciprocal rank is 1/3 - "ratings": [{"key": {"index": "foo", "type": "bar", "doc_id": "doc4"}, "rating": 1}] + "ratings": [{"index": "foo", "type": "bar", "doc_id": "doc4", "rating": 1}] }, { "id" : "berlin_query", "request": { "query": { "match" : { "text" : "berlin" } }, "size" : 10 }, # doc1 should be returned in first position, doc3 in second, so reciprocal rank is 1/2 - "ratings": [{"key": {"index": "foo", "type": "bar", "doc_id": "doc4"}, "rating": 1}] + "ratings": [{"index": "foo", "type": "bar", "doc_id": "doc4", "rating": 1}] } ], "metric" : { "reciprocal_rank": {} } @@ -139,13 +139,13 @@ "id": "amsterdam_query", "request": { "query": { "match" : {"text" : "amsterdam" }}}, # doc4 should be returned in third position, so reciprocal rank is 1/3 - "ratings": [{"key": {"index": "foo", "type": "bar", "doc_id": "doc4"}, "rating": 1}] + "ratings": [{"index": "foo", "type": "bar", "doc_id": "doc4", "rating": 1}] }, { "id" : "berlin_query", "request": { "query": { "match" : { "text" : "berlin" } }, "size" : 10 }, # doc1 should be returned in first position, doc3 in second, so reciprocal rank is 1/2 - "ratings": [{"key": {"index": "foo", "type": "bar", "doc_id": "doc4"}, "rating": 1}] + "ratings": [{"index": "foo", "type": "bar", "doc_id": "doc4", "rating": 1}] } ], "metric" : { diff --git a/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/20_dcg.yaml b/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/20_dcg.yaml index f122265e5a7..3bd4e42b62c 100644 --- a/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/20_dcg.yaml +++ b/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/20_dcg.yaml @@ -53,12 +53,12 @@ "id": "dcg_query", "request": { "query": { "match_all" : {}}, "sort" : [ "bar" ] }, "ratings": [ - {"key": {"index": "foo", "type": "bar", "doc_id": "doc1"}, "rating": 3}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc2"}, "rating": 2}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc3"}, "rating": 3}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc4"}, "rating": 0}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc5"}, "rating": 1}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc6"}, "rating": 2}] + {"index": "foo", "type": "bar", "doc_id": "doc1", "rating": 3}, + {"index": "foo", "type": "bar", "doc_id": "doc2", "rating": 2}, + {"index": "foo", "type": "bar", "doc_id": "doc3", "rating": 3}, + {"index": "foo", "type": "bar", "doc_id": "doc4", "rating": 0}, + {"index": "foo", "type": "bar", "doc_id": "doc5", "rating": 1}, + {"index": "foo", "type": "bar", "doc_id": "doc6", "rating": 2}] } ], "metric" : { "dcg_at_n": { "size": 6}} @@ -78,12 +78,12 @@ "id": "dcg_query_reverse", "request": { "query": { "match_all" : {}}, "sort" : [ {"bar" : "desc" }] }, "ratings": [ - {"key": {"index": "foo", "type": "bar", "doc_id": "doc1"}, "rating": 3}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc2"}, "rating": 2}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc3"}, "rating": 3}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc4"}, "rating": 0}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc5"}, "rating": 1}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc6"}, "rating": 2}] + {"index": "foo", "type": "bar", "doc_id": "doc1", "rating": 3}, + {"index": "foo", "type": "bar", "doc_id": "doc2", "rating": 2}, + {"index": "foo", "type": "bar", "doc_id": "doc3", "rating": 3}, + {"index": "foo", "type": "bar", "doc_id": "doc4", "rating": 0}, + {"index": "foo", "type": "bar", "doc_id": "doc5", "rating": 1}, + {"index": "foo", "type": "bar", "doc_id": "doc6", "rating": 2}] }, ], "metric" : { "dcg_at_n": { "size": 6}} @@ -103,23 +103,23 @@ "id": "dcg_query", "request": { "query": { "match_all" : {}}, "sort" : [ "bar" ] }, "ratings": [ - {"key": {"index": "foo", "type": "bar", "doc_id": "doc1"}, "rating": 3}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc2"}, "rating": 2}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc3"}, "rating": 3}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc4"}, "rating": 0}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc5"}, "rating": 1}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc6"}, "rating": 2}] + {"index": "foo", "type": "bar", "doc_id": "doc1", "rating": 3}, + {"index": "foo", "type": "bar", "doc_id": "doc2", "rating": 2}, + {"index": "foo", "type": "bar", "doc_id": "doc3", "rating": 3}, + {"index": "foo", "type": "bar", "doc_id": "doc4", "rating": 0}, + {"index": "foo", "type": "bar", "doc_id": "doc5", "rating": 1}, + {"index": "foo", "type": "bar", "doc_id": "doc6", "rating": 2}] }, { "id": "dcg_query_reverse", "request": { "query": { "match_all" : {}}, "sort" : [ {"bar" : "desc" }] }, "ratings": [ - {"key": {"index": "foo", "type": "bar", "doc_id": "doc1"}, "rating": 3}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc2"}, "rating": 2}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc3"}, "rating": 3}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc4"}, "rating": 0}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc5"}, "rating": 1}, - {"key": {"index": "foo", "type": "bar", "doc_id": "doc6"}, "rating": 2}] + {"index": "foo", "type": "bar", "doc_id": "doc1", "rating": 3}, + {"index": "foo", "type": "bar", "doc_id": "doc2", "rating": 2}, + {"index": "foo", "type": "bar", "doc_id": "doc3", "rating": 3}, + {"index": "foo", "type": "bar", "doc_id": "doc4", "rating": 0}, + {"index": "foo", "type": "bar", "doc_id": "doc5", "rating": 1}, + {"index": "foo", "type": "bar", "doc_id": "doc6", "rating": 2}] }, ], "metric" : { "dcg_at_n": { "size": 6}}