lucene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dor...@apache.org
Subject svn commit: r1164794 - in /lucene/dev/branches/branch_3x/lucene: ./ src/java/org/apache/lucene/search/ src/test/org/apache/lucene/search/
Date Sat, 03 Sep 2011 02:19:06 GMT
Author: doronc
Date: Sat Sep  3 02:19:06 2011
New Revision: 1164794

URL: http://svn.apache.org/viewvc?rev=1164794&view=rev
Log:
LUCENE-3390: Added SortField.setMissingValue(v) to enable well defined sorting behavior for
documents that do not include the given field.

Modified:
    lucene/dev/branches/branch_3x/lucene/CHANGES.txt
    lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldCache.java
    lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java
    lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldComparator.java
    lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/SortField.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestSort.java

Modified: lucene/dev/branches/branch_3x/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/CHANGES.txt?rev=1164794&r1=1164793&r2=1164794&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/CHANGES.txt (original)
+++ lucene/dev/branches/branch_3x/lucene/CHANGES.txt Sat Sep  3 02:19:06 2011
@@ -57,6 +57,10 @@ Bug fixes
 * LUCENE-3409: IndexWriter.deleteAll was failing to close pooled NRT
   SegmentReaders, leading to unused files accumulating in the
   Directory.  (tal steier via Mike McCandless)
+     
+* LUCENE-3390: Added SortField.setMissingValue(v) to enable well defined
+  sorting behavior for documents that do not include the given field.
+  (Gilad Barkai via Doron Cohen)
   
 New Features
 

Modified: lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldCache.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldCache.java?rev=1164794&r1=1164793&r2=1164794&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldCache.java
(original)
+++ lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldCache.java
Sat Sep  3 02:19:06 2011
@@ -309,6 +309,14 @@ public interface FieldCache {
       return FieldCache.class.getName()+".NUMERIC_UTILS_DOUBLE_PARSER"; 
     }
   };
