diff --git a/CHANGES.txt b/CHANGES.txt index c289200aad2..43529f27981 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -9,6 +9,9 @@ Bug fixes 1. LUCENE-330: Fix issue of FilteredQuery not working properly within BooleanQuery. (Paul Elschot via Erik Hatcher) + 2. LUCENE-515: Make ConstantScoreRangeQuery and ConstantScoreQuery work + with RemoteSearchable. (Philippe Laflamme via Yonik Seeley) + 1.9.1 Bug fixes diff --git a/src/java/org/apache/lucene/search/ConstantScoreQuery.java b/src/java/org/apache/lucene/search/ConstantScoreQuery.java index b0187d207ca..55455555e07 100644 --- a/src/java/org/apache/lucene/search/ConstantScoreQuery.java +++ b/src/java/org/apache/lucene/search/ConstantScoreQuery.java @@ -1,158 +1,158 @@ -package org.apache.lucene.search; - -/** - * Copyright 2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.apache.lucene.index.IndexReader; - -import java.io.IOException; -import java.util.BitSet; - -/** - * A query that wraps a filter and simply returns a constant score equal to the - * query boost for every document in the filter. - * - * @author yonik - * @version $Id$ - */ -public class ConstantScoreQuery extends Query { - protected final Filter filter; - - public ConstantScoreQuery(Filter filter) { - this.filter=filter; - } - - public Query rewrite(IndexReader reader) throws IOException { - return this; - } - - protected class ConstantWeight implements Weight { - private Searcher searcher; - private float queryNorm; - private float queryWeight; - - public ConstantWeight(Searcher searcher) { - this.searcher = searcher; - } - - public Query getQuery() { - return ConstantScoreQuery.this; - } - - public float getValue() { - return queryWeight; - } - - public float sumOfSquaredWeights() throws IOException { - queryWeight = getBoost(); - return queryWeight * queryWeight; - } - - public void normalize(float norm) { - this.queryNorm = norm; - queryWeight *= this.queryNorm; - } - - public Scorer scorer(IndexReader reader) throws IOException { - return new ConstantScorer(getSimilarity(searcher), reader, this); - } - - public Explanation explain(IndexReader reader, int doc) throws IOException { - - ConstantScorer cs = (ConstantScorer)scorer(reader); - boolean exists = cs.bits.get(doc); - - Explanation result = new Explanation(); - - if (exists) { - result.setDescription("ConstantScoreQuery(" + filter - + "), product of:"); - result.setValue(queryWeight); - result.addDetail(new Explanation(getBoost(), "boost")); - result.addDetail(new Explanation(queryNorm,"queryNorm")); - } else { - result.setDescription("ConstantScoreQuery(" + filter - + ") doesn't match id " + doc); - result.setValue(0); - } - return result; - } - } - - protected class ConstantScorer extends Scorer { - final BitSet bits; - final float theScore; - int doc=-1; - - public ConstantScorer(Similarity similarity, IndexReader reader, Weight w) throws IOException { - super(similarity); - theScore = w.getValue(); - 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 theScore; - } - - public boolean skipTo(int target) throws IOException { - doc = bits.nextSetBit(target); // requires JDK 1.4 - return doc >= 0; - } - - public Explanation explain(int doc) throws IOException { - throw new UnsupportedOperationException(); - } - } - - - protected Weight createWeight(Searcher searcher) { - return new ConstantScoreQuery.ConstantWeight(searcher); - } - - - /** Prints a user-readable version of this query. */ - public String toString(String field) - { - return "ConstantScore(" + filter.toString() - + (getBoost()==1.0 ? ")" : "^" + getBoost()); - } - - /** Returns true if o is equal to this. */ - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ConstantScoreQuery)) return false; - ConstantScoreQuery other = (ConstantScoreQuery)o; - return this.getBoost()==other.getBoost() && filter.equals(other.filter); - } - - /** Returns a hash code value for this object. */ - public int hashCode() { - // Simple add is OK since no existing filter hashcode has a float component. - return filter.hashCode() + Float.floatToIntBits(getBoost()); - } - -} - - +package org.apache.lucene.search; + +/** + * Copyright 2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.index.IndexReader; + +import java.io.IOException; +import java.util.BitSet; + +/** + * A query that wraps a filter and simply returns a constant score equal to the + * query boost for every document in the filter. + * + * @author yonik + * @version $Id$ + */ +public class ConstantScoreQuery extends Query { + protected final Filter filter; + + public ConstantScoreQuery(Filter filter) { + this.filter=filter; + } + + public Query rewrite(IndexReader reader) throws IOException { + return this; + } + + protected class ConstantWeight implements Weight { + private Similarity similarity; + private float queryNorm; + private float queryWeight; + + public ConstantWeight(Searcher searcher) { + this.similarity = getSimilarity(searcher); + } + + public Query getQuery() { + return ConstantScoreQuery.this; + } + + public float getValue() { + return queryWeight; + } + + public float sumOfSquaredWeights() throws IOException { + queryWeight = getBoost(); + return queryWeight * queryWeight; + } + + public void normalize(float norm) { + this.queryNorm = norm; + queryWeight *= this.queryNorm; + } + + public Scorer scorer(IndexReader reader) throws IOException { + return new ConstantScorer(similarity, reader, this); + } + + public Explanation explain(IndexReader reader, int doc) throws IOException { + + ConstantScorer cs = (ConstantScorer)scorer(reader); + boolean exists = cs.bits.get(doc); + + Explanation result = new Explanation(); + + if (exists) { + result.setDescription("ConstantScoreQuery(" + filter + + "), product of:"); + result.setValue(queryWeight); + result.addDetail(new Explanation(getBoost(), "boost")); + result.addDetail(new Explanation(queryNorm,"queryNorm")); + } else { + result.setDescription("ConstantScoreQuery(" + filter + + ") doesn't match id " + doc); + result.setValue(0); + } + return result; + } + } + + protected class ConstantScorer extends Scorer { + final BitSet bits; + final float theScore; + int doc=-1; + + public ConstantScorer(Similarity similarity, IndexReader reader, Weight w) throws IOException { + super(similarity); + theScore = w.getValue(); + 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 theScore; + } + + public boolean skipTo(int target) throws IOException { + doc = bits.nextSetBit(target); // requires JDK 1.4 + return doc >= 0; + } + + public Explanation explain(int doc) throws IOException { + throw new UnsupportedOperationException(); + } + } + + + protected Weight createWeight(Searcher searcher) { + return new ConstantScoreQuery.ConstantWeight(searcher); + } + + + /** Prints a user-readable version of this query. */ + public String toString(String field) + { + return "ConstantScore(" + filter.toString() + + (getBoost()==1.0 ? ")" : "^" + getBoost()); + } + + /** Returns true if o is equal to this. */ + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ConstantScoreQuery)) return false; + ConstantScoreQuery other = (ConstantScoreQuery)o; + return this.getBoost()==other.getBoost() && filter.equals(other.filter); + } + + /** Returns a hash code value for this object. */ + public int hashCode() { + // Simple add is OK since no existing filter hashcode has a float component. + return filter.hashCode() + Float.floatToIntBits(getBoost()); + } + +} + + diff --git a/src/java/org/apache/lucene/search/ConstantScoreRangeQuery.java b/src/java/org/apache/lucene/search/ConstantScoreRangeQuery.java index 9b7689b7630..4d65e61d60c 100644 --- a/src/java/org/apache/lucene/search/ConstantScoreRangeQuery.java +++ b/src/java/org/apache/lucene/search/ConstantScoreRangeQuery.java @@ -1,138 +1,138 @@ -package org.apache.lucene.search; - -/** - * Copyright 2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.apache.lucene.index.IndexReader; - -import java.io.IOException; - -/** - * A range query that returns a constant score equal to it's boost for - * all documents in the range. - *

- * It does not have an upper bound on the number of clauses covered in the range. - *

- * 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 the term to exclude.) - * - * @author yonik - * @version $Id$ - */ - -public class ConstantScoreRangeQuery extends Query -{ - private final String fieldName; - private final String lowerVal; - private final String upperVal; - private final boolean includeLower; - private final boolean includeUpper; - - - public ConstantScoreRangeQuery(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 true if the lower endpoint is inclusive */ - public boolean includesLower() { return includeLower; } - /** Returns true if the upper endpoint is inclusive */ - public boolean includesUpper() { return includeUpper; } - - public Query rewrite(IndexReader reader) throws IOException { - // Map to RangeFilter semantics which are slightly different... - RangeFilter rangeFilt = new RangeFilter(fieldName, - lowerVal!=null?lowerVal:"", - upperVal, lowerVal==""?false:includeLower, upperVal==null?false:includeUpper); - Query q = new ConstantScoreQuery(rangeFilt); - q.setBoost(getBoost()); - return q; - } - - /** 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 o is equal to this. */ - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ConstantScoreRangeQuery)) return false; - ConstantScoreRangeQuery other = (ConstantScoreRangeQuery) 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.lowerVal) : 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 : 0) - ^ (includeUpper ? 0x99aa5566 : 0); - return h; - } -} +package org.apache.lucene.search; + +/** + * Copyright 2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.index.IndexReader; + +import java.io.IOException; + +/** + * A range query that returns a constant score equal to it's boost for + * all documents in the range. + *

+ * It does not have an upper bound on the number of clauses covered in the range. + *

+ * 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 the term to exclude.) + * + * @author yonik + * @version $Id$ + */ + +public class ConstantScoreRangeQuery extends Query +{ + private final String fieldName; + private final String lowerVal; + private final String upperVal; + private final boolean includeLower; + private final boolean includeUpper; + + + public ConstantScoreRangeQuery(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 true if the lower endpoint is inclusive */ + public boolean includesLower() { return includeLower; } + /** Returns true if the upper endpoint is inclusive */ + public boolean includesUpper() { return includeUpper; } + + public Query rewrite(IndexReader reader) throws IOException { + // Map to RangeFilter semantics which are slightly different... + RangeFilter rangeFilt = new RangeFilter(fieldName, + lowerVal!=null?lowerVal:"", + upperVal, lowerVal==""?false:includeLower, upperVal==null?false:includeUpper); + Query q = new ConstantScoreQuery(rangeFilt); + q.setBoost(getBoost()); + return q; + } + + /** 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 o is equal to this. */ + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ConstantScoreRangeQuery)) return false; + ConstantScoreRangeQuery other = (ConstantScoreRangeQuery) 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.lowerVal) : 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 : 0) + ^ (includeUpper ? 0x99aa5566 : 0); + return h; + } +} diff --git a/src/test/org/apache/lucene/search/TestRemoteSearchable.java b/src/test/org/apache/lucene/search/TestRemoteSearchable.java index 018a9ad67e0..42a8545d020 100644 --- a/src/test/org/apache/lucene/search/TestRemoteSearchable.java +++ b/src/test/org/apache/lucene/search/TestRemoteSearchable.java @@ -107,4 +107,14 @@ public class TestRemoteSearchable extends TestCase { new QueryFilter(new TermQuery(new Term("test", "non-existent-term")))); assertEquals(0, nohits.length()); } + + public void testConstantScoreQuery() throws Exception { + // try to search the published index + Searchable[] searchables = { getRemote() }; + Searcher searcher = new MultiSearcher(searchables); + Hits hits = searcher.search( + new ConstantScoreQuery(new QueryFilter( + new TermQuery(new Term("test", "test"))))); + assertEquals(1, hits.length()); + } }