Optimize `terms` queries on `ip` addresses to use a `PointInSetQuery` whenever possible. (#25669)

We can't do it in the general case because of prefix queries, but I believe this
is mostly used in query strings and not in explicit `terms` queries.

Closes #25667
This commit is contained in:
Adrien Grand 2017-07-17 15:39:01 +02:00 committed by GitHub
parent 264088f1c4
commit 78a6c3427b
2 changed files with 44 additions and 0 deletions

View File

@ -177,6 +177,30 @@ public class IpFieldMapper extends FieldMapper {
}
}
@Override
public Query termsQuery(List<?> values, QueryShardContext context) {
InetAddress[] addresses = new InetAddress[values.size()];
int i = 0;
for (Object value : values) {
InetAddress address;
if (value instanceof InetAddress) {
address = (InetAddress) value;
} else {
if (value instanceof BytesRef) {
value = ((BytesRef) value).utf8ToString();
}
if (value.toString().contains("/")) {
// the `terms` query contains some prefix queries, so we cannot create a set query
// and need to fall back to a disjunction of `term` queries
return super.termsQuery(values, context);
}
address = InetAddresses.forString(value.toString());
}
addresses[i++] = address;
}
return InetAddressPoint.newSetQuery(name(), addresses);
}
@Override
public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper, QueryShardContext context) {
failIfNotIndexed();

View File

@ -19,10 +19,14 @@
package org.elasticsearch.index.mapper;
import java.net.InetAddress;
import java.util.Arrays;
import org.apache.lucene.document.InetAddressPoint;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.network.InetAddresses;
@ -78,6 +82,22 @@ public class IpFieldTypeTests extends FieldTypeTestCase {
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
public void testTermsQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
assertEquals(InetAddressPoint.newSetQuery("field", InetAddresses.forString("::2"), InetAddresses.forString("::5")),
ft.termsQuery(Arrays.asList(InetAddresses.forString("::2"), InetAddresses.forString("::5")), null));
assertEquals(InetAddressPoint.newSetQuery("field", InetAddresses.forString("::2"), InetAddresses.forString("::5")),
ft.termsQuery(Arrays.asList("::2", "::5"), null));
// if the list includes a prefix query we fallback to a bool query
assertEquals(new ConstantScoreQuery(new BooleanQuery.Builder()
.add(ft.termQuery("::42", null), Occur.SHOULD)
.add(ft.termQuery("::2/16", null), Occur.SHOULD).build()),
ft.termsQuery(Arrays.asList("::42", "::2/16"), null));
}
public void testRangeQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");