+
+  /** Checks the internal cache for an appropriate entry, and if none is found,
+   * reads the terms in <code>field</code> and returns a bit set at the size
of
+   * <code>reader.maxDoc()</code>, with turned on bits for each docid that 
+   * does not have a value for this field.
+   */
+  public DocIdSet getUnValuedDocs (IndexReader reader, String field) 
+  throws IOException;
   
   /** Checks the internal cache for an appropriate entry, and if none is
    * found, reads the terms in <code>field</code> as a single byte and returns
an array

Modified: lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java?rev=1164794&r1=1164793&r2=1164794&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java
(original)
+++ lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java
Sat Sep  3 02:19:06 2011
@@ -20,6 +20,7 @@ package org.apache.lucene.search;
 import java.io.IOException;
 import java.io.PrintStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -29,6 +30,9 @@ import org.apache.lucene.index.IndexRead
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermDocs;
 import org.apache.lucene.index.TermEnum;
+import org.apache.lucene.util.BitVector;
+import org.apache.lucene.util.DocIdBitSet;
+import org.apache.lucene.util.OpenBitSet;
 import org.apache.lucene.util.StringHelper;
 import org.apache.lucene.util.FieldCacheSanityChecker;
 
@@ -47,7 +51,7 @@ class FieldCacheImpl implements FieldCac
     init();
   }
   private synchronized void init() {
-    caches = new HashMap<Class<?>,Cache>(7);
+    caches = new HashMap<Class<?>,Cache>(9);
     caches.put(Byte.TYPE, new ByteCache(this));
     caches.put(Short.TYPE, new ShortCache(this));
     caches.put(Integer.TYPE, new IntCache(this));
@@ -56,6 +60,7 @@ class FieldCacheImpl implements FieldCac
     caches.put(Double.TYPE, new DoubleCache(this));
     caches.put(String.class, new StringCache(this));
     caches.put(StringIndex.class, new StringIndexCache(this));
+    caches.put(UnValuedDocsCache.class, new UnValuedDocsCache(this));
   }
 
   public synchronized void purgeAllCaches() {
@@ -409,6 +414,42 @@ class FieldCacheImpl implements FieldCac
     }
   }
 
+  static final class UnValuedDocsCache extends Cache {
+    UnValuedDocsCache(FieldCache wrapper) {
+      super(wrapper);
+    }
+    
+    @Override
+    protected Object createValue(IndexReader reader, Entry entryKey)
+    throws IOException {
+      Entry entry = entryKey;
+      String field = entry.field;
+      
+      if (reader.maxDoc() == reader.docFreq(new Term(field))) {
+        return DocIdSet.EMPTY_DOCIDSET;
+      }
+      
+      OpenBitSet res = new OpenBitSet(reader.maxDoc());
+      TermDocs termDocs = reader.termDocs();
+      TermEnum termEnum = reader.terms (new Term (field));
+      try {
+        do {
+          Term term = termEnum.term();
+          if (term==null || term.field() != field) break;
+          termDocs.seek (termEnum);
+          while (termDocs.next()) {
+            res.fastSet(termDocs.doc());
+          }
+        } while (termEnum.next());
+      } finally {
+        termDocs.close();
+        termEnum.close();
+      }
+      res.flip(0, reader.maxDoc());
+      return res;
+    }
+  }
+  
 
   // inherit javadocs
   public float[] getFloats (IndexReader reader, String field)
@@ -471,7 +512,7 @@ class FieldCacheImpl implements FieldCac
   public long[] getLongs(IndexReader reader, String field) throws IOException {
     return getLongs(reader, field, null);
   }
-
+  
   // inherit javadocs
   public long[] getLongs(IndexReader reader, String field, FieldCache.LongParser parser)
       throws IOException {
@@ -695,5 +736,10 @@ class FieldCacheImpl implements FieldCac
   public PrintStream getInfoStream() {
     return infoStream;
   }
+  
+  public DocIdSet getUnValuedDocs(IndexReader reader, String field)
+      throws IOException {
+    return (DocIdSet) caches.get(UnValuedDocsCache.class).get(reader, new Entry(field, null));
 
+  }
 }
 

Modified: lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldComparator.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldComparator.java?rev=1164794&r1=1164793&r2=1164794&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldComparator.java
(original)
+++ lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/FieldComparator.java
Sat Sep  3 02:19:06 2011
@@ -29,6 +29,7 @@ import org.apache.lucene.search.FieldCac
 import org.apache.lucene.search.FieldCache.IntParser;
 import org.apache.lucene.search.FieldCache.ShortParser;
 import org.apache.lucene.search.FieldCache.StringIndex;
+import org.apache.lucene.util.OpenBitSet;
 
 /**
  * Expert: a FieldComparator compares hits so as to determine their
@@ -83,6 +84,14 @@ import org.apache.lucene.search.FieldCac
  */
 public abstract class FieldComparator<T> {
 
+  protected T missingValue = null;
+  
+  /** Set a default sorting value for documents which lacks one */
+  public FieldComparator<T> setMissingValue(T missingValue) {
+    this.missingValue = missingValue;
+    return this;
+  }
+  
   /**
    * Compare hit at slot1 with hit at slot2.
    * 
@@ -205,6 +214,13 @@ public abstract class FieldComparator<T>
     @Override
     public void setNextReader(IndexReader reader, int docBase) throws IOException {
       currentReaderValues = FieldCache.DEFAULT.getBytes(reader, field, parser);
+      if (missingValue != null) {
+        DocIdSetIterator iterator = FieldCache.DEFAULT.getUnValuedDocs(reader, field).iterator();
+        final byte byteValue = missingValue.byteValue();
+        for (int doc=iterator.nextDoc(); doc!=DocIdSetIterator.NO_MORE_DOCS; doc=iterator.nextDoc())
{
+          currentReaderValues[doc] = byteValue;
+        }
+      }
     }
     
     @Override
@@ -312,6 +328,13 @@ public abstract class FieldComparator<T>
     @Override
     public void setNextReader(IndexReader reader, int docBase) throws IOException {
       currentReaderValues = FieldCache.DEFAULT.getDoubles(reader, field, parser);
+      if (missingValue != null) {
+        DocIdSetIterator iterator = FieldCache.DEFAULT.getUnValuedDocs(reader, field).iterator();
+        final double doubleValue = missingValue.doubleValue();
+        for (int doc=iterator.nextDoc(); doc!=DocIdSetIterator.NO_MORE_DOCS; doc=iterator.nextDoc())
{
+          currentReaderValues[doc] = doubleValue;
+        }
+      }
     }
     
     @Override
@@ -377,6 +400,13 @@ public abstract class FieldComparator<T>
     @Override
     public void setNextReader(IndexReader reader, int docBase) throws IOException {
       currentReaderValues = FieldCache.DEFAULT.getFloats(reader, field, parser);
+      if (missingValue != null) {
+        DocIdSetIterator iterator = FieldCache.DEFAULT.getUnValuedDocs(reader, field).iterator();
+        final float floatValue = missingValue.floatValue();
+        for (int doc=iterator.nextDoc(); doc!=DocIdSetIterator.NO_MORE_DOCS; doc=iterator.nextDoc())
{
+          currentReaderValues[doc] = floatValue;
+        }
+      }
     }
     
     @Override
@@ -446,6 +476,13 @@ public abstract class FieldComparator<T>
     @Override
     public void setNextReader(IndexReader reader, int docBase) throws IOException {
       currentReaderValues = FieldCache.DEFAULT.getInts(reader, field, parser);
+      if (missingValue != null) {
+        DocIdSetIterator iterator = FieldCache.DEFAULT.getUnValuedDocs(reader, field).iterator();
+        final int intValue = missingValue.intValue();
+        for (int doc=iterator.nextDoc(); doc!=DocIdSetIterator.NO_MORE_DOCS; doc=iterator.nextDoc())
{
+          currentReaderValues[doc] = intValue;
+        }
+      }
     }
     
     @Override
@@ -511,6 +548,13 @@ public abstract class FieldComparator<T>
     @Override
     public void setNextReader(IndexReader reader, int docBase) throws IOException {
       currentReaderValues = FieldCache.DEFAULT.getLongs(reader, field, parser);
+      if (missingValue != null) {
+        DocIdSetIterator iterator = FieldCache.DEFAULT.getUnValuedDocs(reader, field).iterator();
+        final long longValue = missingValue.longValue();
+        for (int doc=iterator.nextDoc(); doc!=DocIdSetIterator.NO_MORE_DOCS; doc=iterator.nextDoc())
{
+          currentReaderValues[doc] = longValue;
+        }
+      }
     }
     
     @Override
@@ -625,6 +669,13 @@ public abstract class FieldComparator<T>
     @Override
     public void setNextReader(IndexReader reader, int docBase) throws IOException {
       currentReaderValues = FieldCache.DEFAULT.getShorts(reader, field, parser);
+      if (missingValue != null) {
+        DocIdSetIterator iterator = FieldCache.DEFAULT.getUnValuedDocs(reader, field).iterator();
+        final short shortValue = missingValue.shortValue();
+        for (int doc=iterator.nextDoc(); doc!=DocIdSetIterator.NO_MORE_DOCS; doc=iterator.nextDoc())
{
+          currentReaderValues[doc] = shortValue;
+        }
+      }
     }
     
     @Override

Modified: lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/SortField.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/SortField.java?rev=1164794&r1=1164793&r2=1164794&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/SortField.java
(original)
+++ lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/SortField.java
Sat Sep  3 02:19:06 2011
@@ -102,6 +102,8 @@ implements Serializable {
   // Used for CUSTOM sort
   private FieldComparatorSource comparatorSource;
 
+  private Object missingValue;
+
   /** Creates a sort by terms in the given field with the type of term
    * values explicitly given.
    * @param field  Name of field to sort by.  Can be <code>null</code> if
@@ -204,6 +206,16 @@ implements Serializable {
     this.comparatorSource = comparator;
   }
 
+  /** Set a default sorting value for documents which lacks one */
+  public SortField setMissingValue(Object missingValue) {
+    if (type != BYTE && type != SHORT && type != INT && type != FLOAT
&& type != LONG && type != DOUBLE) {
+      throw new IllegalArgumentException( "Missing value only works for numeric types" );
+    }
+    this.missingValue = missingValue;
+    
+    return this;
+  }
+  
   // Sets field & type, and ensures field is not NULL unless
   // type is SCORE or DOC
   private void initFieldType(String field, int type) {
@@ -391,22 +403,22 @@ implements Serializable {
       return new FieldComparator.DocComparator(numHits);
 
     case SortField.INT:
-      return new FieldComparator.IntComparator(numHits, field, parser);
+      return new FieldComparator.IntComparator(numHits, field, parser).setMissingValue((Integer)
missingValue);
 
     case SortField.FLOAT:
-      return new FieldComparator.FloatComparator(numHits, field, parser);
+      return new FieldComparator.FloatComparator(numHits, field, parser).setMissingValue((Float)
missingValue);
 
     case SortField.LONG:
-      return new FieldComparator.LongComparator(numHits, field, parser);
+      return new FieldComparator.LongComparator(numHits, field, parser).setMissingValue((Long)
missingValue);
 
     case SortField.DOUBLE:
-      return new FieldComparator.DoubleComparator(numHits, field, parser);
+      return new FieldComparator.DoubleComparator(numHits, field, parser).setMissingValue((Double)
missingValue);
 
     case SortField.BYTE:
-      return new FieldComparator.ByteComparator(numHits, field, parser);
+      return new FieldComparator.ByteComparator(numHits, field, parser).setMissingValue((Byte)
missingValue);
 
     case SortField.SHORT:
-      return new FieldComparator.ShortComparator(numHits, field, parser);
+      return new FieldComparator.ShortComparator(numHits, field, parser).setMissingValue((Short)
missingValue);
 
     case SortField.CUSTOM:
       assert comparatorSource != null;

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestSort.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestSort.java?rev=1164794&r1=1164793&r2=1164794&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestSort.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestSort.java Sat
Sep  3 02:19:06 2011
@@ -68,6 +68,7 @@ public class TestSort extends LuceneTest
   private Query queryE;
   private Query queryF;
   private Query queryG;
+  private Query queryM;
   private Sort sort;
 
   @BeforeClass
@@ -82,22 +83,28 @@ public class TestSort extends LuceneTest
   // the string field to sort by string
     // the i18n field includes accented characters for testing locale-specific sorting
   private String[][] data = new String[][] {
-  // tracer  contents         int            float           string   custom   i18n     
         long            double, 'short', byte, 'custom parser encoding'
-  {   "A",   "x a",           "5",           "4f",           "c",     "A-3",   "p\u00EAche",
     "10",           "-4.0", "3", "126", "J"},//A, x
-  {   "B",   "y a",           "5",           "3.4028235E38", "i",     "B-10",  "HAT",   
         "1000000000", "40.0", "24", "1", "I"},//B, y
-  {   "C",   "x a b c",       "2147483647",  "1.0",          "j",     "A-2",   "p\u00E9ch\u00E9",
"99999999",   "40.00002343", "125", "15", "H"},//C, x
-  {   "D",   "y a b c",       "-1",          "0.0f",         "a",     "C-0",   "HUT",   
         String.valueOf(Long.MAX_VALUE),           String.valueOf(Double.MIN_VALUE), String.valueOf(Short.MIN_VALUE),
String.valueOf(Byte.MIN_VALUE), "G"},//D, y
-  {   "E",   "x a b c d",     "5",           "2f",           "h",     "B-8",   "peach", 
         String.valueOf(Long.MIN_VALUE),           String.valueOf(Double.MAX_VALUE), String.valueOf(Short.MAX_VALUE),
          String.valueOf(Byte.MAX_VALUE), "F"},//E,x
-  {   "F",   "y a b c d",     "2",           "3.14159f",     "g",     "B-1",   "H\u00C5T",
       "-44",           "343.034435444", "-3", "0", "E"},//F,y
-  {   "G",   "x a b c d",     "3",           "-1.0",         "f",     "C-100", "sin",   
         "323254543543", "4.043544", "5", "100", "D"},//G,x
-  {   "H",   "y a b c d",     "0",           "1.4E-45",      "e",     "C-88",  "H\u00D8T",
       "1023423423005","4.043545", "10", "-50", "C"},//H,y
-  {   "I",   "x a b c d e f", "-2147483648", "1.0e+0",       "d",     "A-10",  "s\u00EDn",
       "332422459999", "4.043546", "-340", "51", "B"},//I,x
-  {   "J",   "y a b c d e f", "4",           ".5",           "b",     "C-7",   "HOT",   
         "34334543543",  "4.0000220343", "300", "2", "A"},//J,y
+  // tracer  contents         int            float           string   custom   i18n     
         long            double,          short,     byte, 'custom parser encoding'
+  {   "A",   "x a",           "5",           "4f",           "c",     "A-3",   "p\u00EAche",
     "10",           "-4.0",            "3",    "126", "J"},//A, x
+  {   "B",   "y a",           "5",           "3.4028235E38", "i",     "B-10",  "HAT",   
         "1000000000",   "40.0",           "24",      "1", "I"},//B, y
+  {   "C",   "x a b c",       "2147483647",  "1.0",          "j",     "A-2",   "p\u00E9ch\u00E9",
"99999999","40.00002343",        "125",     "15", "H"},//C, x
+  {   "D",   "y a b c",       "-1",          "0.0f",         "a",     "C-0",   "HUT",   String.valueOf(Long.MAX_VALUE),String.valueOf(Double.MIN_VALUE),
String.valueOf(Short.MIN_VALUE), String.valueOf(Byte.MIN_VALUE), "G"},//D, y
+  {   "E",   "x a b c d",     "5",           "2f",           "h",     "B-8",   "peach", String.valueOf(Long.MIN_VALUE),String.valueOf(Double.MAX_VALUE),
String.valueOf(Short.MAX_VALUE),           String.valueOf(Byte.MAX_VALUE), "F"},//E,x
+  {   "F",   "y a b c d",     "2",           "3.14159f",     "g",     "B-1",   "H\u00C5T",
       "-44",          "343.034435444",  "-3",      "0", "E"},//F,y
+  {   "G",   "x a b c d",     "3",           "-1.0",         "f",     "C-100", "sin",   
         "323254543543", "4.043544",        "5",    "100", "D"},//G,x
+  {   "H",   "y a b c d",     "0",           "1.4E-45",      "e",     "C-88",  "H\u00D8T",
       "1023423423005","4.043545",       "10",    "-50", "C"},//H,y
+  {   "I",   "x a b c d e f", "-2147483648", "1.0e+0",       "d",     "A-10",  "s\u00EDn",
       "332422459999", "4.043546",     "-340",     "51", "B"},//I,x
+  {   "J",   "y a b c d e f", "4",           ".5",           "b",     "C-7",   "HOT",   
         "34334543543",  "4.0000220343",  "300",      "2", "A"},//J,y
   {   "W",   "g",             "1",           null,           null,    null,    null,    
         null,           null, null, null, null},
   {   "X",   "g",             "1",           "0.1",          null,    null,    null,    
         null,           null, null, null, null},
   {   "Y",   "g",             "1",           "0.2",          null,    null,    null,    
         null,           null, null, null, null},
-  {   "Z",   "f g",           null,          null,           null,    null,    null,    
         null,           null, null, null, null}
-  };
+  {   "Z",   "f g",           null,          null,           null,    null,    null,    
         null,           null, null, null, null},
+  
+  // Sort Missing first/last
+  {   "a",   "m",            null,          null,           null,    null,    null,     
        null,           null, null, null, null},
+  {   "b",   "m",            "4",           "4.0",           "4",    null,    null,     
        "4",           "4", "4", "4", null},
+  {   "c",   "m",            "5",           "5.0",           "5",    null,    null,     
        "5",           "5", "5", "5", null},
+  {   "d",   "m",            null,          null,           null,    null,    null,     
        null,           null, null, null, null}
+  }; 
   
   // the sort order of Ø versus U depends on the version of the rules being used
   // for the inherited root locale: Ø's order isnt specified in Locale.US since 
@@ -224,6 +231,7 @@ public class TestSort extends LuceneTest
     queryE = new TermQuery (new Term ("contents", "e"));
     queryF = new TermQuery (new Term ("contents", "f"));
     queryG = new TermQuery (new Term ("contents", "g"));
+    queryM = new TermQuery (new Term ("contents", "m"));
     sort = new Sort();
   }
   
@@ -284,6 +292,68 @@ public class TestSort extends LuceneTest
     assertMatches (full, queryY, sort, "DJHFB");
   }
   
