You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-commits@lucene.apache.org by ry...@apache.org on 2007/06/20 03:38:19 UTC
svn commit: r548887 -
/lucene/solr/trunk/src/java/org/apache/solr/schema/RandomSortField.java
Author: ryan
Date: Tue Jun 19 18:38:18 2007
New Revision: 548887
URL: http://svn.apache.org/viewvc?view=rev&rev=548887
Log:
SOLR-264 - updating the RandomSortField so it follows the Comparator contract. This uses the: field name hash, docID, and reader version as a random generator seed.
This may not be the final version, but it is better then the existing one...
Modified:
lucene/solr/trunk/src/java/org/apache/solr/schema/RandomSortField.java
Modified: lucene/solr/trunk/src/java/org/apache/solr/schema/RandomSortField.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/schema/RandomSortField.java?view=diff&rev=548887&r1=548886&r2=548887
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/schema/RandomSortField.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/schema/RandomSortField.java Tue Jun 19 18:38:18 2007
@@ -18,7 +18,6 @@
package org.apache.solr.schema;
import java.io.IOException;
-import java.util.Random;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.index.IndexReader;
@@ -28,13 +27,15 @@
import org.apache.lucene.search.SortField;
import org.apache.solr.request.TextResponseWriter;
import org.apache.solr.request.XMLWriter;
+import org.apache.solr.search.function.DocValues;
import org.apache.solr.search.function.ValueSource;
/**
* Utility Field used for random sorting. It should not be passed a value.
*
- * To enable random sorting, you will need to add something like this
- * to the schema.xml
+ * This random sorting implementation uses the dynamic field name to set the
+ * random 'seed'. To get random sorting order, you need to use a random
+ * dynamic field name. For example, you will need to configure schema.xml:
*
* <types>
* ...
@@ -43,63 +44,164 @@
* </types>
* <fields>
* ...
- * <field name="random" type="random" indexed="true" stored="false"/>
+ * <dynamicField name="random*" type="rand" indexed="true" stored="false"/>
* ...
* </fields>
+ *
+ * http://localhost:8983/solr/select/?q=*:*&fl=name&sort=rand_1234%20desc
+ * http://localhost:8983/solr/select/?q=*:*&fl=name&sort=rand_2345%20desc
+ * http://localhost:8983/solr/select/?q=*:*&fl=name&sort=rand_ABDC%20desc
+ * http://localhost:8983/solr/select/?q=*:*&fl=name&sort=rand_21%20desc
*
+ * Note that multiple calls to the same URL will return the same sorting order.
+ *
* @author ryan
+ * @author yonik
* @version $Id$
* @since solr 1.3
*/
-public class RandomSortField extends FieldType
-{
- /** Special comparator for sorting hits in random order */
- private static final ScoreDocComparator COMPARE = new ScoreDocComparator() {
- final Random rand = new Random();
-
- public int compare (ScoreDoc i, ScoreDoc j) {
- return (rand.nextInt() & 0x2) - 1; // (rand.nextBoolean()) ? 1 : -1;
+public class RandomSortField extends FieldType {
+ // Thomas Wang's hash32shift function, from http://www.cris.com/~Ttwang/tech/inthash.htm
+ // slightly modified to return only positive integers.
+ private static int hash(int key) {
+ key = ~key + (key << 15); // key = (key << 15) - key - 1;
+ key = key ^ (key >>> 12);
+ key = key + (key << 2);
+ key = key ^ (key >>> 4);
+ key = key * 2057; // key = (key + (key << 3)) + (key << 11);
+ key = key ^ (key >>> 16);
+ return key >>> 1;
+ }
+
+ private static class RandomComparator implements ScoreDocComparator {
+ final int seed;
+
+ RandomComparator(int seed) {
+ this.seed = seed;
}
- public Comparable sortValue (ScoreDoc i) {
- return new Float(rand.nextFloat());
+
+ public int compare(ScoreDoc i, ScoreDoc j) {
+ return hash(i.doc + seed) - hash(j.doc + seed);
}
+
+ public Comparable sortValue(ScoreDoc i) {
+ return new Integer(hash(i.doc + seed));
+ }
+
public int sortType() {
return SortField.CUSTOM;
}
};
-
- /** use random sorting order. */
+
+ /** given a field name, get a random hash seed -- using dynamic fields, you can force the random order to change */
+ private static int getSeed(String fieldName) {
+ return fieldName.hashCode();
+ }
+
private static class RandomSort extends SortField {
- public RandomSort( String n )
- {
- super( n, SortField.CUSTOM );
+ public RandomSort(String n, boolean reverse) {
+ super(n, SortField.CUSTOM, reverse);
}
@Override
public SortComparatorSource getFactory() {
+ final int seed = getSeed(getField());
+
return new SortComparatorSource() {
public ScoreDocComparator newComparator(IndexReader reader, String fieldname) throws IOException {
- return COMPARE;
+ return new RandomComparator( (int)(seed^reader.getVersion()) );
+ }
+
+ @Override
+ public int hashCode() {
+ return getField().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof RandomSort) && getField().equals(((RandomSort) o).getField());
}
};
}
}
-
+
+ public class RandomValueSource extends ValueSource {
+ private final String field;
+ final int seed;
+
+ public RandomValueSource(String field) {
+ this.field=field;
+ seed = getSeed(field);
+ }
+
+ @Override
+ public String description() {
+ return field;
+ }
+
+ @Override
+ public DocValues getValues(IndexReader reader) throws IOException {
+ return new DocValues() {
+ @Override
+ public float floatVal(int doc) {
+ return (float)hash(doc+seed);
+ }
+
+ @Override
+ public int intVal(int doc) {
+ return (int)hash(doc+seed);
+ }
+
+ @Override
+ public long longVal(int doc) {
+ return (long)hash(doc+seed);
+ }
+
+ @Override
+ public double doubleVal(int doc) {
+ return (double)hash(doc+seed);
+ }
+
+ @Override
+ public String strVal(int doc) {
+ return Integer.toString(hash(doc+seed));
+ }
+
+ @Override
+ public String toString(int doc) {
+ return description() + '=' + intVal(doc);
+ }
+ };
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof RandomValueSource)) return false;
+ RandomValueSource other = (RandomValueSource)o;
+ return this.field.equals(other.field);
+ }
+
+ @Override
+ public int hashCode() {
+ return field.hashCode();
+ };
+ }
+
@Override
- public SortField getSortField(SchemaField field,boolean reverse) {
- return new RandomSort(field.getName());
+ public SortField getSortField(SchemaField field, boolean reverse) {
+ return new RandomSort(field.getName(), reverse);
}
@Override
public ValueSource getValueSource(SchemaField field) {
- throw new UnsupportedOperationException("Random field does not have a value source");
+ return new RandomValueSource(field.getName());
}
@Override
- public void write(XMLWriter xmlWriter, String name, Fieldable f) {}
+ public void write(XMLWriter xmlWriter, String name, Fieldable f) throws IOException { }
@Override
- public void write(TextResponseWriter writer, String name, Fieldable f) {}
+ public void write(TextResponseWriter writer, String name, Fieldable f) throws IOException { }
}