Mailing List Archive

cvs commit: jakarta-lucene/src/java/org/apache/lucene/search RangeQuery.java
scottganyo 01/09/25 14:53:20

Added: src/java/org/apache/lucene/search RangeQuery.java
Log:
Added ability to search for documents containing an ordered range of terms.

Revision Changes Path
1.1 jakarta-lucene/src/java/org/apache/lucene/search/RangeQuery.java

Index: RangeQuery.java
===================================================================
package org.apache.lucene.search;

/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache Lucene" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache Lucene", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

import java.io.IOException;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermEnum;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.index.IndexReader;

/** A Query that matches documents within an exclusive range. */
public final class RangeQuery extends Query
{
private Term lowerTerm;
private Term upperTerm;
private boolean inclusive;
private IndexReader reader;
private float boost = 1.0f;
private BooleanQuery query;

/** Constructs a query selecting all terms greater than
* <code>lowerTerm</code> but less than <code>upperTerm</code>.
* There must be at least one term and either term may be null--
* in which case there is no bound on that side, but if there are
* two term, both terms <b>must</b> be for the same field.
*/
public RangeQuery(Term lowerTerm, Term upperTerm, boolean inclusive)
{
if (lowerTerm == null && upperTerm == null)
{
throw new IllegalArgumentException("At least one term must be non-null");
}
if (lowerTerm != null && upperTerm != null && lowerTerm.field() != upperTerm.field())
{
throw new IllegalArgumentException("Both terms must be for the same field");
}
this.lowerTerm = lowerTerm;
this.upperTerm = upperTerm;
this.inclusive = inclusive;
}

/** Sets the boost for this term to <code>b</code>. Documents containing
this term will (in addition to the normal weightings) have their score
multiplied by <code>boost</code>. */
public void setBoost(float boost)
{
this.boost = boost;
}

/** Returns the boost for this term. */
public float getBoost()
{
return boost;
}

final void prepare(IndexReader reader)
{
this.query = null;
this.reader = reader;
}

final float sumOfSquaredWeights(Searcher searcher) throws IOException
{
return getQuery().sumOfSquaredWeights(searcher);
}

void normalize(float norm)
{
try
{
getQuery().normalize(norm);
}
catch (IOException e)
{
throw new RuntimeException(e.toString());
}
}

Scorer scorer(IndexReader reader) throws IOException
{
return getQuery().scorer(reader);
}

private BooleanQuery getQuery() throws IOException
{
if (query == null)
{
BooleanQuery q = new BooleanQuery();
// if we have a lowerTerm, start there. otherwise, start at beginning
if (lowerTerm == null) lowerTerm = new Term(getField(), "");
TermEnum enum = reader.terms(lowerTerm);
try
{
String lowerText = null;
String field;
boolean checkLower = false;
if (!inclusive) // make adjustments to set to exclusive
{
if (lowerTerm != null)
{
lowerText = lowerTerm.text();
checkLower = true;
}
if (upperTerm != null)
{
// set upperTerm to an actual term in the index
TermEnum uppEnum = reader.terms(upperTerm);
upperTerm = uppEnum.term();
}
}
String testField = getField();
do
{
Term term = enum.term();
if (term != null && term.field() == testField)
{
if (!checkLower || term.text().compareTo(lowerText) > 0)
{
checkLower = false;
// if exclusive and this is last term, don't count it and break
if (!inclusive && (upperTerm != null) && (upperTerm.compareTo(term) <= 0)) break;
TermQuery tq = new TermQuery(term); // found a match
tq.setBoost(boost); // set the boost
q.add(tq, false, false); // add to q
// if inclusive just added last term, break out
if (inclusive && (upperTerm != null) && (upperTerm.compareTo(term) <= 0)) break;
}
}
else
{
break;
}
}
while (enum.next());
}
finally
{
enum.close();
}
query = q;
}
return query;
}

private String getField()
{
return (lowerTerm != null ? lowerTerm.field() : upperTerm.field());
}

/** 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(inclusive ? "[." : "{");
buffer.append(lowerTerm != null ? lowerTerm.text() : "null");
buffer.append("-");
buffer.append(upperTerm != null ? upperTerm.text() : "null");
buffer.append(inclusive ? "]" : "}");
if (boost != 1.0f)
{
buffer.append("^");
buffer.append(Float.toString(boost));
}
return buffer.toString();
}
}