Index: lucene/join/src/java/org/apache/lucene/search/join/TermsCollector.java =================================================================== --- lucene/join/src/java/org/apache/lucene/search/join/TermsCollector.java (revision 1470552) +++ lucene/join/src/java/org/apache/lucene/search/join/TermsCollector.java (working copy) @@ -19,14 +19,20 @@ import java.io.IOException; +import org.apache.lucene.index.AtomicReader; import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.search.Collector; import org.apache.lucene.search.FieldCache; +import org.apache.lucene.search.FieldCache.Doubles; +import org.apache.lucene.search.FieldCache.Floats; +import org.apache.lucene.search.FieldCache.Ints; +import org.apache.lucene.search.FieldCache.Longs; import org.apache.lucene.search.Scorer; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRefHash; +import org.apache.lucene.util.NumericUtils; /** * A collector that collects all terms from a specified field matching the query. @@ -95,7 +101,7 @@ static class SV extends TermsCollector { final BytesRef spare = new BytesRef(); - private BinaryDocValues fromDocTerms; + private IValueCollector valueCollector; SV(String field) { super(field); @@ -103,14 +109,189 @@ @Override public void collect(int doc) throws IOException { - fromDocTerms.get(doc, spare); + valueCollector.collectValue(doc, spare); collectorTerms.add(spare); } @Override public void setNextReader(AtomicReaderContext context) throws IOException { - fromDocTerms = FieldCache.DEFAULT.getTerms(context.reader(), field); + valueCollector = ValueCollectorProvider.INSTANCE.getValueCollector(context, field); } } + + /**Represents a collector, responsible for extracting the value of a document.*/ + static abstract interface IValueCollector { + /** + * Fetches a value from the document and writes it to the specified {@link BytesRef}. + * @param docID the document ID. + * @param spare the document value to write into. + * */ + void collectValue(final int docID, final BytesRef spare); + + } + + /**Singleton value collector provider. This class is responsible for making an attempt + * to parse the value from a field identified by its field name and returns with a {@link IValueCollector} instance. + * This class is capable to fetch a field value, even if it was indexed as a trie.*/ + static enum ValueCollectorProvider { + + /**The shared instance.*/ + INSTANCE; + + + /** + * Returns with the {@link IValueCollector value collector} instance. + * @param context the atomic reader context. + * @param field the field name. + * @return the value collector that can fetch the field value even if it was indexed as a numeric field. + * @throws IOException + */ + IValueCollector getValueCollector(final AtomicReaderContext context, final String field) throws IOException { + + if (null == context) { + throw new NullPointerException("Atomic reader context argument cannot be null."); + } + + + if (null == field) { + throw new NullPointerException("Field argument cannot be null."); + } + + + final AtomicReader reader = context.reader(); + + + try { + + //parsing fields indexed as plain string. + return new StringValueCollector(FieldCache.DEFAULT.getTerms(reader, field)); + + } catch (final NumberFormatException e) { + + try { + + //parsing numeric fields indexed as 32-bit signed integers. + return new IntValueCollector(FieldCache.DEFAULT.getInts(reader, field, false)); + + } catch (final NumberFormatException e1) { + + try { + + //attempt to parse fields indexed as 64-bit signed longs. + return new LongValueCollector(FieldCache.DEFAULT.getLongs(reader, field, false)); + + } catch (final NumberFormatException e2) { + + try { + + //attempt to parse fields indexed as 32-bit float numeric fields. + return new FloatValueCollector(FieldCache.DEFAULT.getFloats(reader, field, false)); + + } catch (final NumberFormatException e3) { + + try { + + //trying to parse numeric fields indexed as 64-bit longs. + return new DoubleValueCollector(FieldCache.DEFAULT.getDoubles(reader, field, false)); + + } catch (final NumberFormatException e4) { + + //cannot parse field. + throw new IllegalStateException("Cannot parse value for field: " + field + "."); + + } + + } + + } + + } + + } + + } + + } + /**Collector for fields indexed as 32-bit floats.*/ + private static class FloatValueCollector implements IValueCollector { + private final Floats floats; + private FloatValueCollector(final Floats floats) { + if (null == floats) { + throw new NullPointerException("Floats argument cannot be null."); + } + this.floats = floats; + } + + @Override + public void collectValue(int docID, BytesRef spare) { + spare = new BytesRef(Float.toString(floats.get(docID))); + }; + } + + /**Collector for fields indexed as 64-bit doubles.*/ + private static class DoubleValueCollector implements IValueCollector { + private final Doubles doubles; + private DoubleValueCollector(final Doubles doubles) { + if (null == doubles) { + throw new NullPointerException("Doubles argument cannot be null."); + } + this.doubles = doubles; + } + + @Override + public void collectValue(int docID, BytesRef spare) { + spare = new BytesRef(Double.toString(doubles.get(docID))); + }; + } + + /**Collector for fields indexed as 64-bit signed longs.*/ + private static class LongValueCollector implements IValueCollector { + private final Longs longs; + private LongValueCollector(final Longs longs) { + if (null == longs) { + throw new NullPointerException("Longs argument cannot be null."); + } + this.longs = longs; + } + + @Override + public void collectValue(int docID, BytesRef spare) { + NumericUtils.longToPrefixCoded(longs.get(docID), 0, spare); + }; + } + + /**Collector for fields indexed as 32-bit signed integers.*/ + private static class IntValueCollector implements IValueCollector { + private final Ints ints; + private IntValueCollector(final Ints ints) { + if (null == ints) { + throw new NullPointerException("Ints argument cannot be null."); + } + this.ints = ints; + } + + @Override + public void collectValue(int docID, BytesRef spare) { + NumericUtils.intToPrefixCoded(ints.get(docID), 0, spare); + }; + } + + + /**Collector for fields indexed as plain string.*/ + private static class StringValueCollector implements IValueCollector { + private final BinaryDocValues docValues; + private StringValueCollector(final BinaryDocValues docValues) { + if (null == docValues) { + throw new NullPointerException("Doc values argument cannot be null."); + } + this.docValues = docValues; + } + + @Override + public void collectValue(int docID, BytesRef spare) { + docValues.get(docID, spare); + }; + } + }