mirror of https://github.com/apache/lucene.git
Added ability to search for documents containing an ordered range of terms.
git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@149592 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
6c282c6a4e
commit
7a28132692
|
@ -0,0 +1,223 @@
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue