You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ju...@apache.org on 2022/04/04 19:15:16 UTC

[lucene] branch branch_9x updated: LUCENE-10466: Ensure IndexSortSortedNumericDocValuesRangeQuery handles sort types besides LONG

This is an automated email from the ASF dual-hosted git repository.

julietibs pushed a commit to branch branch_9x
in repository https://gitbox.apache.org/repos/asf/lucene.git


The following commit(s) were added to refs/heads/branch_9x by this push:
     new 03dd543572c LUCENE-10466: Ensure IndexSortSortedNumericDocValuesRangeQuery handles sort types besides LONG
03dd543572c is described below

commit 03dd543572cef06068d8515d97fc9b4c902afe60
Author: Andriy Redko <an...@aiven.io>
AuthorDate: Mon Apr 4 15:02:00 2022 -0400

    LUCENE-10466: Ensure IndexSortSortedNumericDocValuesRangeQuery handles sort types besides LONG
    
    IndexSortSortedNumericDocValuesRangeQuery unconditionally assumes the usage of
    the LONG-encoded SortField. Using the numeric range query (in case of sorted
    index) with anything but LONG ends up with class cast exception. Now the query
    consults the numeric type of the `SortField` and perform appropriate checks.
---
 lucene/CHANGES.txt                                 |  3 ++
 .../IndexSortSortedNumericDocValuesRangeQuery.java | 47 +++++++++++++++++-----
 ...tIndexSortSortedNumericDocValuesRangeQuery.java | 29 +++++++++++--
 3 files changed, 64 insertions(+), 15 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 4b7a1a8e5e8..a36cab8d8ef 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -46,6 +46,9 @@ Bug Fixes
 * LUCENE-10491: A correctness bug in the way scores are provided within TaxonomyFacetSumValueSource
   was fixed. (Michael McCandless, Greg Miller)
 
+* LUCENE-10466: Ensure IndexSortSortedNumericDocValuesRangeQuery handles sort field
+  types besides LONG (Andriy Redko)
+
 Build
 ---------------------
 
diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/IndexSortSortedNumericDocValuesRangeQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/IndexSortSortedNumericDocValuesRangeQuery.java
index 38d9314fefd..ccaf0766f73 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/IndexSortSortedNumericDocValuesRangeQuery.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/IndexSortSortedNumericDocValuesRangeQuery.java
@@ -40,6 +40,8 @@ import org.apache.lucene.search.Scorer;
 import org.apache.lucene.search.ScorerSupplier;
 import org.apache.lucene.search.Sort;
 import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.SortField.Type;
