Skip to content

Commit

Permalink
Emit deprecation warning when TermsLookup contains a type (#53731)
Browse files Browse the repository at this point in the history
TermsLookup in master no longer accepts a type parameter. We should emit
a deprecate warning in 7.x when a terms lookup requests includes type to prepare
users for its removal.

Relates to #41059
  • Loading branch information
romseygeek authored Mar 20, 2020
1 parent d486bde commit a3f21f2
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ setup:
---
"Filter aggs with terms lookup and ensure it's cached":
# Because the filter agg rewrites the terms lookup in the rewrite phase the request can be cached

- skip:
features: allowed_warnings
- do:
allowed_warnings:
- "Deprecated field [type] used, this field is unused and will be removed entirely"
search:
rest_total_hits_as_int: true
size: 0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"Ensure that we fetch the document only once":
- skip:
features: allowed_warnings
- do:
indices.create:
index: search_index
Expand Down Expand Up @@ -31,11 +33,13 @@
indices.refresh: {}

- do:
allowed_warnings:
- "Deprecated field [type] used, this field is unused and will be removed entirely"
catch: /no such index/
search:
rest_total_hits_as_int: true
index: "search_index"
body: { "size" : 0, "query" : { "terms" : { "user" : { "index": "lookup_index", "type": "_doc", "id": "1", "path": "followers"} } } }
body: { "size" : 0, "query" : { "terms" : { "user" : { "index": "lookup_index", "type" : "_doc", "id": "1", "path": "followers"} } } }
- do:
indices.create:
index: lookup_index
Expand All @@ -55,10 +59,12 @@
indices.refresh: {}

- do:
allowed_warnings:
- "Deprecated field [type] used, this field is unused and will be removed entirely"
search:
rest_total_hits_as_int: true
index: "search_index"
body: { "size" : 0, "query" : { "terms" : { "user" : { "index": "lookup_index", "type": "_doc", "id": "1", "path": "followers"} } } }
body: { "size" : 0, "query" : { "terms" : { "user" : { "index": "lookup_index", "type" : "_doc", "id": "1", "path": "followers"} } } }

- match: { _shards.total: 5 }
- match: { _shards.successful: 5 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- skip:
version: " - 6.99.99"
reason: index.max_terms_count setting has been added in 7.0.0
features: allowed_warnings
- do:
indices.create:
include_type_name: true
Expand Down Expand Up @@ -46,6 +47,8 @@
body: {"query" : {"terms" : {"user" : ["u1", "u2", "u3"]}}}

- do:
allowed_warnings:
- "Deprecated field [type] used, this field is unused and will be removed entirely"
search:
rest_total_hits_as_int: true
index: test_index
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

package org.elasticsearch.index.query;

import org.apache.logging.log4j.LogManager;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
Expand All @@ -35,13 +34,12 @@
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.ConstantFieldType;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.indices.TermsLookup;

import java.io.IOException;
Expand All @@ -64,11 +62,6 @@
public class TermsQueryBuilder extends AbstractQueryBuilder<TermsQueryBuilder> {
public static final String NAME = "terms";

private static final DeprecationLogger deprecationLogger = new DeprecationLogger(
LogManager.getLogger(TermsQueryBuilder.class));
static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Types are deprecated " +
"in [terms] lookup queries.";

private final String fieldName;
private final List<?> values;
private final TermsLookup termsLookup;
Expand Down Expand Up @@ -402,15 +395,9 @@ public static TermsQueryBuilder fromXContent(XContentParser parser) throws IOExc
"followed by array of terms or a document lookup specification");
}

TermsQueryBuilder builder = new TermsQueryBuilder(fieldName, values, termsLookup)
return new TermsQueryBuilder(fieldName, values, termsLookup)
.boost(boost)
.queryName(queryName);

if (builder.isTypeless() == false) {
deprecationLogger.deprecatedAndMaybeLog("terms_lookup_with_types", TYPES_DEPRECATION_MESSAGE);
}

return builder;
}

