Browse Source

Use IndexOrDocValues query for IP range queries (#90303)

Closes #83658
Yannick Welsch 3 years ago
parent
commit
99d51df238

+ 6 - 0
docs/changelog/90303.yaml

@@ -0,0 +1,6 @@
+pr: 90303
+summary: Use `IndexOrDocValues` query for IP range queries
+area: Search
+type: enhancement
+issues:
+ - 83658

+ 6 - 1
server/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java

@@ -13,6 +13,7 @@ import org.apache.lucene.document.InetAddressPoint;
 import org.apache.lucene.document.SortedSetDocValuesField;
 import org.apache.lucene.document.StoredField;
 import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.search.IndexOrDocValuesQuery;
 import org.apache.lucene.search.MatchNoDocsQuery;
 import org.apache.lucene.search.PointRangeQuery;
 import org.apache.lucene.search.Query;
@@ -343,7 +344,11 @@ public class IpFieldMapper extends FieldMapper {
             return rangeQuery(lowerTerm, upperTerm, includeLower, includeUpper, (lower, upper) -> {
                 Query query = InetAddressPoint.newRangeQuery(name(), lower, upper);
                 if (isIndexed()) {
-                    return query;
+                    if (hasDocValues()) {
+                        return new IndexOrDocValuesQuery(query, convertToDocValuesQuery(query));
+                    } else {
+                        return query;
+                    }
                 } else {
                     return convertToDocValuesQuery(query);
                 }

+ 32 - 12
server/src/test/java/org/elasticsearch/index/mapper/IpFieldTypeTests.java

@@ -11,7 +11,9 @@ import org.apache.lucene.document.InetAddressPoint;
 import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.ConstantScoreQuery;
+import org.apache.lucene.search.IndexOrDocValuesQuery;
 import org.apache.lucene.search.MatchNoDocsQuery;
+import org.apache.lucene.search.Query;
 import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.Version;
 import org.elasticsearch.common.network.InetAddresses;
@@ -134,43 +136,51 @@ public class IpFieldTypeTests extends FieldTypeTestCase {
     public void testRangeQuery() {
         MappedFieldType ft = new IpFieldMapper.IpFieldType("field");
 
+        Query query = InetAddressPoint.newRangeQuery("field", InetAddresses.forString("::"), InetAddressPoint.MAX_VALUE);
         assertEquals(
-            InetAddressPoint.newRangeQuery("field", InetAddresses.forString("::"), InetAddressPoint.MAX_VALUE),
+            new IndexOrDocValuesQuery(query, convertToDocValuesQuery(query)),
             ft.rangeQuery(null, null, randomBoolean(), randomBoolean(), null, null, null, MOCK_CONTEXT)
         );
 
+        query = InetAddressPoint.newRangeQuery("field", InetAddresses.forString("::"), InetAddresses.forString("192.168.2.0"));
         assertEquals(
-            InetAddressPoint.newRangeQuery("field", InetAddresses.forString("::"), InetAddresses.forString("192.168.2.0")),
+            new IndexOrDocValuesQuery(query, convertToDocValuesQuery(query)),
             ft.rangeQuery(null, "192.168.2.0", randomBoolean(), true, null, null, null, MOCK_CONTEXT)
         );
 
+        query = InetAddressPoint.newRangeQuery("field", InetAddresses.forString("::"), InetAddresses.forString("192.168.1.255"));
         assertEquals(
-            InetAddressPoint.newRangeQuery("field", InetAddresses.forString("::"), InetAddresses.forString("192.168.1.255")),
+            new IndexOrDocValuesQuery(query, convertToDocValuesQuery(query)),
             ft.rangeQuery(null, "192.168.2.0", randomBoolean(), false, null, null, null, MOCK_CONTEXT)
         );
 
+        query = InetAddressPoint.newRangeQuery("field", InetAddresses.forString("2001:db8::"), InetAddressPoint.MAX_VALUE);
         assertEquals(
-            InetAddressPoint.newRangeQuery("field", InetAddresses.forString("2001:db8::"), InetAddressPoint.MAX_VALUE),
+            new IndexOrDocValuesQuery(query, convertToDocValuesQuery(query)),
             ft.rangeQuery("2001:db8::", null, true, randomBoolean(), null, null, null, MOCK_CONTEXT)
         );
 
+        query = InetAddressPoint.newRangeQuery("field", InetAddresses.forString("2001:db8::1"), InetAddressPoint.MAX_VALUE);
         assertEquals(
-            InetAddressPoint.newRangeQuery("field", InetAddresses.forString("2001:db8::1"), InetAddressPoint.MAX_VALUE),
+            new IndexOrDocValuesQuery(query, convertToDocValuesQuery(query)),
             ft.rangeQuery("2001:db8::", null, false, randomBoolean(), null, null, null, MOCK_CONTEXT)
         );
 
+        query = InetAddressPoint.newRangeQuery("field", InetAddresses.forString("2001:db8::"), InetAddresses.forString("2001:db8::ffff"));
         assertEquals(
-            InetAddressPoint.newRangeQuery("field", InetAddresses.forString("2001:db8::"), InetAddresses.forString("2001:db8::ffff")),
+            new IndexOrDocValuesQuery(query, convertToDocValuesQuery(query)),
             ft.rangeQuery("2001:db8::", "2001:db8::ffff", true, true, null, null, null, MOCK_CONTEXT)
         );
 
+        query = InetAddressPoint.newRangeQuery("field", InetAddresses.forString("2001:db8::1"), InetAddresses.forString("2001:db8::fffe"));
         assertEquals(
-            InetAddressPoint.newRangeQuery("field", InetAddresses.forString("2001:db8::1"), InetAddresses.forString("2001:db8::fffe")),
+            new IndexOrDocValuesQuery(query, convertToDocValuesQuery(query)),
             ft.rangeQuery("2001:db8::", "2001:db8::ffff", false, false, null, null, null, MOCK_CONTEXT)
         );
 
+        query = InetAddressPoint.newRangeQuery("field", InetAddresses.forString("2001:db8::2"), InetAddresses.forString("2001:db8::"));
         assertEquals(
-            InetAddressPoint.newRangeQuery("field", InetAddresses.forString("2001:db8::2"), InetAddresses.forString("2001:db8::")),
+            new IndexOrDocValuesQuery(query, convertToDocValuesQuery(query)),
             // same lo/hi values but inclusive=false so this won't match anything
             ft.rangeQuery("2001:db8::1", "2001:db8::1", false, false, null, null, null, MOCK_CONTEXT)
         );
@@ -193,24 +203,34 @@ public class IpFieldTypeTests extends FieldTypeTestCase {
             )
         );
 
+        query = InetAddressPoint.newRangeQuery("field", InetAddresses.forString("::"), InetAddresses.forString("::fffe:ffff:ffff"));
         assertEquals(
-            InetAddressPoint.newRangeQuery("field", InetAddresses.forString("::"), InetAddresses.forString("::fffe:ffff:ffff")),
+            new IndexOrDocValuesQuery(query, convertToDocValuesQuery(query)),
             // same lo/hi values but inclusive=false so this won't match anything
             ft.rangeQuery("::", "0.0.0.0", true, false, null, null, null, MOCK_CONTEXT)
         );
 
+        query = InetAddressPoint.newRangeQuery("field", InetAddresses.forString("::1:0:0:0"), InetAddressPoint.MAX_VALUE);
         assertEquals(
-            InetAddressPoint.newRangeQuery("field", InetAddresses.forString("::1:0:0:0"), InetAddressPoint.MAX_VALUE),
+            new IndexOrDocValuesQuery(query, convertToDocValuesQuery(query)),
             // same lo/hi values but inclusive=false so this won't match anything
             ft.rangeQuery("255.255.255.255", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", false, true, null, null, null, MOCK_CONTEXT)
         );
 
+        // lower bound is ipv4, upper bound is ipv6
+        query = InetAddressPoint.newRangeQuery("field", InetAddresses.forString("192.168.1.7"), InetAddresses.forString("2001:db8::"));
         assertEquals(
-            // lower bound is ipv4, upper bound is ipv6
-            InetAddressPoint.newRangeQuery("field", InetAddresses.forString("192.168.1.7"), InetAddresses.forString("2001:db8::")),
+            new IndexOrDocValuesQuery(query, convertToDocValuesQuery(query)),
             ft.rangeQuery("::ffff:c0a8:107", "2001:db8::", true, true, null, null, null, MOCK_CONTEXT)
         );
 
+        ft = new IpFieldMapper.IpFieldType("field", true, false);
+
+        assertEquals(
+            InetAddressPoint.newRangeQuery("field", InetAddresses.forString("::"), InetAddressPoint.MAX_VALUE),
+            ft.rangeQuery(null, null, randomBoolean(), randomBoolean(), null, null, null, MOCK_CONTEXT)
+        );
+
         ft = new IpFieldMapper.IpFieldType("field", false);
 
         assertEquals(