OK, so as I said, my previous version of UnscoredRangeQuery that could
work with any number of terms in the range had a problem - it could
return duplicates if a doc had more than one term in the range.
Here is how I fixed it:
I hacked together an UnscoredQuery that takes a Filter (it's like
FilteredQuery without the Query part). My UnscoredRangeQuery now
rewrites to an UnscoredQuery wrapping a RangeFilter. Since I have all
the docids to start with, the scorer can now implement skipTo.
Anyone have a better name than UnscoredQuery? It currently wrapps a
filter, but the name FilterQuery seems to close to FilteredQuery.
I'll cut-n-paste the classes below since last time at least one person
had problems seeing attachments.
-Yonik
---------------------- UnscoredRangeQuery.java
package org.apache.lucene.search;
import java.io.IOException;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermEnum;
import org.apache.lucene.index.IndexReader;
/**
* A Query that can handle any number of terms (unlike the standard RangeQuery
* which expands to a boolean query).
* A constant score is produced for all documents in the range.
* <p>
* If an endpoint is null, it is said to be "open".
* Either or both endpoints may be open. Open endpoints may not be exclusive
* (you can't select all but the first or last term without explicitly
specifying them.)
*
* @author yonik
* @version $Id: UnscoredRangeQuery.java,v 1.5 2005/04/18 01:58:14 yonik Exp $
*/
public class UnscoredRangeQuery extends Query
{
private final String fieldName;
private final String lowerVal;
private final String upperVal;
private final boolean includeLower;
private final boolean includeUpper;
public UnscoredRangeQuery(String fieldName, String lowerVal, String
upperVal, boolean includeLower, boolean includeUpper)
{
// do a little bit of normalization...
// open ended range queries should always be inclusive.
if (lowerVal==null) {
includeLower=true;
} else if (includeLower && lowerVal.equals("")) {
lowerVal=null;
}
if (upperVal==null) {
includeUpper=true;
}
this.fieldName = fieldName.intern(); // intern it, just like terms...
this.lowerVal = lowerVal;
this.upperVal = upperVal;
this.includeLower = includeLower;
this.includeUpper = includeUpper;
}
/** Returns the field name for this query */
public String getField() { return fieldName; }
/** Returns the value of the lower endpoint of this range query,
null if open ended */
public String getLowerVal() { return lowerVal; }
/** Returns the value of the upper endpoint of this range query,
null if open ended */
public String getUpperVal() { return upperVal; }
/** Returns <code>true</code> if the lower endpoint is inclusive */
public boolean includesLower() { return includeLower; }
/** Returns <code>true</code> if the upper endpoint is inclusive */
public boolean includesUpper() { return includeUpper; }
public Query rewrite(IndexReader reader) throws IOException {
// TODO: if number of terms are low enough, rewrite to a BooleanQuery
// or RangeQuery.rewrite() for potentially faster execution.
// Map to RangeFilter semantics...
RangeFilter rangeFilt = new RangeFilter(fieldName,
lowerVal!=null?lowerVal:"",
upperVal, lowerVal==""?false:includeLower,
upperVal==null?false:includeUpper);
return new UnscoredQuery(rangeFilt);
}
/** Prints a user-readable version of this query. */
public String toString(String field)
{
StringBuffer buffer = new StringBuffer();
if (!getField().equals(field))
{
buffer.append(getField());
buffer.append(":");
}
buffer.append(includeLower ? '[' : '{');
buffer.append(lowerVal != null ? lowerVal : "*");
buffer.append(" TO ");
buffer.append(upperVal != null ? upperVal : "*");
buffer.append(includeUpper ? ']' : '}');
if (getBoost() != 1.0f)
{
buffer.append("^");
buffer.append(Float.toString(getBoost()));
}
return buffer.toString();
}
/** Returns true if <code>o</code> is equal to this. */
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof UnscoredRangeQuery)) return false;
UnscoredRangeQuery other = (UnscoredRangeQuery) o;
if (this.fieldName != other.fieldName // interned comparison
|| this.includeLower != other.includeLower
|| this.includeUpper != other.includeUpper
) { return false; }
if (this.lowerVal != null ?
!this.lowerVal.equals(other.upperVal) : other.lowerVal != null) return
false;
if (this.upperVal != null ?
!this.upperVal.equals(other.upperVal) : other.upperVal != null) return
false;
return this.getBoost() == other.getBoost();
}
/** Returns a hash code value for this object.*/
public int hashCode() {
int h = Float.floatToIntBits(getBoost()) ^ fieldName.hashCode();
// hashCode of "" is 0, so don't use that for null...
h ^= lowerVal != null ? lowerVal.hashCode() : 0x965a965a;
// don't just XOR upperVal with out mixing either it or h, as it
will cancel
// out lowerVal if they are equal.
h ^= (h << 17) | (h >>> 16); // a reversible (one to one) 32
bit mapping mix
h ^= (upperVal != null ? (upperVal.hashCode()) : 0x5a695a69);
h ^= (includeLower ? 0x665599aa : 0x5566aa99)
^ (includeUpper ? 0x99aa5566 : 0xaa996655);
return h;
}
}
------------------ UnscoredQuery.java
package org.apache.lucene.search;
import org.apache.lucene.index.IndexReader;
import java.io.IOException;
import java.util.BitSet;
/**
* @author yonik
* @version $Id: UnscoredQuery.java,v 1.1 2005/04/18 01:53:13 yonik Exp $
*/
public class UnscoredQuery extends Query {
protected final Filter filter;
public UnscoredQuery(Filter filter) {
this.filter=filter;
}
public Query rewrite(IndexReader reader) throws IOException {
return this;
}
protected class UnscoredWeight implements Weight {
private Searcher searcher;
private float queryNorm;
public UnscoredWeight(Searcher searcher) {
this.searcher = searcher;
}
public Query getQuery() {
return UnscoredQuery.this;
}
public float getValue() {
return 1e-4f;
}
public float sumOfSquaredWeights() throws IOException {
return 1e-4f;
}
public void normalize(float norm) {
this.queryNorm = norm;
}
public Scorer scorer(IndexReader reader) throws IOException {
return new UnscoredScorer(getSimilarity(searcher), reader, this);
}
public Explanation explain(IndexReader reader, int doc) throws IOException {
return new Explanation(); // TODO
}
}
protected class UnscoredScorer extends Scorer {
protected final BitSet bits;
int doc=-1;
public UnscoredScorer(Similarity similarity, IndexReader reader,
Weight w) throws IOException {
super(similarity);
bits = filter.bits(reader);
}
public boolean next() throws IOException {
doc = bits.nextSetBit(doc+1);
return doc >= 0;
}
public int doc() {
return doc;
}
public float score() throws IOException {
return 1e-4f;
}
public boolean skipTo(int target) throws IOException {
doc = bits.nextSetBit(target);
return doc >= 0;
}
public Explanation explain(int doc) throws IOException {
return new Explanation(); //TODO
}
}
protected Weight createWeight(Searcher searcher) {
return new UnscoredQuery.UnscoredWeight(searcher);
}
/** Prints a user-readable version of this query. */
public String toString(String field)
{
return filter.toString();
}
/** Returns true if <code>o</code> is equal to this. */
public boolean equals(Object o) {
if (true) throw new UnsupportedOperationException("Filters don't
support equals yet!");
if (this == o) return true;
if (!(o instanceof UnscoredQuery)) return false;
UnscoredQuery other = (UnscoredQuery)o;
return this.getBoost()==other.getBoost() && filter.equals(other.filter);
}
/** Returns a hash code value for this object.*/
public int hashCode() {
if (true) throw new UnsupportedOperationException("Filters don't
support hashCode yet!");
int h = Float.floatToIntBits(getBoost());
int h2 = filter.hashCode();
h ^= ((h2 << 8) | (h2 >>> 25));
return h;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]