LUCENE-10026: Fix CombinedFieldQuery equals and hashCode (#212)

The previous equals and hashCode methods only compared query terms. This meant
that queries on different fields, or with different field weights, were
considered the same

During boolean query rewrites, duplicate clauses are removed. So because equals/
hashCode was incorrect, rewrites could accidentally drop CombinedFieldQuery
clauses.
This commit is contained in:
Julie Tibshirani 2021-07-16 09:59:33 -07:00 committed by GitHub
parent e65941f9c5
commit b9a70c28b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 4 deletions

View File

@ -24,6 +24,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import org.apache.lucene.index.IndexReader;
@ -147,6 +148,19 @@ public final class CombinedFieldQuery extends Query implements Accountable {
this.field = field;
this.weight = weight;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FieldAndWeight that = (FieldAndWeight) o;
return Float.compare(that.weight, weight) == 0 && Objects.equals(field, that.field);
}
@Override
public int hashCode() {
return Objects.hash(field, weight);
}
}
// sorted map for fields.
@ -212,13 +226,20 @@ public final class CombinedFieldQuery extends Query implements Accountable {
}
@Override
public int hashCode() {
return 31 * classHash() + Arrays.hashCode(terms);
public boolean equals(Object o) {
if (this == o) return true;
if (sameClassAs(o) == false) return false;
CombinedFieldQuery that = (CombinedFieldQuery) o;
return Objects.equals(fieldAndWeights, that.fieldAndWeights)
&& Arrays.equals(terms, that.terms);
}
@Override
public boolean equals(Object other) {
return sameClassAs(other) && Arrays.equals(terms, ((CombinedFieldQuery) other).terms);
public int hashCode() {
int result = classHash();
result += Objects.hash(fieldAndWeights);
result = 31 * result + Arrays.hashCode(terms);
return result;
}
@Override

View File

@ -72,6 +72,42 @@ public class TestCombinedFieldQuery extends LuceneTestCase {
assertEquals(actual, query);
}
public void testEqualsAndHashCode() {
CombinedFieldQuery query1 =
new CombinedFieldQuery.Builder()
.addField("field1")
.addField("field2")
.addTerm(new BytesRef("value"))
.build();
CombinedFieldQuery query2 =
new CombinedFieldQuery.Builder()
.addField("field1")
.addField("field2", 1.3f)
.addTerm(new BytesRef("value"))
.build();
assertNotEquals(query1, query2);
assertNotEquals(query1.hashCode(), query2.hashCode());
CombinedFieldQuery query3 =
new CombinedFieldQuery.Builder()
.addField("field3")
.addField("field4")
.addTerm(new BytesRef("value"))
.build();
assertNotEquals(query1, query3);
assertNotEquals(query1.hashCode(), query2.hashCode());
CombinedFieldQuery duplicateQuery1 =
new CombinedFieldQuery.Builder()
.addField("field1")
.addField("field2")
.addTerm(new BytesRef("value"))
.build();
assertEquals(query1, duplicateQuery1);
assertEquals(query1.hashCode(), duplicateQuery1.hashCode());
}
public void testToString() {
assertEquals("CombinedFieldQuery(()())", new CombinedFieldQuery.Builder().build().toString());
CombinedFieldQuery.Builder builder = new CombinedFieldQuery.Builder();