001: package org.apache.lucene.search;
002:
003: /**
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import org.apache.lucene.index.IndexReader;
021:
022: import java.io.IOException;
023:
024: /**
025: * A range query that returns a constant score equal to its boost for
026: * all documents in the range.
027: * <p>
028: * It does not have an upper bound on the number of clauses covered in the range.
029: * <p>
030: * If an endpoint is null, it is said to be "open".
031: * Either or both endpoints may be open. Open endpoints may not be exclusive
032: * (you can't select all but the first or last term without explicitly specifying the term to exclude.)
033: *
034: *
035: * @version $Id: ConstantScoreRangeQuery.java 564236 2007-08-09 15:21:19Z gsingers $
036: */
037:
038: public class ConstantScoreRangeQuery extends Query {
039: private final String fieldName;
040: private final String lowerVal;
041: private final String upperVal;
042: private final boolean includeLower;
043: private final boolean includeUpper;
044:
045: public ConstantScoreRangeQuery(String fieldName, String lowerVal,
046: String upperVal, boolean includeLower, boolean includeUpper) {
047: // do a little bit of normalization...
048: // open ended range queries should always be inclusive.
049: if (lowerVal == null) {
050: includeLower = true;
051: } else if (includeLower && lowerVal.equals("")) {
052: lowerVal = null;
053: }
054: if (upperVal == null) {
055: includeUpper = true;
056: }
057:
058: this .fieldName = fieldName.intern(); // intern it, just like terms...
059: this .lowerVal = lowerVal;
060: this .upperVal = upperVal;
061: this .includeLower = includeLower;
062: this .includeUpper = includeUpper;
063: }
064:
065: /** Returns the field name for this query */
066: public String getField() {
067: return fieldName;
068: }
069:
070: /** Returns the value of the lower endpoint of this range query, null if open ended */
071: public String getLowerVal() {
072: return lowerVal;
073: }
074:
075: /** Returns the value of the upper endpoint of this range query, null if open ended */
076: public String getUpperVal() {
077: return upperVal;
078: }
079:
080: /** Returns <code>true</code> if the lower endpoint is inclusive */
081: public boolean includesLower() {
082: return includeLower;
083: }
084:
085: /** Returns <code>true</code> if the upper endpoint is inclusive */
086: public boolean includesUpper() {
087: return includeUpper;
088: }
089:
090: public Query rewrite(IndexReader reader) throws IOException {
091: // Map to RangeFilter semantics which are slightly different...
092: RangeFilter rangeFilt = new RangeFilter(fieldName,
093: lowerVal != null ? lowerVal : "", upperVal,
094: lowerVal == "" ? false : includeLower,
095: upperVal == null ? false : includeUpper);
096: Query q = new ConstantScoreQuery(rangeFilt);
097: q.setBoost(getBoost());
098: return q;
099: }
100:
101: /** Prints a user-readable version of this query. */
102: public String toString(String field) {
103: StringBuffer buffer = new StringBuffer();
104: if (!getField().equals(field)) {
105: buffer.append(getField());
106: buffer.append(":");
107: }
108: buffer.append(includeLower ? '[' : '{');
109: buffer.append(lowerVal != null ? lowerVal : "*");
110: buffer.append(" TO ");
111: buffer.append(upperVal != null ? upperVal : "*");
112: buffer.append(includeUpper ? ']' : '}');
113: if (getBoost() != 1.0f) {
114: buffer.append("^");
115: buffer.append(Float.toString(getBoost()));
116: }
117: return buffer.toString();
118: }
119:
120: /** Returns true if <code>o</code> is equal to this. */
121: public boolean equals(Object o) {
122: if (this == o)
123: return true;
124: if (!(o instanceof ConstantScoreRangeQuery))
125: return false;
126: ConstantScoreRangeQuery other = (ConstantScoreRangeQuery) o;
127:
128: if (this .fieldName != other.fieldName // interned comparison
129: || this .includeLower != other.includeLower
130: || this .includeUpper != other.includeUpper) {
131: return false;
132: }
133: if (this .lowerVal != null ? !this .lowerVal
134: .equals(other.lowerVal) : other.lowerVal != null)
135: return false;
136: if (this .upperVal != null ? !this .upperVal
137: .equals(other.upperVal) : other.upperVal != null)
138: return false;
139: return this .getBoost() == other.getBoost();
140: }
141:
142: /** Returns a hash code value for this object.*/
143: public int hashCode() {
144: int h = Float.floatToIntBits(getBoost()) ^ fieldName.hashCode();
145: // hashCode of "" is 0, so don't use that for null...
146: h ^= lowerVal != null ? lowerVal.hashCode() : 0x965a965a;
147: // don't just XOR upperVal with out mixing either it or h, as it will cancel
148: // out lowerVal if they are equal.
149: h ^= (h << 17) | (h >>> 16); // a reversible (one to one) 32 bit mapping mix
150: h ^= (upperVal != null ? (upperVal.hashCode()) : 0x5a695a69);
151: h ^= (includeLower ? 0x665599aa : 0)
152: ^ (includeUpper ? 0x99aa5566 : 0);
153: return h;
154: }
155: }
|