You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by jp...@apache.org on 2017/05/23 16:47:00 UTC

lucene-solr:master: LUCENE-7847: Fix the all-docs-match optimization of range queries on range fields.

Repository: lucene-solr
Updated Branches:
  refs/heads/master 31e02e93a -> 14320a584


LUCENE-7847: Fix the all-docs-match optimization of range queries on range fields.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/14320a58
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/14320a58
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/14320a58

Branch: refs/heads/master
Commit: 14320a584c7771c63fba4de868c51ee9a5cf06de
Parents: 31e02e9
Author: Adrien Grand <jp...@gmail.com>
Authored: Tue May 23 18:37:01 2017 +0200
Committer: Adrien Grand <jp...@gmail.com>
Committed: Tue May 23 18:46:50 2017 +0200

----------------------------------------------------------------------
 lucene/CHANGES.txt                              |  3 ++
 .../apache/lucene/document/RangeFieldQuery.java | 48 ++++++++++----------
 .../search/TestDoubleRangeFieldQueries.java     | 15 ++++--
 .../search/TestFloatRangeFieldQueries.java      | 15 ++++--
 .../lucene/search/TestIntRangeFieldQueries.java | 23 ++++++++--
 .../search/TestLongRangeFieldQueries.java       | 23 ++++++++--
 .../search/TestInetAddressRangeQueries.java     | 18 ++++++--
 .../search/BaseRangeFieldQueryTestCase.java     |  4 +-
 8 files changed, 104 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/14320a58/lucene/CHANGES.txt
----------------------------------------------------------------------
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 2138321..3951cea 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -155,6 +155,9 @@ Bug Fixes
 * LUCENE-7833: ToParentBlockJoinQuery computed the min score instead of the max
   score with ScoreMode.MAX. (Adrien Grand)
 
+* LUCENE-7847: Fixed all-docs-match optimization of range queries on range
+  fields. (Adrien Grand)
+
 Improvements
 
 * LUCENE-7782: OfflineSorter now passes the total number of items it

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/14320a58/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java b/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java
index 10f10fa..750189d 100644
--- a/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java
@@ -112,6 +112,7 @@ abstract class RangeFieldQuery extends Query {
   public final Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException {
     return new ConstantScoreWeight(this, boost) {
       final RangeFieldComparator target = new RangeFieldComparator();
+
       private DocIdSet buildMatchingDocIdSet(LeafReader reader, PointValues values) throws IOException {
         DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc(), values, field);
         values.intersect(
@@ -133,25 +134,29 @@ abstract class RangeFieldQuery extends Query {
               }
               @Override
               public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
-                byte[] node = getInternalRange(minPackedValue, maxPackedValue);
-                // compute range relation for BKD traversal
-                if (target.intersects(node) == false) {
-                  return Relation.CELL_OUTSIDE_QUERY;
-                } else if (target.within(node)) {
-                  // target within cell; continue traversing:
-                  return Relation.CELL_CROSSES_QUERY;
-                } else if (target.contains(node)) {
-                  // target contains cell; add iff queryType is not a CONTAINS or CROSSES query:
-                  return (queryType == QueryType.CONTAINS || queryType == QueryType.CROSSES) ?
-                      Relation.CELL_OUTSIDE_QUERY : Relation.CELL_INSIDE_QUERY;
-                }
-                // target intersects cell; continue traversing:
-                return Relation.CELL_CROSSES_QUERY;
+                return compareRange(minPackedValue, maxPackedValue);
               }
             });
         return result.build();
       }
 
