lucene-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Yonik Seeley <ysee...@gmail.com>
Subject Re: UnscoredRangeQuery
Date Thu, 21 Apr 2005 15:41:15 GMT
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: java-dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: java-dev-help@lucene.apache.org


Mime
View raw message