Index: src/java/org/apache/lucene/search/TopFieldCollector.java
===================================================================
--- src/java/org/apache/lucene/search/TopFieldCollector.java (revision 0)
+++ src/java/org/apache/lucene/search/TopFieldCollector.java (revision 0)
@@ -0,0 +1,204 @@
+package org.apache.lucene.search;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.FieldValueHitQueue.Entry;
+
+/**
+ * A {@link HitCollector} that sorts by {@link SortField} using
+ * {@link FieldComparator}s.
+ *
+ * NOTE: This API is experimental and might change in
+ * incompatible ways in the next release.
+ */
+public class TopFieldCollector extends MultiReaderHitCollector {
+
+ private final FieldValueHitQueue queue;
+
+ private final FieldComparator[] comparators;
+ private FieldComparator comparator1;
+ private final int numComparators;
+ private int[] reverseMul;
+ private int reverseMul1 = 0;
+
+ private int subReaderIndex = -1;
+
+ private final int numHits;
+ private int totalHits;
+ private FieldValueHitQueue.Entry weakest = null;
+
+ /** Stores the maximum score value encountered, needed for normalizing. */
+ private float maxScore = Float.NEGATIVE_INFINITY;
+
+ private boolean queueFull;
+
+ private boolean fillFields;
+
+ private ComparatorPolicy[] comparatorPolicies;
+
+
+ public TopFieldCollector(Sort sort, int numHits, IndexReader[] subReaders, boolean fillFields)
+ throws IOException {
+ queue = new FieldValueHitQueue(sort.fields, numHits, subReaders);
+ comparators = queue.getComparators();
+ comparatorPolicies = queue.getComparatorPolicies();
+ reverseMul = queue.getReverseMul();
+ numComparators = comparatorPolicies.length;
+
+
+ this.numHits = numHits;
+
+ this.fillFields = fillFields;
+
+ }
+
+ static boolean first = true;
+
+ // javadoc inherited
+ public void setNextReader(IndexReader reader, int docBase) throws IOException {
+ final int numSlotsFull;
+ if (queueFull)
+ numSlotsFull = numHits;
+ else
+ numSlotsFull = totalHits;
+
+ subReaderIndex++;
+ for (int i = 0; i < numComparators; i++) {
+ FieldComparator comparator = comparatorPolicies[i].nextComparator(comparators[i], reader, numHits, numSlotsFull);
+ comparator.setNextReader(reader, docBase, numSlotsFull);
+ // nocommit
+ if (first) {
+ System.out.println("COMP=" + comparator);
+ first = false;
+ }
+ comparators[i] = comparator;
+ }
+ if (numComparators == 1) {
+ comparator1 = comparators[0];
+ reverseMul1 = reverseMul[0];
+ } else {
+ comparator1 = null;
+ reverseMul1 = 0;
+ }
+ queue.setComparator1(comparator1);
+ queue.setReverseMul1(reverseMul1);
+ }
+
+ // javadoc inherited
+ public void collect(int doc, float score) {
+ if (score > 0.0f) {
+
+ maxScore = Math.max(maxScore, score);
+ totalHits++;
+
+ if (queueFull) {
+ // Fastmatch: return if this hit is not competitive
+ if (numComparators == 1) {
+ // Common case
+ if (reverseMul1*comparator1.compareBottom(doc, score) <= 0) {
+ // Definitely not competitive
+ return;
+ }
+
+ // This hit is competitive -- replace weakest
+ // element in queue & adjustTop
+ comparator1.copy(weakest.slot, doc, score);
+ } else {
+ for(int i=0;;i++) {
+ final int c = reverseMul[i] * comparators[i].compare(weakest.slot, doc, score);
+ if (c < 0) {
+ // Definitely not competitive
+ return;
+ } else if (c > 0) {
+ // Definitely competitive
+ break;
+ } else if (i == numComparators-1) {
+ // This is the equals case. We don't need to
+ // fallback to docID comparison because lower
+ // docIDs always win, and this docID must be
+ // greater than all docIDs in the queue now,
+ // so this hit is not competitive.
+ return;
+ }
+ }
+
+ // This hit is competitive -- replace weakest
+ // element in queue & adjustTop
+ for (int i = 0; i < numComparators; i++) {
+ comparators[i].copy(weakest.slot, doc, score);
+ }
+ }
+
+ weakest.subReaderIndex = subReaderIndex;
+ weakest.subDocID = doc;
+ weakest.score = score;
+ queue.adjustTop();
+ weakest = (FieldValueHitQueue.Entry) queue.top();
+
+ comparators[0].setBottom(weakest.slot);
+ } else {
+ // Startup transient: queue hasn't gathered numHits
+ // yet
+
+ final int slot = totalHits-1;
+
+ // Copy hit into queue
+ if (numComparators == 1) {
+ // Common case
+ comparator1.copy(slot, doc, score);
+ } else {
+ for (int i = 0; i < numComparators; i++) {
+ comparators[i].copy(slot, doc, score);
+ }
+ }
+
+ queue.put(new FieldValueHitQueue.Entry(slot,
+ subReaderIndex, doc, score));
+
+ weakest = (FieldValueHitQueue.Entry) queue.top();
+ queueFull = totalHits == numHits;
+
+ if (queueFull) {
+ comparators[0].setBottom(weakest.slot);
+ }
+ }
+ }
+ }
+
+ // javadoc inherited
+ public TopDocs topDocs(int[] starts) {
+ ScoreDoc[] scoreDocs = new ScoreDoc[queue.size()];
+ if (fillFields) {
+ for (int i = queue.size() - 1; i >= 0; i--) {
+ scoreDocs[i] = queue.fillFields((FieldValueHitQueue.Entry) queue.pop(),
+ starts);
+ }
+ } else {
+ Entry entry = (FieldValueHitQueue.Entry) queue.pop();
+ for (int i = queue.size() - 1; i >= 0; i--) {
+ scoreDocs[i] = new FieldDoc(entry.subDocID + starts[entry.subReaderIndex],
+ entry.score);
+ }
+ }
+
+ return new TopFieldDocs(totalHits, scoreDocs, queue.getFields(), maxScore);
+ }
+}
Property changes on: src/java/org/apache/lucene/search/TopFieldCollector.java
___________________________________________________________________
Name: svn:eol-style
+ native
Index: src/java/org/apache/lucene/search/FieldComparator.java
===================================================================
--- src/java/org/apache/lucene/search/FieldComparator.java (revision 0)
+++ src/java/org/apache/lucene/search/FieldComparator.java (revision 0)
@@ -0,0 +1,1256 @@
+package org.apache.lucene.search;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.ExtendedFieldCache.DoubleParser;
+import org.apache.lucene.search.ExtendedFieldCache.LongParser;
+import org.apache.lucene.search.FieldCache.ByteParser;
+import org.apache.lucene.search.FieldCache.FloatParser;
+import org.apache.lucene.search.FieldCache.IntParser;
+import org.apache.lucene.search.FieldCache.ShortParser;
+import org.apache.lucene.search.FieldCache.StringIndex;
+
+/**
+ * A FieldComparator compares hits across multiple IndexReaders.
+ *
+ * A comparator can compare a hit at hit 'slot a' with hit 'slot b',
+ * compare a hit on 'doc i' with hit 'slot a', or copy a hit at 'doc i'
+ * to 'slot a'. Each slot refers to a hit while each doc refers to the
+ * current IndexReader.
+ *
+ * NOTE: This API is experimental and might change in
+ * incompatible ways in the next release.
+ */
+public abstract class FieldComparator {
+
+ public static final class ByteComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+
+ private final byte[] values;
+ private byte[] currentReaderValues;
+ private final String field;
+ private ByteParser parser;
+
+ ByteComparator(int numHits, String field, FieldCache.Parser parser) {
+ values = new byte[numHits];
+ this.field = field;
+ this.parser = (ByteParser) parser;
+ }
+
+ public int compare(int slot1, int slot2) {
+ return values[slot1] - values[slot2];
+ }
+
+ public int compare(int slot, int doc, float score) {
+ return (values[slot] - currentReaderValues[doc]);
+ }
+
+ public void copy(int slot, int doc, float score) {
+ values[slot] = currentReaderValues[doc];
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ currentReaderValues = parser != null ? ExtendedFieldCache.EXT_DEFAULT
+ .getBytes(reader, field, parser) : ExtendedFieldCache.EXT_DEFAULT
+ .getBytes(reader, field);
+ }
+
+ public int sortType() {
+ return SortField.BYTE;
+ }
+
+ public Comparable value(int slot) {
+ return new Byte(values[slot]);
+ }
+ };
+
+ public static final class DocComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+
+ private final int[] docIDs;
+ private int docBase;
+
+ DocComparator(int numHits) {
+ docIDs = new int[numHits];
+ }
+
+ public int compare(int slot1, int slot2) {
+ return docIDs[slot1] - docIDs[slot2];
+ }
+
+ public int compare(int slot, int doc, float score) {
+ return docIDs[slot] - docBase - doc;
+ }
+
+ public void copy(int slot, int doc, float score) {
+ docIDs[slot] = docBase + doc;
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) {
+ // TODO: can we "map" our docIDs to the current
+ // reader? saves having to then subtract on every
+ // compare call
+ this.docBase = docBase;
+ }
+
+ public int sortType() {
+ return SortField.DOC;
+ }
+
+ public Comparable value(int slot) {
+ return new Integer(docIDs[slot]);
+ }
+ };
+
+ public static final class DoubleComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+
+ private final double[] values;
+ private double[] currentReaderValues;
+ private final String field;
+ private DoubleParser parser;
+
+ DoubleComparator(int numHits, String field, FieldCache.Parser parser) {
+ values = new double[numHits];
+ this.field = field;
+ this.parser = (DoubleParser) parser;
+ }
+
+ public int compare(int slot1, int slot2) {
+ if (values[slot1] > values[slot2])
+ return 1;
+ if (values[slot1] < values[slot2])
+ return -1;
+ return 0;
+ }
+
+ public int compare(int slot, int doc, float score) {
+ if (values[slot] > currentReaderValues[doc])
+ return 1;
+ if (values[slot] < currentReaderValues[doc])
+ return -1;
+ return 0;
+ }
+
+ public void copy(int slot, int doc, float score) {
+ values[slot] = currentReaderValues[doc];
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ currentReaderValues = parser != null ? ExtendedFieldCache.EXT_DEFAULT
+ .getDoubles(reader, field, parser) : ExtendedFieldCache.EXT_DEFAULT
+ .getDoubles(reader, field);
+ }
+
+ public int sortType() {
+ return SortField.DOUBLE;
+ }
+
+ public Comparable value(int slot) {
+ return new Double(values[slot]);
+ }
+ };
+
+ public static final class FloatComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+
+ private final float[] values;
+ private float[] currentReaderValues;
+ private final String field;
+ private FloatParser parser;
+
+ FloatComparator(int numHits, String field, FieldCache.Parser parser) {
+ values = new float[numHits];
+ this.field = field;
+ this.parser = (FloatParser) parser;
+ }
+
+ public int compare(int slot1, int slot2) {
+ if (values[slot1] > values[slot2])
+ return 1;
+ if (values[slot1] < values[slot2])
+ return -1;
+ return 0;
+ }
+
+ public int compare(int slot, int doc, float score) {
+ float val = currentReaderValues[doc];
+ if (values[slot] > val)
+ return 1;
+ if (values[slot] < val)
+ return -1;
+ return 0;
+ }
+
+ public void copy(int slot, int doc, float score) {
+ values[slot] = currentReaderValues[doc];
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ currentReaderValues = parser != null ? FieldCache.DEFAULT.getFloats(
+ reader, field, parser) : FieldCache.DEFAULT.getFloats(reader, field);
+ }
+
+ public int sortType() {
+ return SortField.FLOAT;
+ }
+
+ public Comparable value(int slot) {
+ return new Float(values[slot]);
+ }
+ };
+
+ public static final class IntComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+
+ private final int[] values;
+ private int[] currentReaderValues;
+ private final String field;
+ private IntParser parser;
+
+ IntComparator(int numHits, String field, FieldCache.Parser parser) {
+ values = new int[numHits];
+ this.field = field;
+ this.parser = (IntParser) parser;
+ }
+
+ public int compare(int slot1, int slot2) {
+ if (values[slot1] > values[slot2])
+ return 1;
+ if (values[slot1] < values[slot2])
+ return -1;
+ return 0;
+ }
+
+ public int compare(int slot, int doc, float score) {
+ return values[slot] - currentReaderValues[doc];
+ }
+
+ public void copy(int slot, int doc, float score) {
+ values[slot] = currentReaderValues[doc];
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ currentReaderValues = parser != null ? FieldCache.DEFAULT.getInts(reader,
+ field, parser) : FieldCache.DEFAULT.getInts(reader, field);
+ }
+
+ public int sortType() {
+ return SortField.INT;
+ }
+
+ public Comparable value(int slot) {
+ return new Integer(values[slot]);
+ }
+ };
+
+ public static final class LongComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+
+ private final long[] values;
+ private long[] currentReaderValues;
+ private final String field;
+ private LongParser parser;
+
+ LongComparator(int numHits, String field, FieldCache.Parser parser) {
+ values = new long[numHits];
+ this.field = field;
+ this.parser = (LongParser) parser;
+ }
+
+ public int compare(int slot1, int slot2) {
+ if (values[slot1] > values[slot2])
+ return 1;
+ if (values[slot1] < values[slot2])
+ return -1;
+ return 0;
+ }
+
+ public int compare(int slot, int doc, float score) {
+ if (values[slot] > currentReaderValues[doc])
+ return 1;
+ if (values[slot] < currentReaderValues[doc])
+ return -1;
+ return 0;
+ }
+
+ public void copy(int slot, int doc, float score) {
+ values[slot] = currentReaderValues[doc];
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ currentReaderValues = parser != null ? ExtendedFieldCache.EXT_DEFAULT
+ .getLongs(reader, field, parser) : ExtendedFieldCache.EXT_DEFAULT
+ .getLongs(reader, field);
+ }
+
+ public int sortType() {
+ return SortField.LONG;
+ }
+
+ public Comparable value(int slot) {
+ return new Long(values[slot]);
+ }
+ };
+
+ public static final class RelevanceComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+
+ private final float[] scores;
+
+ RelevanceComparator(int numHits) {
+ scores = new float[numHits];
+ }
+
+ public int compare(int slot1, int slot2) {
+ float score1 = scores[slot1];
+ float score2 = scores[slot2];
+ if (score1 > score2)
+ return -1;
+ if (score1 < score2)
+ return 1;
+ return 0;
+ }
+
+ public int compare(int slot, int doc, float score) {
+ float slotScore = scores[slot];
+ if (slotScore > score)
+ return -1;
+ if (slotScore < score)
+ return 1;
+ return 0;
+ }
+
+ public void copy(int slot, int doc, float score) {
+ scores[slot] = score;
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) {
+ }
+
+ public int sortType() {
+ return SortField.SCORE;
+ }
+
+ public Comparable value(int slot) {
+ return new Float(scores[slot]);
+ }
+ };
+
+ public static final class ShortComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+
+ private final short[] values;
+ private short[] currentReaderValues;
+ private final String field;
+ private ShortParser parser;
+
+ ShortComparator(int numHits, String field, FieldCache.Parser parser) {
+ values = new short[numHits];
+ this.field = field;
+ this.parser = (ShortParser) parser;
+ }
+
+ public int compare(int slot1, int slot2) {
+ if (values[slot1] > values[slot2])
+ return 1;
+ if (values[slot1] < values[slot2])
+ return -1;
+ return 0;
+ }
+
+ public int compare(int slot, int doc, float score) {
+ if (values[slot] > currentReaderValues[doc])
+ return 1;
+ if (values[slot] < currentReaderValues[doc])
+ return -1;
+ return 0;
+ }
+
+ public void copy(int slot, int doc, float score) {
+ values[slot] = currentReaderValues[doc];
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ currentReaderValues = parser != null ? ExtendedFieldCache.EXT_DEFAULT
+ .getShorts(reader, field, parser) : ExtendedFieldCache.EXT_DEFAULT
+ .getShorts(reader, field);
+ }
+
+ public int sortType() {
+ return SortField.BYTE;
+ }
+
+ public Comparable value(int slot) {
+ return new Short(values[slot]);
+ }
+ };
+
+ public static final class StringComparatorLocale extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+ private final String[] values;
+ private String[] currentReaderValues;
+ private final String field;
+ final Collator collator;
+
+ StringComparatorLocale(int numHits, String field, Locale locale) {
+ values = new String[numHits];
+ this.field = field;
+ collator = Collator.getInstance(locale);
+ }
+
+ public int compare(int slot1, int slot2) {
+ final String val1 = values[slot1];
+ final String val2 = values[slot2];
+ if (val1 == null) {
+ if (val2 == null) {
+ return 0;
+ }
+ return -1;
+ } else if (val2 == null) {
+ return 1;
+ }
+ return collator.compare(val1, val2);
+ }
+
+ public int compare(int slot, int doc, float score) {
+ return values[slot].compareTo(currentReaderValues[doc]);
+ }
+
+ public void copy(int slot, int doc, float score) {
+ values[slot] = currentReaderValues[doc];
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ currentReaderValues = ExtendedFieldCache.EXT_DEFAULT.getStrings(reader,
+ field);
+ }
+
+ public int sortType() {
+ return SortField.STRING;
+ }
+
+ public Comparable value(int slot) {
+ return values[slot];
+ }
+ };
+
+ /**
+ * This Comparator can only be used a single IndexReader or the first IndexReader in a series
+ * of IndexReaders.
+ */
+ public static final class StringOrdComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+ private int[] subords;
+ final int[] ords;
+ String[] values;
+ String[] lookup;
+ private int[] order;
+ final String field;
+
+ StringOrdComparator(String field, String[] values, int[] ords, int[] subords) {
+ this.field = field;
+ this.values = values;
+ this.ords = ords;
+ this.subords = subords;
+ }
+
+ StringOrdComparator(int numHits, String field) {
+ ords = new int[numHits];
+ values = new String[numHits];
+ subords = new int[numHits];
+ this.field = field;
+ }
+
+ public int compare(int slot1, int slot2) {
+ return ords[slot1] - ords[slot2];
+ }
+
+ public int compare(int slot, int doc, float score) {
+ int ord = order[doc];
+ return ords[slot] - ord;
+ }
+
+ public void copy(int slot, int doc, float score) {
+ int ord = order[doc];
+ ords[slot] = ord;
+ subords[slot] = 0;
+ values[slot] = lookup[ord];
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ StringIndex currentReaderValues = ExtendedFieldCache.EXT_DEFAULT
+ .getStringIndex(reader, field);
+
+ lookup = currentReaderValues.lookup;
+ order = currentReaderValues.order;
+ }
+
+ public int sortType() {
+ return SortField.STRING_ORD;
+ }
+
+ public Comparable value(int slot) {
+ return values[slot];
+ }
+ }
+
+ /**
+ * This Comparator can only be used a single IndexReader or the first IndexReader in a series
+ * of IndexReaders.
+ */
+ public static final class StringOrd2Comparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+ private int[] subords;
+ final int[] ords;
+ String[] values;
+ String[] lookup;
+ private int[] order;
+ final String field;
+
+ StringOrd2Comparator(String field, String[] values, int[] ords, int[] subords) {
+ this.field = field;
+ this.values = values;
+ this.ords = ords;
+ this.subords = subords;
+ }
+
+ StringOrd2Comparator(int numHits, String field) {
+ ords = new int[numHits];
+ values = new String[numHits];
+ subords = new int[numHits];
+ this.field = field;
+ }
+
+ private int bottomOrd;
+
+ public void setBottom(int slot) {
+ bottomOrd = ords[slot];
+ }
+
+ public int compareBottom(int doc, float score) {
+ return bottomOrd - order[doc];
+ }
+
+ public int compare(int slot1, int slot2) {
+ return ords[slot1] - ords[slot2];
+ }
+
+ public int compare(int slot, int doc, float score) {
+ int ord = order[doc];
+ return ords[slot] - ord;
+ }
+
+ public void copy(int slot, int doc, float score) {
+ int ord = order[doc];
+ ords[slot] = ord;
+ subords[slot] = 0;
+ values[slot] = lookup[ord];
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ StringIndex currentReaderValues = ExtendedFieldCache.EXT_DEFAULT
+ .getStringIndex(reader, field);
+
+ lookup = currentReaderValues.lookup;
+ order = currentReaderValues.order;
+ }
+
+ public int sortType() {
+ return SortField.STRING_ORD;
+ }
+
+ public Comparable value(int slot) {
+ return values[slot];
+ }
+ }
+
+ public static final class StringOrdSubOrdComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+ private int[] subords;
+ final int[] ords;
+ String[] values;
+ String[] lookup;
+ private int[] order;
+ final String field;
+
+ StringOrdSubOrdComparator(String field, String[] values, int[] ords, int[] subords) {
+ this.field = field;
+ this.values = values;
+ this.ords = ords;
+ this.subords = subords;
+ }
+
+ StringOrdSubOrdComparator(int numHits, String field) {
+ ords = new int[numHits];
+ values = new String[numHits];
+ subords = new int[numHits];
+ this.field = field;
+ }
+
+ public int compare(int slot1, int slot2) {
+ int cmp = ords[slot1] - ords[slot2];
+ if (cmp != 0) {
+ return cmp;
+ }
+ return subords[slot1] - subords[slot2];
+ }
+
+ public int compare(int slot, int doc, float score) {
+ int ord = order[doc];
+ final int cmp = ords[slot] - ord;
+ if (cmp != 0) { return cmp;}
+ return 1;
+ }
+
+ public void copy(int slot, int doc, float score) {
+ int ord = order[doc];
+ ords[slot] = ord;
+ subords[slot] = 0;
+ values[slot] = lookup[ord];
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ // Map ords in queue to ords in reader
+
+ StringIndex currentReaderValues = ExtendedFieldCache.EXT_DEFAULT
+ .getStringIndex(reader, field);
+
+ lookup = currentReaderValues.lookup;
+ order = currentReaderValues.order;
+
+ if (lookup.length == 0) {
+ return;
+ }
+ Map map = new HashMap();
+ for (int i = 0; i < numSlotsFull; i++) {
+ String val = values[i];
+ if (val == null) {
+ subords[i] = 0;
+ ords[i] = 0;
+ continue;
+ }
+
+ int index = binarySearch(lookup, val);
+
+ if (index < 0) {
+ index = -index - 2;
+
+ Integer intOrd = Integer.valueOf(index);
+ List slotVals = (List) map.get(intOrd);
+ if (slotVals == null) {
+ slotVals = new ArrayList();
+ slotVals.add(new SlotValPair(i, val));
+ map.put(intOrd, slotVals);
+ } else {
+ slotVals.add(new SlotValPair(i, val));
+ }
+
+ } else {
+ subords[i] = 0;
+ }
+ ords[i] = index;
+ }
+
+ Iterator dit = map.values().iterator();
+ while (dit.hasNext()) {
+ List list = (List) dit.next();
+ if (list.size() > 1) {
+ Collections.sort(list);
+ int sz = list.size();
+ int cnt = 1;
+ SlotValPair svp = (SlotValPair) list.get(0);
+ String last = svp.val;
+ for (int i = 1; i < sz; i++) {
+ if(last.equals(svp.val) ) {
+ subords[svp.i] = cnt;
+ } else {
+ subords[svp.i] = ++cnt;
+ }
+ last = svp.val;
+ svp = (SlotValPair) list.get(i);
+ }
+ if(last.equals(svp.val) ) {
+ subords[svp.i] = cnt;
+ } else {
+ subords[svp.i] = ++cnt;
+ }
+ } else {
+ SlotValPair svp = (SlotValPair) list.get(0);
+ subords[svp.i] = 1;
+ }
+ }
+
+ }
+
+ public int sortType() {
+ return SortField.STRING_ORD;
+ }
+
+ public Comparable value(int slot) {
+ return values[slot];
+ }
+
+ class SlotValPair implements Comparable {
+ public SlotValPair(int i, String val) {
+ this.val = val;
+ this.i = i;
+ }
+
+ String val;
+ int i;
+
+ public int compareTo(Object o) {
+ SlotValPair odoub = (SlotValPair) o;
+ return val.compareTo(odoub.val);
+ }
+
+ public String toString() {
+ return "i:" + i + " val:" + val;
+ }
+ }
+ }
+
+ public static final class StringOrdValOnDemComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+ private final int[] ords;
+ String[] values;
+ private final int[] readerIndex;
+ private int currentReaderIndex = -1;
+ private String[] lookup;
+ private int length;
+ private int[] order;
+ private final String field;
+
+ public StringOrdValOnDemComparator(String field, String[] values, int[] ords, int currentReaderIndex) {
+ this.field = field;
+ this.values = values;
+ this.ords = ords;
+ readerIndex = new int[values.length];
+ }
+
+ StringOrdValOnDemComparator(int numHits, String field) {
+ ords = new int[numHits];
+ values = new String[numHits];
+ readerIndex = new int[numHits];
+ this.field = field;
+ }
+
+ public int compare(int slot1, int slot2) {
+ if (readerIndex[slot1] != currentReaderIndex) {
+ convert(slot1);
+ }
+ if (readerIndex[slot2] != currentReaderIndex) {
+ convert(slot2);
+ }
+ int cmp = ords[slot1] - ords[slot2];
+ if (cmp != 0) {
+ return cmp;
+ }
+ final String val1 = values[slot1];
+ final String val2 = values[slot2];
+ if (val1 == null) {
+ if (val2 == null) {
+ return 0;
+ }
+ return -1;
+ } else if (val2 == null) {
+ return 1;
+ }
+
+ return val1.compareTo(val2);
+ }
+
+ public int compare(int slot, int doc, float score) {
+ if (readerIndex[slot] != currentReaderIndex) {
+ convert(slot);
+ }
+ int ord = ords[slot];
+ int order = this.order[doc];
+ final int cmp = ord - order;
+ if (cmp != 0) {
+ return cmp;
+ }
+
+ final String val1 = values[slot];
+ final String val2 = lookup[order];
+ if (val1 == null) {
+ if (val2 == null) {
+ return 0;
+ }
+ return -1;
+ } else if (val2 == null) {
+ return 1;
+ }
+ return val1.compareTo(val2);
+ }
+
+ private void convert(int slot) {
+ readerIndex[slot] = currentReaderIndex;
+ if (length == 0) {
+ return;
+ }
+
+ int index = 0;
+ String value = values[slot];
+ if (value == null) {
+ ords[slot] = 0;
+ return;
+ }
+ index = binarySearch(lookup, value);
+ if (index < 0) {
+ index = -index - 2;
+ }
+ ords[slot] = index;
+ }
+
+ public void copy(int slot, int doc, float score) {
+ int ord = order[doc];
+ ords[slot] = ord;
+ values[slot] = lookup[ord];
+ readerIndex[slot] = currentReaderIndex;
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ StringIndex currentReaderValues = ExtendedFieldCache.EXT_DEFAULT
+ .getStringIndex(reader, field);
+ order = currentReaderValues.order;
+ lookup = currentReaderValues.lookup;
+ currentReaderIndex++;
+ length = lookup.length;
+ }
+
+ public int sortType() {
+ return SortField.STRING_ORD_VAL;
+ }
+
+ public Comparable value(int slot) {
+ return values[slot];
+ }
+
+ };
+
+ public static final class StringOrdValOnDem2Comparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+ private final int[] ords;
+ String[] values;
+ private final int[] readerIndex;
+ private int currentReaderIndex = -1;
+ private String[] lookup;
+ private int length;
+ private int[] order;
+ private final String field;
+
+ private int bottomOrd;
+ private String bottomVal;
+ private int bottomSlot;
+
+ public StringOrdValOnDem2Comparator(String field, String[] values, int[] ords, int currentReaderIndex) {
+ this.field = field;
+ this.values = values;
+ this.ords = ords;
+ readerIndex = new int[values.length];
+ }
+
+ StringOrdValOnDem2Comparator(int numHits, String field) {
+ ords = new int[numHits];
+ values = new String[numHits];
+ readerIndex = new int[numHits];
+ this.field = field;
+ }
+
+ public void setBottom(int slot) {
+ assert readerIndex[slot] == currentReaderIndex;
+ bottomOrd = ords[slot];
+ bottomVal = values[slot];
+ bottomSlot = slot;
+ }
+
+ public int compareBottom(int doc, float score) {
+ final int order = this.order[doc];
+ int cmp = bottomOrd - order;
+ if (cmp != 0) {
+ return cmp;
+ }
+
+ final String val1 = bottomVal;
+ final String val2 = lookup[order];
+ if (val1 == null) {
+ if (val2 == null) {
+ return 0;
+ }
+ return -1;
+ } else if (val2 == null) {
+ return 1;
+ }
+ return val1.compareTo(val2);
+ }
+
+ public int compare(int slot1, int slot2) {
+ if (readerIndex[slot1] != currentReaderIndex) {
+ convert(slot1);
+ }
+ if (readerIndex[slot2] != currentReaderIndex) {
+ convert(slot2);
+ }
+ int cmp = ords[slot1] - ords[slot2];
+ if (cmp != 0) {
+ return cmp;
+ }
+ final String val1 = values[slot1];
+ final String val2 = values[slot2];
+ if (val1 == null) {
+ if (val2 == null) {
+ return 0;
+ }
+ return -1;
+ } else if (val2 == null) {
+ return 1;
+ }
+
+ return val1.compareTo(val2);
+ }
+
+ public int compare(int slot, int doc, float score) {
+ if (readerIndex[slot] != currentReaderIndex) {
+ convert(slot);
+ }
+ int ord = ords[slot];
+ int order = this.order[doc];
+ final int cmp = ord - order;
+ if (cmp != 0) {
+ return cmp;
+ }
+
+ final String val1 = values[slot];
+ final String val2 = lookup[order];
+ if (val1 == null) {
+ if (val2 == null) {
+ return 0;
+ }
+ return -1;
+ } else if (val2 == null) {
+ return 1;
+ }
+ return val1.compareTo(val2);
+ }
+
+ private void convert(int slot) {
+ readerIndex[slot] = currentReaderIndex;
+ if (length == 0) {
+ return;
+ }
+
+ int index = 0;
+ String value = values[slot];
+ if (value == null) {
+ ords[slot] = 0;
+ return;
+ }
+ index = binarySearch(lookup, value);
+ if (index < 0) {
+ index = -index - 2;
+ }
+ ords[slot] = index;
+ }
+
+ public void copy(int slot, int doc, float score) {
+ int ord = order[doc];
+ ords[slot] = ord;
+ values[slot] = lookup[ord];
+ readerIndex[slot] = currentReaderIndex;
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ StringIndex currentReaderValues = ExtendedFieldCache.EXT_DEFAULT
+ .getStringIndex(reader, field);
+ order = currentReaderValues.order;
+ lookup = currentReaderValues.lookup;
+ currentReaderIndex++;
+ length = lookup.length;
+ bottomOrd = ords[bottomSlot];
+ }
+
+ public int sortType() {
+ return SortField.STRING_ORD_VAL;
+ }
+
+ public Comparable value(int slot) {
+ return values[slot];
+ }
+
+ };
+
+ public static final class StringOrdValComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+ private final int[] ords;
+ private final String[] values;
+ private String[] lookup;
+ private int[] order;
+ private final String field;
+
+ StringOrdValComparator(int numHits, String field) {
+ ords = new int[numHits];
+ values = new String[numHits];
+ this.field = field;
+ }
+
+ public int compare(int slot1, int slot2) {
+ int cmp = ords[slot1] - ords[slot2];
+ if (cmp != 0) { return cmp;}
+ final String val1 = values[slot1];
+ final String val2 = values[slot2];
+ if (val1 == null) {
+ if (val2 == null) {
+ return 0;
+ }
+ return -1;
+ } else if (val2 == null) {
+ return 1;
+ }
+ return val1.compareTo(val2);
+ }
+
+ public int compare(int slot, int doc, float score) {
+ final int ord = order[doc];
+ int cmp = ords[slot] - ord;
+ if (cmp != 0) { return cmp;}
+ final String val1 = values[slot];
+ final String val2 = lookup[ord];
+ if (val1 == null) {
+ if (val2 == null) {
+ return 0;
+ }
+ return -1;
+ } else if (val2 == null) {
+ return 1;
+ }
+
+ return val1.compareTo(val2);
+ }
+
+ public void copy(int slot, int doc, float score) {
+ int ord = order[doc];
+ ords[slot] = ord;
+ values[slot] = lookup[ord];
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ StringIndex currentReaderValues = ExtendedFieldCache.EXT_DEFAULT
+ .getStringIndex(reader, field);
+
+ order = currentReaderValues.order;
+ lookup = currentReaderValues.lookup;
+
+ int index = 0;
+ for (int i = 0; i < numSlotsFull; i++) {
+ String value = values[i];
+ if (value == null) {
+ continue;
+ }
+
+ index = binarySearch(lookup, value);
+
+ if (index < 0) {
+ index = -index - 2;
+ }
+ ords[i] = index;
+ }
+ }
+
+ public int sortType() {
+ return SortField.STRING_ORD_VAL;
+ }
+
+ public Comparable value(int slot) {
+ return values[slot];
+ }
+
+ };
+
+ public static final class StringValComparator extends FieldComparator {
+
+ // nocommit -- maybe "setcurrentscoredoc"?
+ private String[] values;
+ private String[] currentReaderValues;
+ private final String field;
+
+ StringValComparator(int numHits, String field) {
+ values = new String[numHits];
+ this.field = field;
+ }
+
+ public int compare(int slot1, int slot2) {
+ final String val1 = values[slot1];
+ final String val2 = values[slot2];
+ if (val1 == null) {
+ if (val2 == null) {
+ return 0;
+ }
+ return -1;
+ } else if (val2 == null) {
+ return 1;
+ }
+
+ return val1.compareTo(val2);
+ }
+
+ public int compare(int slot, int doc, float score) {
+ final String val1 = values[slot];
+ final String val2 = currentReaderValues[doc];
+ if (val1 == null) {
+ if (val2 == null) {
+ return 0;
+ }
+ return -1;
+ } else if (val2 == null) {
+ return 1;
+ }
+ return val1.compareTo(val2);
+ }
+
+ public void copy(int slot, int doc, float score) {
+ values[slot] = currentReaderValues[doc];
+ }
+
+ public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
+ currentReaderValues = ExtendedFieldCache.EXT_DEFAULT.getStrings(reader,
+ field);
+ }
+
+ public int sortType() {
+ return SortField.STRING_VAL;
+ }
+
+ public Comparable value(int slot) {
+ return values[slot];
+ }
+ };
+
+ private static int binarySearch(String[] a, String key) {
+ int low = 0;
+ int high = a.length - 1;
+
+ while (low <= high) {
+ int mid = (low + high) >>> 1;
+ String midVal = a[mid];
+ int cmp;
+ if (midVal != null) {
+ cmp = midVal.compareTo(key);
+ } else {
+ cmp = -1;
+ }
+
+ if (cmp < 0)
+ low = mid + 1;
+ else if (cmp > 0)
+ high = mid - 1;
+ else
+ return mid;
+ }
+ return -(low + 1);
+ };
+
+ /**
+ * Compare hit at slot1 with hit at slot2.
+ *
+ * @param slot1
+ * @param slot2
+ * @return
+ */
+ public abstract int compare(int slot1, int slot2);
+
+ // nocommit -- allowed to return -X or only -1 (and X, 1)???
+ /**
+ * Compare hit at slot with hit (doc,score).
+ *
+ * @param slot hit slot
+ * @param doc doc in currentIndexReader
+ * @param score hit score
+ * @return
+ */
+ public abstract int compare(int slot, int doc, float score);
+
+ /**
+ * Copy hit (doc,score) to hit slot.
+ *
+ * @param slot
+ * @param doc
+ * @param score
+ */
+ public abstract void copy(int slot, int doc, float score);
+
+ /**
+ * Set a new Reader. All doc correspond to the current Reader.
+ *
+ * @param reader
+ * @param objects
+ * @throws IOException
+ * @throws IOException
+ */
+ public abstract void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException;
+
+ /**
+ * @return SortField.TYPE
+ */
+ public abstract int sortType();
+
+ /**
+ * Return the actual value at slot.
+ *
+ * @param slot the value
+ * @return
+ */
+ public abstract Comparable value(int slot);
+
+ private int bottomSlot;
+
+ public void setBottom(int slot) {
+ bottomSlot = slot;
+ }
+
+ public int compareBottom(int doc, float score) {
+ return compare(bottomSlot, doc, score);
+ }
+}
Property changes on: src/java/org/apache/lucene/search/FieldComparator.java
___________________________________________________________________
Name: svn:eol-style
+ native
Index: src/java/org/apache/lucene/search/SortField.java
===================================================================
--- src/java/org/apache/lucene/search/SortField.java (revision 732086)
+++ src/java/org/apache/lucene/search/SortField.java (working copy)
@@ -17,9 +17,14 @@
* limitations under the License.
*/
+import java.io.IOException;
import java.io.Serializable;
import java.util.Locale;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.FieldComparator.StringOrdValOnDemComparator;
+import org.apache.lucene.search.FieldComparator.StringOrdValOnDem2Comparator;
+
/**
* Stores information about how to sort documents by terms in an individual
* field. Fields must be indexed in order to sort by them.
@@ -80,8 +85,23 @@
* Sort using term values as encoded bytes. Sort values are bytes and lower values are at the front
*/
public static final int BYTE = 10;
+
+ public static final int STRING_ORD = 11;
+
+ public static final int STRING_VAL = 12;
+
+ public static final int STRING_ORD_VAL = 13;
+
+ public static final int STRING_ORD_VAL_DEM = 14;
+
+ public static final int STRING_ORD_VAL_DEM_WIN = 15;
+ public static final int STRING_ORD_SUBORD = 16;
+ public static final int STRING_ORD_VAL_DEM2 = 17;
+
+ public static final int STRING_ORD2 = 18;
+
// IMPLEMENTATION NOTE: the FieldCache.STRING_INDEX is in the same "namespace"
// as the above static int values. Any new values must not have the same value
// as FieldCache.STRING_INDEX.
@@ -101,6 +121,10 @@
private SortComparatorSource factory;
private FieldCache.Parser parser;
+ private FieldComparatorSource comparatorSource;
+
+ private boolean useLegacy = false; // remove in Lucene 3.0
+
/** Creates a sort by terms in the given field where the type of term value
* is determined dynamically ({@link #AUTO AUTO}).
* @param field Name of field to sort by, cannot be null.
@@ -206,22 +230,44 @@
/** Creates a sort with a custom comparison function.
* @param field Name of field to sort by; cannot be null.
* @param comparator Returns a comparator for sorting hits.
+ * @deprecated use SortField (String field, FieldComparatorSource comparator)
*/
public SortField (String field, SortComparatorSource comparator) {
initFieldType(field, CUSTOM);
this.factory = comparator;
}
+
+ /** Creates a sort with a custom comparison function.
+ * @param field Name of field to sort by; cannot be null.
+ * @param comparator Returns a comparator for sorting hits.
+ */
+ public SortField (String field, FieldComparatorSource comparator) {
+ initFieldType(field, CUSTOM);
+ this.comparatorSource = comparator;
+ }
/** Creates a sort, possibly in reverse, with a custom comparison function.
* @param field Name of field to sort by; cannot be null.
* @param comparator Returns a comparator for sorting hits.
* @param reverse True if natural order should be reversed.
+ * @deprecated use SortField (String field, FieldComparatorSource comparator, boolean reverse)
*/
public SortField (String field, SortComparatorSource comparator, boolean reverse) {
initFieldType(field, CUSTOM);
this.reverse = reverse;
this.factory = comparator;
}
+
+ /** Creates a sort, possibly in reverse, with a custom comparison function.
+ * @param field Name of field to sort by; cannot be null.
+ * @param comparator Returns a comparator for sorting hits.
+ * @param reverse True if natural order should be reversed.
+ */
+ public SortField (String field, FieldComparatorSource comparator, boolean reverse) {
+ initFieldType(field, CUSTOM);
+ this.reverse = reverse;
+ this.comparatorSource = comparator;
+ }
// Sets field & type, and ensures field is not NULL unless
// type is SCORE or DOC
@@ -273,9 +319,36 @@
return reverse;
}
+ /**
+ * @deprecated use {@link #getComparatorSource()}
+ */
public SortComparatorSource getFactory() {
return factory;
}
+
+ public FieldComparatorSource getComparatorSource() {
+ return comparatorSource;
+ }
+
+ /**
+ * Use legacy IndexSearch semantics: search with a MultiSegmentReader rather
+ * than passing a single hit collector to multiple SegmentReaders.
+ *
+ * @param legacy true for legacy behavior
+ * @deprecated will be removed in Lucene 3.0.
+ */
+ public void setUseLegacySearch(boolean legacy) {
+ this.useLegacy = legacy;
+ }
+
+ /**
+ * @return if true, IndexSearch will use legacy sorting search semantics.
+ * eg. multiple Priority Queues.
+ * @deprecated will be removed in Lucene 3.0.
+ */
+ public boolean getUseLegacySearch() {
+ return this.useLegacy;
+ }
public String toString() {
StringBuffer buffer = new StringBuffer();
@@ -333,4 +406,200 @@
if (parser != null) hash += parser.hashCode()^0x3aaf56ff;
return hash;
}
+
+ ComparatorPolicy getComparatorPolicy(IndexReader[] subReaders, final int numHits) throws IOException {
+ switch (type) {
+ case SortField.SCORE:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.RelevanceComparator(numHits);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+ case SortField.DOC:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.DocComparator(numHits);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+ case SortField.INT:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.IntComparator(numHits, field, parser);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+ case SortField.FLOAT:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.FloatComparator(numHits, field, parser);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+ case SortField.LONG:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.LongComparator(numHits, field, parser);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+ case SortField.DOUBLE:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.DoubleComparator(numHits, field, parser);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+ case SortField.BYTE:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.ByteComparator(numHits, field, parser);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+ case SortField.SHORT:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.ShortComparator(numHits, field, parser);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+ case SortField.CUSTOM:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = comparatorSource.newComparator(field);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+
+ case SortField.STRING:
+ if (locale != null) {
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.StringComparatorLocale(numHits, field, locale);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+ }
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.StringOrdSubOrdComparator(numHits, field);;
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+
+ case SortField.STRING_VAL:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.StringValComparator(numHits, field);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+
+ case SortField.STRING_ORD:
+ if (locale != null) {
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.StringComparatorLocale(numHits, field, locale);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+ }
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.StringOrdComparator(numHits, field);
+ private boolean first = true;
+ private boolean second = true;
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ if(first) {
+ first = false;
+ return comparator;
+ } else if(second){
+ StringOrdValOnDemComparator comp = new FieldComparator.StringOrdValOnDemComparator(numHits, field);
+ comp.values = ((FieldComparator.StringOrdComparator)comparator).values;
+ comparator = comp;
+ second = false;
+ return comp;
+ }
+ return comparator;
+ }};
+
+ case SortField.STRING_ORD2:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.StringOrd2Comparator(numHits, field);
+ private boolean first = true;
+ private boolean second = true;
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ if(first) {
+ first = false;
+ return comparator;
+ } else if(second){
+ StringOrdValOnDem2Comparator comp = new FieldComparator.StringOrdValOnDem2Comparator(numHits, field);
+ comp.values = ((FieldComparator.StringOrd2Comparator)comparator).values;
+ comparator = comp;
+ second = false;
+ return comp;
+ }
+ return comparator;
+ }};
+
+ case SortField.STRING_ORD_SUBORD:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.StringOrdSubOrdComparator(numHits, field);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+
+ case SortField.STRING_ORD_VAL:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.StringOrdValComparator(numHits, field);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+
+ case SortField.STRING_ORD_VAL_DEM:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.StringOrdValOnDemComparator(numHits, field);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+
+ case SortField.STRING_ORD_VAL_DEM2:
+ return new ComparatorPolicy(){
+ private FieldComparator comparator = new FieldComparator.StringOrdValOnDem2Comparator(numHits, field);
+ public FieldComparator nextComparator(FieldComparator oldComparator,
+ IndexReader reader, int numHits, int numSlotsFull)
+ throws IOException {
+ return comparator;
+ }};
+
+ default:
+ throw new IllegalStateException("Illegal sort type: " + type);
+ }
+
+ }
+
}
Index: src/java/org/apache/lucene/search/FieldValueHitQueue.java
===================================================================
--- src/java/org/apache/lucene/search/FieldValueHitQueue.java (revision 0)
+++ src/java/org/apache/lucene/search/FieldValueHitQueue.java (revision 0)
@@ -0,0 +1,228 @@
+package org.apache.lucene.search;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermEnum;
+import org.apache.lucene.util.PriorityQueue;
+
+import java.io.IOException;;
+
+/**
+ * Expert: A hit queue for sorting by hits by terms in more than one field.
+ * Uses FieldCache.DEFAULT for maintaining
+ * internal term lookup tables.
+ *
+ * NOTE: This API is experimental and might change in
+ * incompatible ways in the next release.
+ *
+ * @since lucene 2.9
+ * @version $Id:
+ * @see Searcher#search(Query,Filter,int,Sort)
+ * @see FieldCache
+ */
+public class FieldValueHitQueue extends PriorityQueue {
+
+ final static class Entry {
+ int slot;
+ int subReaderIndex;
+ int subDocID;
+ float score;
+ Entry(int slot, int subReaderIndex, int subDocID, float score) {
+ this.slot = slot;
+ this.subReaderIndex = subReaderIndex;
+ this.subDocID = subDocID;
+ this.score = score;
+ }
+
+ public String toString() {
+ return "slot:" + slot + " subR:" + subReaderIndex + " subid:" + subDocID;
+ }
+ }
+
+ // nocommit
+ private static boolean first = true;
+
+ /**
+ * Creates a hit queue sorted by the given list of fields.
+ * @param reader
+ * @param fields Fieldable names, in priority order (highest priority first). Cannot be null or empty.
+ * @param size The number of hits to retain. Must be greater than zero.
+ * @throws IOException
+ */
+ public FieldValueHitQueue(SortField[] fields, int size, IndexReader[] subReaders) throws IOException {
+ numComparators = fields.length;
+ comparators = new FieldComparator[numComparators];
+ comparatorPolicies = new ComparatorPolicy[numComparators];
+ reverseMul = new int[numComparators];
+
+ this.fields = fields;
+ for (int i=0; ia is less relevant than b.
+ * @param a ScoreDoc
+ * @param b ScoreDoc
+ * @return true if document a should be sorted after document b.
+ */
+ protected boolean lessThan (final Object a, final Object b) {
+ final Entry hitA = (Entry) a;
+ final Entry hitB = (Entry) b;
+
+ if (numComparators == 1) {
+ // Common case
+ final int c = reverseMul1 * comparator1.compare (hitA.slot, hitB.slot);
+ if (c != 0) {
+ return c > 0;
+ }
+ } else {
+ // run comparators
+ for (int i=0; i 0;
+ }
+ }
+ }
+
+ // avoid random sort order that could lead to duplicates (bug #31241):
+ return hitA.subReaderIndex > hitB.subReaderIndex ||
+ (hitA.subReaderIndex == hitB.subReaderIndex &&
+ hitA.subDocID > hitB.subDocID);
+ }
+
+
+ /**
+ * Given a FieldDoc object, stores the values used
+ * to sort the given document. These values are not the raw
+ * values out of the index, but the internal representation
+ * of them. This is so the given search hit can be collated
+ * by a MultiSearcher with other search hits.
+ * @param doc The FieldDoc to store sort values into.
+ * @return The same FieldDoc passed in.
+ * @see Searchable#search(Weight,Filter,int,Sort)
+ */
+ FieldDoc fillFields (final Entry entry, int[] starts) {
+ final int n = comparators.length;
+ final Comparable[] fields = new Comparable[n];
+ for (int i=0; i 1.0f) doc.score /= maxscore; // normalize scores
+ return new FieldDoc(entry.subDocID + starts[entry.subReaderIndex],
+ entry.score,
+ fields);
+ }
+
+
+ /** Returns the SortFields being used by this hit queue. */
+ SortField[] getFields() {
+ return fields;
+ }
+
+ /**
+ * Attempts to detect the given field type for an IndexReader.
+ */
+ static int detectFieldType(IndexReader reader, String fieldKey) throws IOException {
+ String field = ((String)fieldKey).intern();
+ TermEnum enumerator = reader.terms (new Term (field));
+ try {
+ Term term = enumerator.term();
+ if (term == null) {
+ throw new RuntimeException ("no terms in field " + field + " - cannot determine sort type");
+ }
+ int ret = 0;
+ if (term.field() == field) {
+ String termtext = term.text().trim();
+
+ /**
+ * Java 1.4 level code:
+
+ if (pIntegers.matcher(termtext).matches())
+ return IntegerSortedHitQueue.comparator (reader, enumerator, field);
+
+ else if (pFloats.matcher(termtext).matches())
+ return FloatSortedHitQueue.comparator (reader, enumerator, field);
+ */
+
+ // Java 1.3 level code:
+ try {
+ Integer.parseInt (termtext);
+ ret = SortField.INT;
+ } catch (NumberFormatException nfe1) {
+ try {
+ Long.parseLong(termtext);
+ ret = SortField.LONG;
+ } catch (NumberFormatException nfe2) {
+ try {
+ Float.parseFloat (termtext);
+ ret = SortField.FLOAT;
+ } catch (NumberFormatException nfe3) {
+ ret = SortField.STRING;
+ }
+ }
+ }
+ } else {
+ throw new RuntimeException ("field \"" + field + "\" does not appear to be indexed");
+ }
+ return ret;
+ } finally {
+ enumerator.close();
+ }
+ }
+
+ ComparatorPolicy[] getComparatorPolicies() {
+ return comparatorPolicies;
+ }
+
+ //void setReversMulti1(int rev) {
+ void setReverseMul1(int rev) {
+ this.reverseMul1 = rev;
+ }
+
+ void setComparator1(FieldComparator comp) {
+ this.comparator1 = comp;
+ }
+}
Property changes on: src/java/org/apache/lucene/search/FieldValueHitQueue.java
___________________________________________________________________
Name: svn:eol-style
+ native