static List<Object> parseValues(XContentParser parser) throws IOException {
Expand Down
65 changes: 23 additions & 42 deletions server/src/main/java/org/elasticsearch/indices/TermsLookup.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@

import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.ParseField;
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.ToXContentFragment;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
Expand All @@ -33,10 +34,14 @@
import java.io.IOException;
import java.util.Objects;

import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;

/**
* Encapsulates the parameters needed to fetch terms.
*/
public class TermsLookup implements Writeable, ToXContentFragment {

private final String index;
private @Nullable String type;
private final String id;
Expand Down Expand Up @@ -142,48 +147,24 @@ public TermsLookup routing(String routing) {
return this;
}

private static final ConstructingObjectParser<TermsLookup, Void> PARSER = new ConstructingObjectParser<>("terms_lookup",
args -> {
String index = (String) args[0];
String type = (String) args[1];
String id = (String) args[2];
String path = (String) args[3];
return new TermsLookup(index, type, id, path);
});
static {
PARSER.declareString(constructorArg(), new ParseField("index"));
PARSER.declareString(optionalConstructorArg(), new ParseField("type").withAllDeprecated());
PARSER.declareString(constructorArg(), new ParseField("id"));
PARSER.declareString(constructorArg(), new ParseField("path"));
PARSER.declareString(TermsLookup::routing, new ParseField("routing"));
}

public static TermsLookup parseTermsLookup(XContentParser parser) throws IOException {
String index = null;
String type = null;
String id = null;
String path = null;
String routing = null;
XContentParser.Token token;
String currentFieldName = "";
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (token.isValue()) {
switch (currentFieldName) {
case "index":
index = parser.text();
break;
case "type":
type = parser.text();
break;
case "id":
id = parser.text();
break;
case "routing":
routing = parser.textOrNull();
break;
case "path":
path = parser.text();
break;
default:
throw new ParsingException(parser.getTokenLocation(), "[" + TermsQueryBuilder.NAME +
"] query does not support [" + currentFieldName + "] within lookup element");
}
} else {
throw new ParsingException(parser.getTokenLocation(), "[" + TermsQueryBuilder.NAME + "] unknown token ["
+ token + "] after [" + currentFieldName + "]");
}
}
if (type == null) {
return new TermsLookup(index, id, path).routing(routing);
} else {
return new TermsLookup(index, type, id, path).routing(routing);
}
return PARSER.parse(parser, null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
public class TermsQueryBuilderTests extends AbstractQueryTestCase<TermsQueryBuilder> {
private List<Object> randomTerms;
private String termsPath;
private boolean maybeIncludeType = true;

@Before
public void randomTerms() {
Expand Down Expand Up @@ -100,10 +101,10 @@ protected TermsQueryBuilder doCreateTestQueryBuilder() {

private TermsLookup randomTermsLookup() {
// Randomly choose between a typeless terms lookup and one with an explicit type to make sure we are
TermsLookup lookup = maybeIncludeType && randomBoolean()
? new TermsLookup(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10), termsPath)
: new TermsLookup(randomAlphaOfLength(10), randomAlphaOfLength(10), termsPath);
// testing both cases.
TermsLookup lookup = randomBoolean()
? new TermsLookup(randomAlphaOfLength(10), randomAlphaOfLength(10), termsPath)
: new TermsLookup(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10), termsPath);
lookup.routing(randomBoolean() ? randomAlphaOfLength(10) : null);
return lookup;
}
Expand Down Expand Up @@ -149,7 +150,13 @@ protected void doAssertLuceneQuery(TermsQueryBuilder queryBuilder, Query query,
}
}

public void testEmtpyFieldName() {
@Override
public void testUnknownField() throws IOException {
maybeIncludeType = false; // deprecation warnings will fail the parent test, so we disable types
super.testUnknownField();
}

public void testEmptyFieldName() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new TermsQueryBuilder(null, "term"));
assertEquals("field name cannot be null.", e.getMessage());
e = expectThrows(IllegalArgumentException.class, () -> new TermsQueryBuilder("", "term"));
Expand Down Expand Up @@ -326,32 +333,36 @@ public void testTypeField() throws IOException {
builder.doToQuery(createShardContext());
assertWarnings(QueryShardContext.TYPES_DEPRECATION_MESSAGE);
}

public void testRewriteIndexQueryToMatchNone() throws IOException {
TermsQueryBuilder query = new TermsQueryBuilder("_index", "does_not_exist", "also_does_not_exist");
QueryShardContext queryShardContext = createShardContext();
QueryBuilder rewritten = query.rewrite(queryShardContext);
assertThat(rewritten, instanceOf(MatchNoneQueryBuilder.class));
}
}

public void testRewriteIndexQueryToNotMatchNone() throws IOException {
// At least one name is good
TermsQueryBuilder query = new TermsQueryBuilder("_index", "does_not_exist", getIndex().getName());
QueryShardContext queryShardContext = createShardContext();
QueryBuilder rewritten = query.rewrite(queryShardContext);
assertThat(rewritten, instanceOf(MatchAllQueryBuilder.class));
}
}

@Override
protected QueryBuilder parseQuery(XContentParser parser) throws IOException {
QueryBuilder query = super.parseQuery(parser);
assertThat(query, CoreMatchers.instanceOf(TermsQueryBuilder.class));
try {
QueryBuilder query = super.parseQuery(parser);
assertThat(query, CoreMatchers.instanceOf(TermsQueryBuilder.class));

TermsQueryBuilder termsQuery = (TermsQueryBuilder) query;
if (termsQuery.isTypeless() == false) {
assertWarnings("Deprecated field [type] used, this field is unused and will be removed entirely");
}
return query;
} finally {

TermsQueryBuilder termsQuery = (TermsQueryBuilder) query;
if (termsQuery.isTypeless() == false) {
assertWarnings(TermsQueryBuilder.TYPES_DEPRECATION_MESSAGE);
}
return query;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import org.elasticsearch.Version;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.test.ESTestCase;

import java.io.IOException;
Expand Down Expand Up @@ -105,6 +107,32 @@ public void testSerializationWithTypes() throws IOException {
}
}

public void testXContentParsingWithType() throws IOException {
XContentParser parser = createParser(JsonXContent.jsonXContent,
"{ \"index\" : \"index\", \"id\" : \"id\", \"type\" : \"type\", \"path\" : \"path\", \"routing\" : \"routing\" }");

TermsLookup tl = TermsLookup.parseTermsLookup(parser);
assertEquals("index", tl.index());
assertEquals("type", tl.type());
assertEquals("id", tl.id());
assertEquals("path", tl.path());
assertEquals("routing", tl.routing());

assertWarnings("Deprecated field [type] used, this field is unused and will be removed entirely");
}

public void testXContentParsing() throws IOException {
XContentParser parser = createParser(JsonXContent.jsonXContent,
"{ \"index\" : \"index\", \"id\" : \"id\", \"path\" : \"path\", \"routing\" : \"routing\" }");

TermsLookup tl = TermsLookup.parseTermsLookup(parser);
assertEquals("index", tl.index());
assertNull(tl.type());
assertEquals("id", tl.id());
assertEquals("path", tl.path());
assertEquals("routing", tl.routing());
}

public static TermsLookup randomTermsLookup() {
return new TermsLookup(
randomAlphaOfLength(10),
Expand Down

0 comments on commit a3f21f2

Please sign in to comment.