Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emit deprecation warning when TermsLookup contains a type #53731

Merged
merged 16 commits into from
Mar 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@romseygeek sorry for the late review, I'm wondering why this check wasn't sufficient for emitting a deprecation warning? Was it not triggered on all the relevant code paths?

It would be nice to keep this strategy if possible, since it's consistent with all our other types deprecation warnings (deprecatedAndMaybeLog("api_name_with_types", TYPES_DEPRECATION_MESSAGE);). It also lets us avoid adding an allowed_warnings section to the yml tests, since in 7.x we already ignore all warnings in yml tests that start with [types removal] ... .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a path that didn't trigger the warning, but I can't find it now, so it may have been refactored away elsewhere. I'll have a look, it would be good to remove some of these extra allowed_warnings messages.

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