+  private static class SortMissingLastTestHelper {
+    final SortField sortField;
+    final Object min;
+    final Object max;
+    
+    SortMissingLastTestHelper( SortField sortField, Object min, Object max ) {
+      this.sortField = sortField;
+      this.min = min;
+      this.max = max;
+    }
+  }
+
+  // test sorts where the type of field is specified
+  public void testSortMissingLast() throws Exception {
+    
+    @SuppressWarnings("boxing")
+    SortMissingLastTestHelper[] ascendTesters = new SortMissingLastTestHelper[] {
+        new SortMissingLastTestHelper( new SortField(   "byte",   SortField.BYTE ), Byte.MIN_VALUE,
   Byte.MAX_VALUE ),
+        new SortMissingLastTestHelper( new SortField(  "short",  SortField.SHORT ), Short.MIN_VALUE,
  Short.MAX_VALUE ),
+        new SortMissingLastTestHelper( new SortField(    "int",    SortField.INT ), Integer.MIN_VALUE,
Integer.MAX_VALUE ),
+        new SortMissingLastTestHelper( new SortField(   "long",   SortField.LONG ), Long.MIN_VALUE,
   Long.MAX_VALUE ),
+        new SortMissingLastTestHelper( new SortField(  "float",  SortField.FLOAT ), Float.MIN_VALUE,
  Float.MAX_VALUE ),
+        new SortMissingLastTestHelper( new SortField( "double", SortField.DOUBLE ), Double.MIN_VALUE,
 Double.MAX_VALUE ),
+    };
+    
+    @SuppressWarnings("boxing")
+    SortMissingLastTestHelper[] descendTesters = new SortMissingLastTestHelper[] {
+      new SortMissingLastTestHelper( new SortField(   "byte",   SortField.BYTE, true ), Byte.MIN_VALUE,
   Byte.MAX_VALUE ),
+      new SortMissingLastTestHelper( new SortField(  "short",  SortField.SHORT, true ), Short.MIN_VALUE,
  Short.MAX_VALUE ),
+      new SortMissingLastTestHelper( new SortField(    "int",    SortField.INT, true ), Integer.MIN_VALUE,
Integer.MAX_VALUE ),
+      new SortMissingLastTestHelper( new SortField(   "long",   SortField.LONG, true ), Long.MIN_VALUE,
   Long.MAX_VALUE ),
+      new SortMissingLastTestHelper( new SortField(  "float",  SortField.FLOAT, true ), Float.MIN_VALUE,
  Float.MAX_VALUE ),
+      new SortMissingLastTestHelper( new SortField( "double", SortField.DOUBLE, true ), Double.MIN_VALUE,
 Double.MAX_VALUE ),
+    };
+    
+    // Default order: ascending
+    for( SortMissingLastTestHelper t : ascendTesters ) {
+      sort.setSort (t.sortField, SortField.FIELD_DOC );
+      assertMatches("sortField:"+t.sortField, full, queryM, sort, "adbc" );
+
+      sort.setSort (t.sortField.setMissingValue( t.max ), SortField.FIELD_DOC );
+      assertMatches("sortField:"+t.sortField, full, queryM, sort, "bcad" );
+
+      sort.setSort (t.sortField.setMissingValue( t.min ), SortField.FIELD_DOC );
+      assertMatches("sortField:"+t.sortField, full, queryM, sort, "adbc" );
+    }
+    
+    // Reverse order: descending (Note: Order for un-valued documents remains the same due
to tie breaker: a,d)
+    for( SortMissingLastTestHelper t : descendTesters ) {
+      sort.setSort (t.sortField, SortField.FIELD_DOC );
+      assertMatches("sortField:"+t.sortField, full, queryM, sort, "cbad" );
+      
+      sort.setSort (t.sortField.setMissingValue( t.max ), SortField.FIELD_DOC );
+      assertMatches("sortField:"+t.sortField, full, queryM, sort, "adcb" );
+      
+      sort.setSort (t.sortField.setMissingValue( t.min ), SortField.FIELD_DOC );
+      assertMatches("sortField:"+t.sortField, full, queryM, sort, "cbad" );
+    }
+    
+    
+  }
+  
   /**
    * Test String sorting: small queue to many matches, multi field sort, reverse sort
    */