+import org.apache.lucene.search.SortedNumericSortField;
 import org.apache.lucene.search.Weight;
 
 /**
@@ -52,6 +54,7 @@ import org.apache.lucene.search.Weight;
  * <ul>
  *   <li>The index is sorted, and its primary sort is on the same field as the query.
  *   <li>The query field has either {@link SortedNumericDocValues} or {@link NumericDocValues}.
+ *   <li>The sort field is of type {@code SortField.Type.LONG} or {@code SortField.Type.INT}.
  *   <li>The segments must have at most one field value per document (otherwise we cannot easily
  *       determine the matching document IDs through a binary search).
  * </ul>
@@ -222,8 +225,12 @@ public class IndexSortSortedNumericDocValuesRangeQuery extends Query {
           && indexSort.getSort().length > 0
           && indexSort.getSort()[0].getField().equals(field)) {
 
-        SortField sortField = indexSort.getSort()[0];
-        return getDocIdSetIterator(sortField, context, numericValues);
+        final SortField sortField = indexSort.getSort()[0];
+        final SortField.Type sortFieldType = getSortFieldType(sortField);
+        // The index sort optimization is only supported for Type.INT and Type.LONG
+        if (sortFieldType == Type.INT || sortFieldType == Type.LONG) {
+          return getDocIdSetIterator(sortField, sortFieldType, context, numericValues);
+        }
       }
     }
     return null;
@@ -242,14 +249,17 @@ public class IndexSortSortedNumericDocValuesRangeQuery extends Query {
    * no value.
    */
   private BoundedDocIdSetIterator getDocIdSetIterator(
-      SortField sortField, LeafReaderContext context, DocIdSetIterator delegate)
+      SortField sortField,
+      SortField.Type sortFieldType,
+      LeafReaderContext context,
+      DocIdSetIterator delegate)
       throws IOException {
     long lower = sortField.getReverse() ? upperValue : lowerValue;
     long upper = sortField.getReverse() ? lowerValue : upperValue;
     int maxDoc = context.reader().maxDoc();
 
     // Perform a binary search to find the first document with value >= lower.
-    ValueComparator comparator = loadComparator(sortField, lower, context);
+    ValueComparator comparator = loadComparator(sortField, sortFieldType, lower, context);
     int low = 0;
     int high = maxDoc - 1;
 
@@ -257,7 +267,7 @@ public class IndexSortSortedNumericDocValuesRangeQuery extends Query {
       int mid = (low + high) >>> 1;
       if (comparator.compare(mid) <= 0) {
         high = mid - 1;
-        comparator = loadComparator(sortField, lower, context);
+        comparator = loadComparator(sortField, sortFieldType, lower, context);
       } else {
         low = mid + 1;
       }
@@ -267,7 +277,7 @@ public class IndexSortSortedNumericDocValuesRangeQuery extends Query {
     // Perform a binary search to find the first document with value > upper.
     // Since we know that upper >= lower, we can initialize the lower bound
     // of the binary search to the result of the previous search.
-    comparator = loadComparator(sortField, upper, context);
+    comparator = loadComparator(sortField, sortFieldType, upper, context);
     low = firstDocIdInclusive;
     high = maxDoc - 1;
 
@@ -275,7 +285,7 @@ public class IndexSortSortedNumericDocValuesRangeQuery extends Query {
       int mid = (low + high) >>> 1;
       if (comparator.compare(mid) < 0) {
         high = mid - 1;
-        comparator = loadComparator(sortField, upper, context);
+        comparator = loadComparator(sortField, sortFieldType, upper, context);
       } else {
         low = mid + 1;
       }
@@ -303,11 +313,17 @@ public class IndexSortSortedNumericDocValuesRangeQuery extends Query {
   }
 
   private static ValueComparator loadComparator(
-      SortField sortField, long topValue, LeafReaderContext context) throws IOException {
+      SortField sortField, SortField.Type type, long topValue, LeafReaderContext context)
+      throws IOException {
     @SuppressWarnings("unchecked")
-    FieldComparator<Long> fieldComparator =
-        (FieldComparator<Long>) sortField.getComparator(1, false);
-    fieldComparator.setTopValue(topValue);
+    FieldComparator<Number> fieldComparator =
+        (FieldComparator<Number>) sortField.getComparator(1, false);
+    if (type == Type.INT) {
+      fieldComparator.setTopValue((int) topValue);
+    } else {
+      // Since we support only Type.INT and Type.LONG, assuming LONG for all other cases
+      fieldComparator.setTopValue(topValue);
+    }
 
     LeafFieldComparator leafFieldComparator = fieldComparator.getLeafComparator(context);
     int direction = sortField.getReverse() ? -1 : 1;
@@ -318,6 +334,15 @@ public class IndexSortSortedNumericDocValuesRangeQuery extends Query {
     };
   }
 
+  private static SortField.Type getSortFieldType(SortField sortField) {
+    // We expect the sortField to be SortedNumericSortField
+    if (sortField instanceof SortedNumericSortField) {
+      return ((SortedNumericSortField) sortField).getNumericType();
+    } else {
+      return sortField.getType();
+    }
+  }
+
   /**
    * A doc ID set iterator that wraps a delegate iterator and only returns doc IDs in the range
    * [firstDocInclusive, lastDoc).
diff --git a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestIndexSortSortedNumericDocValuesRangeQuery.java b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestIndexSortSortedNumericDocValuesRangeQuery.java
index 8c8d228b932..64bcdbb448a 100644
--- a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestIndexSortSortedNumericDocValuesRangeQuery.java
+++ b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestIndexSortSortedNumericDocValuesRangeQuery.java
@@ -155,15 +155,18 @@ public class TestIndexSortSortedNumericDocValuesRangeQuery extends LuceneTestCas
   }
 
   public void testIndexSortDocValuesWithEvenLength() throws Exception {
-    testIndexSortDocValuesWithEvenLength(false);
-    testIndexSortDocValuesWithEvenLength(true);
+    for (SortField.Type type : new SortField.Type[] {SortField.Type.INT, SortField.Type.LONG}) {
+      testIndexSortDocValuesWithEvenLength(true, type);
+      testIndexSortDocValuesWithEvenLength(false, type);
+    }
   }
 
-  public void testIndexSortDocValuesWithEvenLength(boolean reverse) throws Exception {
+  public void testIndexSortDocValuesWithEvenLength(boolean reverse, SortField.Type type)
+      throws Exception {
     Directory dir = newDirectory();
 
     IndexWriterConfig iwc = new IndexWriterConfig(new MockAnalyzer(random()));
-    Sort indexSort = new Sort(new SortedNumericSortField("field", SortField.Type.LONG, reverse));
+    Sort indexSort = new Sort(new SortedNumericSortField("field", type, reverse));
     iwc.setIndexSort(indexSort);
     RandomIndexWriter writer = new RandomIndexWriter(random(), dir, iwc);
 
@@ -428,6 +431,24 @@ public class TestIndexSortSortedNumericDocValuesRangeQuery extends LuceneTestCas
     dir.close();
   }
 
+  public void testOtherSortTypes() throws Exception {
+    for (SortField.Type type : new SortField.Type[] {SortField.Type.FLOAT, SortField.Type.DOUBLE}) {
+      Directory dir = newDirectory();
+
+      IndexWriterConfig iwc = new IndexWriterConfig(new MockAnalyzer(random()));
+      Sort indexSort = new Sort(new SortedNumericSortField("field", type));
+      iwc.setIndexSort(indexSort);
+
+      RandomIndexWriter writer = new RandomIndexWriter(random(), dir, iwc);
+      writer.addDocument(createDocument("field", 0));
+
+      testIndexSortOptimizationDeactivated(writer);
+
+      writer.close();
+      dir.close();
+    }
+  }
+
   /**
    * Test that the index sort optimization is not activated when some documents have multiple
    * values.