+      private Relation compareRange(byte[] minPackedValue, byte[] maxPackedValue) {
+        byte[] node = getInternalRange(minPackedValue, maxPackedValue);
+        // compute range relation for BKD traversal
+        if (target.intersects(node) == false) {
+          return Relation.CELL_OUTSIDE_QUERY;
+        } else if (target.within(node)) {
+          // target within cell; continue traversing:
+          return Relation.CELL_CROSSES_QUERY;
+        } else if (target.contains(node)) {
+          // target contains cell; add iff queryType is not a CONTAINS or CROSSES query:
+          return (queryType == QueryType.CONTAINS || queryType == QueryType.CROSSES) ?
+              Relation.CELL_OUTSIDE_QUERY : Relation.CELL_INSIDE_QUERY;
+        }
+        // target intersects cell; continue traversing:
+        return Relation.CELL_CROSSES_QUERY;
+      }
+
       @Override
       public Scorer scorer(LeafReaderContext context) throws IOException {
         LeafReader reader = context.reader();
@@ -166,17 +171,10 @@ abstract class RangeFieldQuery extends Query {
           return null;
         }
         checkFieldInfo(fieldInfo);
-        boolean allDocsMatch = true;
-        if (values.getDocCount() == reader.maxDoc()) {
-          // if query crosses, docs need to be further scrutinized
-          byte[] range = getInternalRange(values.getMinPackedValue(), values.getMaxPackedValue());
-          // if the internal node is not equal and not contained by the query, all docs do not match
-          if (queryType == QueryType.CROSSES || (!Arrays.equals(ranges, range)
-              && (target.contains(range) == false || queryType != QueryType.WITHIN))) {
-            allDocsMatch = false;
-          }
-        } else {
-          allDocsMatch = false;
+        boolean allDocsMatch = false;
+        if (values.getDocCount() == reader.maxDoc()
+            && compareRange(values.getMinPackedValue(), values.getMaxPackedValue()) == Relation.CELL_INSIDE_QUERY) {
+          allDocsMatch = true;
         }
 
         DocIdSetIterator iterator = allDocsMatch == true ?

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/14320a58/lucene/core/src/test/org/apache/lucene/search/TestDoubleRangeFieldQueries.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestDoubleRangeFieldQueries.java b/lucene/core/src/test/org/apache/lucene/search/TestDoubleRangeFieldQueries.java
index 49ca710..a5cbed6 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestDoubleRangeFieldQueries.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestDoubleRangeFieldQueries.java
@@ -31,11 +31,18 @@ public class TestDoubleRangeFieldQueries extends BaseRangeFieldQueryTestCase {
   private static final String FIELD_NAME = "doubleRangeField";
 
   private double nextDoubleInternal() {
-    if (rarely()) {
-      return random().nextBoolean() ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
+    switch (random().nextInt(5)) {
+      case 0:
+        return Double.NEGATIVE_INFINITY;
+      case 1:
+        return Double.POSITIVE_INFINITY;
+      default:
+        if (random().nextBoolean()) {
+          return random().nextDouble();
+        } else {
+          return (random().nextInt(15) - 7) / 3d;
+        }
     }
-    double max = Double.MAX_VALUE / 2;
-    return (max + max) * random().nextDouble() - max;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/14320a58/lucene/core/src/test/org/apache/lucene/search/TestFloatRangeFieldQueries.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestFloatRangeFieldQueries.java b/lucene/core/src/test/org/apache/lucene/search/TestFloatRangeFieldQueries.java
index 6dc5907..6eda4de 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestFloatRangeFieldQueries.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestFloatRangeFieldQueries.java
@@ -31,11 +31,18 @@ public class TestFloatRangeFieldQueries extends BaseRangeFieldQueryTestCase {
   private static final String FIELD_NAME = "floatRangeField";
 
   private float nextFloatInternal() {
-    if (rarely()) {
-      return random().nextBoolean() ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
+    switch (random().nextInt(5)) {
+      case 0:
+        return Float.NEGATIVE_INFINITY;
+      case 1:
+        return Float.POSITIVE_INFINITY;
+      default:
+        if (random().nextBoolean()) {
+          return random().nextFloat();
+        } else {
+          return (random().nextInt(15) - 7) / 3f;
+        }
     }
-    float max = Float.MAX_VALUE / 2;
-    return (max + max) * random().nextFloat() - max;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/14320a58/lucene/core/src/test/org/apache/lucene/search/TestIntRangeFieldQueries.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestIntRangeFieldQueries.java b/lucene/core/src/test/org/apache/lucene/search/TestIntRangeFieldQueries.java
index 14771c9..ecbd55b 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestIntRangeFieldQueries.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestIntRangeFieldQueries.java
@@ -23,6 +23,7 @@ import org.apache.lucene.document.IntRange;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.RandomIndexWriter;
 import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.TestUtil;
 
 /**
  * Random testing for IntRange Queries.
@@ -31,11 +32,25 @@ public class TestIntRangeFieldQueries extends BaseRangeFieldQueryTestCase {
   private static final String FIELD_NAME = "intRangeField";
 
   private int nextIntInternal() {
-    if (rarely()) {
-      return random().nextBoolean() ? Integer.MAX_VALUE : Integer.MIN_VALUE;
+    switch (random().nextInt(5)) {
+      case 0:
+        return Integer.MIN_VALUE;
+      case 1:
+        return Integer.MAX_VALUE;
+      default:
+        int bpv = random().nextInt(32);
+        switch (bpv) {
+          case 32:
+            return random().nextInt();
+          default:
+            int v = TestUtil.nextInt(random(), 0, (1 << bpv) - 1);
+            if (bpv > 0) {
+              // negative values sometimes
+              v -= 1 << (bpv - 1);
+            }
+            return v;
+        }
     }
-    int max = Integer.MAX_VALUE / 2;
-    return (max + max) * random().nextInt() - max;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/14320a58/lucene/core/src/test/org/apache/lucene/search/TestLongRangeFieldQueries.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestLongRangeFieldQueries.java b/lucene/core/src/test/org/apache/lucene/search/TestLongRangeFieldQueries.java
index 60d7ea3..3ad34b5 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestLongRangeFieldQueries.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestLongRangeFieldQueries.java
@@ -23,6 +23,7 @@ import org.apache.lucene.document.LongRange;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.RandomIndexWriter;
 import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.TestUtil;
 
 /**
  * Random testing for LongRange Queries.
@@ -31,11 +32,25 @@ public class TestLongRangeFieldQueries extends BaseRangeFieldQueryTestCase {
   private static final String FIELD_NAME = "longRangeField";
 
   private long nextLongInternal() {
-    if (rarely()) {
-      return random().nextBoolean() ? Long.MAX_VALUE : Long.MIN_VALUE;
+    switch (random().nextInt(5)) {
+      case 0:
+        return Long.MIN_VALUE;
+      case 1:
+        return Long.MAX_VALUE;
+      default:
+        int bpv = random().nextInt(64);
+        switch (bpv) {
+          case 64:
+            return random().nextLong();
+          default:
+            long v = TestUtil.nextLong(random(), 0, (1L << bpv) - 1);
+            if (bpv > 0) {
+              // negative values sometimes
+              v -= 1L << (bpv - 1);
+            }
+            return v;
+        }
     }
-    long max = Long.MAX_VALUE / 2;
-    return (max + max) * random().nextLong() - max;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/14320a58/lucene/misc/src/test/org/apache/lucene/search/TestInetAddressRangeQueries.java
----------------------------------------------------------------------
diff --git a/lucene/misc/src/test/org/apache/lucene/search/TestInetAddressRangeQueries.java b/lucene/misc/src/test/org/apache/lucene/search/TestInetAddressRangeQueries.java
index 252162c..907ba55 100644
--- a/lucene/misc/src/test/org/apache/lucene/search/TestInetAddressRangeQueries.java
+++ b/lucene/misc/src/test/org/apache/lucene/search/TestInetAddressRangeQueries.java
@@ -18,6 +18,7 @@ package org.apache.lucene.search;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.Arrays;
 
 import org.apache.lucene.document.InetAddressPoint;
 import org.apache.lucene.document.InetAddressRange;
@@ -44,8 +45,19 @@ public class TestInetAddressRangeQueries extends BaseRangeFieldQueryTestCase {
   /** return random IPv4 or IPv6 address */
   private InetAddress nextInetaddress() throws UnknownHostException {
     byte[] b = random().nextBoolean() ? new byte[4] : new byte[16];
-    random().nextBytes(b);
-    return InetAddress.getByAddress(b);
+    switch (random().nextInt(5)) {
+      case 0:
+        return InetAddress.getByAddress(b);
+      case 1:
+        Arrays.fill(b, (byte) 0xff);
+        return InetAddress.getByAddress(b);
+      case 2:
+        Arrays.fill(b, (byte) 42);
+        return InetAddress.getByAddress(b);
+      default:
+        random().nextBytes(b);
+        return InetAddress.getByAddress(b);
+    }
   }
 
   @Override
@@ -159,7 +171,7 @@ public class TestInetAddressRangeQueries extends BaseRangeFieldQueryTestCase {
     @Override
     protected boolean isEqual(Range o) {
       IpRange other = (IpRange)o;
-      return this.min.equals(other.min) && this.max.equals(other.max);
+      return Arrays.equals(min, other.min) && Arrays.equals(max, other.max);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/14320a58/lucene/test-framework/src/java/org/apache/lucene/search/BaseRangeFieldQueryTestCase.java
----------------------------------------------------------------------
diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/BaseRangeFieldQueryTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/search/BaseRangeFieldQueryTestCase.java
index 76de732..7d21eb3 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/search/BaseRangeFieldQueryTestCase.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/search/BaseRangeFieldQueryTestCase.java
@@ -61,7 +61,9 @@ public abstract class BaseRangeFieldQueryTestCase extends LuceneTestCase {
 
   public void testRandomTiny() throws Exception {
     // Make sure single-leaf-node case is OK:
-    doTestRandom(10, false);
+    for (int i = 0; i < 10; ++i) {
+      doTestRandom(10, false);
+    }
   }
 
   public void testRandomMedium() throws Exception {