@@ -1056,13 +1126,17 @@ public class TestSort extends LuceneTest
 
   }
 
+  private void assertMatches(Searcher searcher, Query query, Sort sort, String expectedResult)
throws IOException {
+    assertMatches( null, searcher, query, sort, expectedResult );
+  }
+
   // make sure the documents returned by the search match the expected list
-  private void assertMatches(Searcher searcher, Query query, Sort sort,
+  private void assertMatches(String msg, Searcher searcher, Query query, Sort sort,
       String expectedResult) throws IOException {
     //ScoreDoc[] result = searcher.search (query, null, 1000, sort).scoreDocs;
     TopDocs hits = searcher.search (query, null, Math.max(1, expectedResult.length()), sort);
     ScoreDoc[] result = hits.scoreDocs;
-    assertEquals(hits.totalHits, expectedResult.length());
+    assertEquals(expectedResult.length(),hits.totalHits);
     StringBuilder buff = new StringBuilder(10);
     int n = result.length;
     for (int i=0; i<n; ++i) {
@@ -1072,7 +1146,7 @@ public class TestSort extends LuceneTest
         buff.append (v[j]);
       }
     }
-    assertEquals (expectedResult, buff.toString());
+    assertEquals (msg, expectedResult, buff.toString());
   }
 
   private HashMap<String,Float> getScores (ScoreDoc[] hits, Searcher searcher)



Mime
View raw message