You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by cp...@apache.org on 2017/05/25 17:55:11 UTC
[02/44] lucene-solr:jira/solr-8668: LUCENE-7810: Fix equals() and
hashCode() methods of several join queries.
LUCENE-7810: Fix equals() and hashCode() methods of several join queries.
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/85c1319c
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/85c1319c
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/85c1319c
Branch: refs/heads/jira/solr-8668
Commit: 85c1319c7678e9deaccb7b7add50fa3f465bd44f
Parents: 08d2457
Author: Martijn van Groningen <ma...@gmail.com>
Authored: Mon May 22 17:56:08 2017 +0200
Committer: Martijn van Groningen <mv...@apache.org>
Committed: Tue May 23 10:45:54 2017 +0200
----------------------------------------------------------------------
lucene/CHANGES.txt | 5 +
.../lucene/search/join/GlobalOrdinalsQuery.java | 6 +-
.../join/GlobalOrdinalsWithScoreQuery.java | 18 +-
.../org/apache/lucene/search/join/JoinUtil.java | 23 +-
.../join/PointInSetIncludingScoreQuery.java | 10 +-
.../search/join/TermsIncludingScoreQuery.java | 91 +++----
.../apache/lucene/search/join/TermsQuery.java | 39 +--
.../apache/lucene/search/join/TestJoinUtil.java | 246 +++++++++++++++++++
.../search/join/TestScoreJoinQPNoScore.java | 9 +
9 files changed, 357 insertions(+), 90 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/85c1319c/lucene/CHANGES.txt
----------------------------------------------------------------------
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 43b13b1..2138321 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -103,6 +103,11 @@ Other
from methods that don't declare them ("sneaky throw" hack). (Robert Muir,
Uwe Schindler, Dawid Weiss)
+Bug Fixes
+
+* LUCENE-7810: Fix equals() and hashCode() methods of several join queries.
+ (Hossman, Adrien Grand, Martijn van Groningen)
+
======================= Lucene 6.6.0 =======================
New Features
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/85c1319c/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java
----------------------------------------------------------------------
diff --git a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java
index 5aaca1a..aacda2d 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java
@@ -20,7 +20,6 @@ import java.io.IOException;
import java.util.Set;
import org.apache.lucene.index.DocValues;
-import org.apache.lucene.index.IndexReaderContext;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.MultiDocValues;
import org.apache.lucene.index.SortedDocValues;
@@ -51,13 +50,14 @@ final class GlobalOrdinalsQuery extends Query {
// id of the context rather than the context itself in order not to hold references to index readers
private final Object indexReaderContextId;
- GlobalOrdinalsQuery(LongBitSet foundOrds, String joinField, MultiDocValues.OrdinalMap globalOrds, Query toQuery, Query fromQuery, IndexReaderContext context) {
+ GlobalOrdinalsQuery(LongBitSet foundOrds, String joinField, MultiDocValues.OrdinalMap globalOrds, Query toQuery,
+ Query fromQuery, Object indexReaderContextId) {
this.foundOrds = foundOrds;
this.joinField = joinField;
this.globalOrds = globalOrds;
this.toQuery = toQuery;
this.fromQuery = fromQuery;
- this.indexReaderContextId = context.id();
+ this.indexReaderContextId = indexReaderContextId;
}
@Override
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/85c1319c/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java
----------------------------------------------------------------------
diff --git a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java
index 5e614ea..1c80bf3 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java
@@ -20,7 +20,6 @@ import java.io.IOException;
import java.util.Set;
import org.apache.lucene.index.DocValues;
-import org.apache.lucene.index.IndexReaderContext;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.MultiDocValues;
import org.apache.lucene.index.SortedDocValues;
@@ -45,21 +44,25 @@ final class GlobalOrdinalsWithScoreQuery extends Query {
private final Query toQuery;
// just for hashcode and equals:
+ private final ScoreMode scoreMode;
private final Query fromQuery;
private final int min;
private final int max;
// id of the context rather than the context itself in order not to hold references to index readers
private final Object indexReaderContextId;
- GlobalOrdinalsWithScoreQuery(GlobalOrdinalsWithScoreCollector collector, String joinField, MultiDocValues.OrdinalMap globalOrds, Query toQuery, Query fromQuery, int min, int max, IndexReaderContext context) {
+ GlobalOrdinalsWithScoreQuery(GlobalOrdinalsWithScoreCollector collector, ScoreMode scoreMode, String joinField,
+ MultiDocValues.OrdinalMap globalOrds, Query toQuery, Query fromQuery, int min, int max,
+ Object indexReaderContextId) {
this.collector = collector;
this.joinField = joinField;
this.globalOrds = globalOrds;
this.toQuery = toQuery;
+ this.scoreMode = scoreMode;
this.fromQuery = fromQuery;
this.min = min;
this.max = max;
- this.indexReaderContextId = context.id();
+ this.indexReaderContextId = indexReaderContextId;
}
@Override
@@ -67,6 +70,13 @@ final class GlobalOrdinalsWithScoreQuery extends Query {
if (searcher.getTopReaderContext().id() != indexReaderContextId) {
throw new IllegalStateException("Creating the weight against a different index reader than this query has been built for.");
}
+ boolean doNoMinMax = min <= 0 && max == Integer.MAX_VALUE;
+ if (needsScores == false && doNoMinMax) {
+ // We don't need scores then quickly change the query to not uses the scores:
+ GlobalOrdinalsQuery globalOrdinalsQuery = new GlobalOrdinalsQuery(collector.collectedOrds, joinField, globalOrds,
+ toQuery, fromQuery, indexReaderContextId);
+ return globalOrdinalsQuery.createWeight(searcher, false, boost);
+ }
return new W(this, toQuery.createWeight(searcher, false, 1f));
}
@@ -79,6 +89,7 @@ final class GlobalOrdinalsWithScoreQuery extends Query {
private boolean equalsTo(GlobalOrdinalsWithScoreQuery other) {
return min == other.min &&
max == other.max &&
+ scoreMode.equals(other.scoreMode) &&
joinField.equals(other.joinField) &&
fromQuery.equals(other.fromQuery) &&
toQuery.equals(other.toQuery) &&
@@ -88,6 +99,7 @@ final class GlobalOrdinalsWithScoreQuery extends Query {
@Override
public int hashCode() {
int result = classHash();
+ result = 31 * result + scoreMode.hashCode();
result = 31 * result + joinField.hashCode();
result = 31 * result + toQuery.hashCode();
result = 31 * result + fromQuery.hashCode();
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/85c1319c/lucene/join/src/java/org/apache/lucene/search/join/JoinUtil.java
----------------------------------------------------------------------
diff --git a/lucene/join/src/java/org/apache/lucene/search/join/JoinUtil.java b/lucene/join/src/java/org/apache/lucene/search/join/JoinUtil.java
index 537b224..d7e0ae8 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/JoinUtil.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/JoinUtil.java
@@ -104,7 +104,7 @@ public final class JoinUtil {
termsWithScoreCollector = GenericTermsCollector.createCollectorSV(svFunction, scoreMode);
}
- return createJoinQuery(multipleValuesPerDocument, toField, fromQuery, fromSearcher, scoreMode, termsWithScoreCollector);
+ return createJoinQuery(multipleValuesPerDocument, toField, fromQuery, fromField, fromSearcher, scoreMode, termsWithScoreCollector);
}
/**
@@ -362,7 +362,7 @@ public final class JoinUtil {
encoded.length = bytesPerDim;
if (needsScore) {
- return new PointInSetIncludingScoreQuery(fromQuery, multipleValuesPerDocument, toField, bytesPerDim, stream) {
+ return new PointInSetIncludingScoreQuery(scoreMode, fromQuery, multipleValuesPerDocument, toField, bytesPerDim, stream) {
@Override
protected String toString(byte[] value) {
@@ -379,25 +379,26 @@ public final class JoinUtil {
}
}
- private static Query createJoinQuery(boolean multipleValuesPerDocument, String toField, Query fromQuery,
- IndexSearcher fromSearcher, ScoreMode scoreMode, final GenericTermsCollector collector)
- throws IOException {
+ private static Query createJoinQuery(boolean multipleValuesPerDocument, String toField, Query fromQuery, String fromField,
+ IndexSearcher fromSearcher, ScoreMode scoreMode, final GenericTermsCollector collector) throws IOException {
fromSearcher.search(fromQuery, collector);
-
switch (scoreMode) {
case None:
- return new TermsQuery(toField, fromQuery, collector.getCollectedTerms());
+ return new TermsQuery(toField, collector.getCollectedTerms(), fromField, fromQuery, fromSearcher.getTopReaderContext().id());
case Total:
case Max:
case Min:
case Avg:
return new TermsIncludingScoreQuery(
+ scoreMode,
toField,
multipleValuesPerDocument,
collector.getCollectedTerms(),
collector.getScoresPerTerm(),
- fromQuery
+ fromField,
+ fromQuery,
+ fromSearcher.getTopReaderContext().id()
);
default:
throw new IllegalArgumentException(String.format(Locale.ROOT, "Score mode %s isn't supported.", scoreMode));
@@ -507,7 +508,8 @@ public final class JoinUtil {
if (min <= 0 && max == Integer.MAX_VALUE) {
GlobalOrdinalsCollector globalOrdinalsCollector = new GlobalOrdinalsCollector(joinField, ordinalMap, valueCount);
searcher.search(rewrittenFromQuery, globalOrdinalsCollector);
- return new GlobalOrdinalsQuery(globalOrdinalsCollector.getCollectorOrdinals(), joinField, ordinalMap, rewrittenToQuery, rewrittenFromQuery, searcher.getTopReaderContext());
+ return new GlobalOrdinalsQuery(globalOrdinalsCollector.getCollectorOrdinals(), joinField, ordinalMap, rewrittenToQuery,
+ rewrittenFromQuery, searcher.getTopReaderContext().id());
} else {
globalOrdinalsWithScoreCollector = new GlobalOrdinalsWithScoreCollector.NoScore(joinField, ordinalMap, valueCount, min, max);
break;
@@ -516,7 +518,8 @@ public final class JoinUtil {
throw new IllegalArgumentException(String.format(Locale.ROOT, "Score mode %s isn't supported.", scoreMode));
}
searcher.search(rewrittenFromQuery, globalOrdinalsWithScoreCollector);
- return new GlobalOrdinalsWithScoreQuery(globalOrdinalsWithScoreCollector, joinField, ordinalMap, rewrittenToQuery, rewrittenFromQuery, min, max, searcher.getTopReaderContext());
+ return new GlobalOrdinalsWithScoreQuery(globalOrdinalsWithScoreCollector, scoreMode, joinField, ordinalMap, rewrittenToQuery,
+ rewrittenFromQuery, min, max, searcher.getTopReaderContext().id());
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/85c1319c/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java
----------------------------------------------------------------------
diff --git a/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java
index 70c28d5..3130ae6 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java
@@ -66,6 +66,7 @@ abstract class PointInSetIncludingScoreQuery extends Query {
}
};
+ final ScoreMode scoreMode;
final Query originalQuery;
final boolean multipleValuesPerDocument;
final PrefixCodedTerms sortedPackedPoints;
@@ -81,8 +82,9 @@ abstract class PointInSetIncludingScoreQuery extends Query {
}
- PointInSetIncludingScoreQuery(Query originalQuery, boolean multipleValuesPerDocument, String field, int bytesPerDim,
- Stream packedPoints) {
+ PointInSetIncludingScoreQuery(ScoreMode scoreMode, Query originalQuery, boolean multipleValuesPerDocument,
+ String field, int bytesPerDim, Stream packedPoints) {
+ this.scoreMode = scoreMode;
this.originalQuery = originalQuery;
this.multipleValuesPerDocument = multipleValuesPerDocument;
this.field = field;
@@ -276,6 +278,7 @@ abstract class PointInSetIncludingScoreQuery extends Query {
@Override
public final int hashCode() {
int hash = classHash();
+ hash = 31 * hash + scoreMode.hashCode();
hash = 31 * hash + field.hashCode();
hash = 31 * hash + originalQuery.hashCode();
hash = 31 * hash + sortedPackedPointsHashCode;
@@ -290,7 +293,8 @@ abstract class PointInSetIncludingScoreQuery extends Query {
}
private boolean equalsTo(PointInSetIncludingScoreQuery other) {
- return other.field.equals(field) &&
+ return other.scoreMode.equals(scoreMode) &&
+ other.field.equals(field) &&
other.originalQuery.equals(originalQuery) &&
other.bytesPerDim == bytesPerDim &&
other.sortedPackedPointsHashCode == sortedPackedPointsHashCode &&
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/85c1319c/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java
----------------------------------------------------------------------
diff --git a/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java
index 28d3044..cd3beaf 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java
@@ -17,11 +17,10 @@
package org.apache.lucene.search.join;
import java.io.IOException;
-import java.io.PrintStream;
import java.util.Locale;
+import java.util.Objects;
import java.util.Set;
-import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.PostingsEnum;
import org.apache.lucene.index.Term;
@@ -40,48 +39,36 @@ import org.apache.lucene.util.FixedBitSet;
class TermsIncludingScoreQuery extends Query {
- final String field;
- final boolean multipleValuesPerDocument;
- final BytesRefHash terms;
- final float[] scores;
- final int[] ords;
- final Query originalQuery;
- final Query unwrittenOriginalQuery;
-
- TermsIncludingScoreQuery(String field, boolean multipleValuesPerDocument, BytesRefHash terms, float[] scores, Query originalQuery) {
- this.field = field;
+ private final ScoreMode scoreMode;
+ private final String toField;
+ private final boolean multipleValuesPerDocument;
+ private final BytesRefHash terms;
+ private final float[] scores;
+ private final int[] ords;
+
+ // These fields are used for equals() and hashcode() only
+ private final Query fromQuery;
+ private final String fromField;
+ // id of the context rather than the context itself in order not to hold references to index readers
+ private final Object topReaderContextId;
+
+ TermsIncludingScoreQuery(ScoreMode scoreMode, String toField, boolean multipleValuesPerDocument, BytesRefHash terms, float[] scores,
+ String fromField, Query fromQuery, Object indexReaderContextId) {
+ this.scoreMode = scoreMode;
+ this.toField = toField;
this.multipleValuesPerDocument = multipleValuesPerDocument;
this.terms = terms;
this.scores = scores;
- this.originalQuery = originalQuery;
this.ords = terms.sort();
- this.unwrittenOriginalQuery = originalQuery;
- }
- private TermsIncludingScoreQuery(String field, boolean multipleValuesPerDocument, BytesRefHash terms, float[] scores, int[] ords, Query originalQuery, Query unwrittenOriginalQuery) {
- this.field = field;
- this.multipleValuesPerDocument = multipleValuesPerDocument;
- this.terms = terms;
- this.scores = scores;
- this.originalQuery = originalQuery;
- this.ords = ords;
- this.unwrittenOriginalQuery = unwrittenOriginalQuery;
+ this.fromField = fromField;
+ this.fromQuery = fromQuery;
+ this.topReaderContextId = indexReaderContextId;
}
@Override
public String toString(String string) {
- return String.format(Locale.ROOT, "TermsIncludingScoreQuery{field=%s;originalQuery=%s}", field, unwrittenOriginalQuery);
- }
-
- @Override
- public Query rewrite(IndexReader reader) throws IOException {
- final Query originalQueryRewrite = originalQuery.rewrite(reader);
- if (originalQueryRewrite != originalQuery) {
- return new TermsIncludingScoreQuery(field, multipleValuesPerDocument, terms, scores,
- ords, originalQueryRewrite, originalQuery);
- } else {
- return super.rewrite(reader);
- }
+ return String.format(Locale.ROOT, "TermsIncludingScoreQuery{field=%s;fromQuery=%s}", toField, fromQuery);
}
@Override
@@ -91,21 +78,25 @@ class TermsIncludingScoreQuery extends Query {
}
private boolean equalsTo(TermsIncludingScoreQuery other) {
- return field.equals(other.field) &&
- unwrittenOriginalQuery.equals(other.unwrittenOriginalQuery);
+ return Objects.equals(scoreMode, other.scoreMode) &&
+ Objects.equals(toField, other.toField) &&
+ Objects.equals(fromField, other.fromField) &&
+ Objects.equals(fromQuery, other.fromQuery) &&
+ Objects.equals(topReaderContextId, other.topReaderContextId);
}
@Override
public int hashCode() {
- final int prime = 31;
- int result = classHash();
- result += prime * field.hashCode();
- result += prime * unwrittenOriginalQuery.hashCode();
- return result;
+ return classHash() + Objects.hash(scoreMode, toField, fromField, fromQuery, topReaderContextId);
}
@Override
public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException {
+ if (needsScores == false) {
+ // We don't need scores then quickly change the query:
+ TermsQuery termsQuery = new TermsQuery(toField, terms, fromField, fromQuery, topReaderContextId);
+ return searcher.rewrite(termsQuery).createWeight(searcher, false, boost);
+ }
return new Weight(TermsIncludingScoreQuery.this) {
@Override
@@ -113,7 +104,7 @@ class TermsIncludingScoreQuery extends Query {
@Override
public Explanation explain(LeafReaderContext context, int doc) throws IOException {
- Terms terms = context.reader().terms(field);
+ Terms terms = context.reader().terms(toField);
if (terms != null) {
TermsEnum segmentTermsEnum = terms.iterator();
BytesRef spare = new BytesRef();
@@ -133,7 +124,7 @@ class TermsIncludingScoreQuery extends Query {
@Override
public Scorer scorer(LeafReaderContext context) throws IOException {
- Terms terms = context.reader().terms(field);
+ Terms terms = context.reader().terms(toField);
if (terms == null) {
return null;
}
@@ -151,7 +142,7 @@ class TermsIncludingScoreQuery extends Query {
};
}
-
+
class SVInOrderScorer extends Scorer {
final DocIdSetIterator matchingDocsIterator;
@@ -238,14 +229,4 @@ class TermsIncludingScoreQuery extends Query {
}
}
- void dump(PrintStream out){
- out.println(field+":");
- final BytesRef ref = new BytesRef();
- for (int i = 0; i < terms.size(); i++) {
- terms.get(ords[i], ref);
- out.print(ref+" "+ref.utf8ToString()+" ");
- out.println(" score="+scores[ords[i]]);
- out.println("");
- }
- }
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/85c1319c/lucene/join/src/java/org/apache/lucene/search/join/TermsQuery.java
----------------------------------------------------------------------
diff --git a/lucene/join/src/java/org/apache/lucene/search/join/TermsQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/TermsQuery.java
index 63561c3..3ff0a5c 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/TermsQuery.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/TermsQuery.java
@@ -16,6 +16,9 @@
*/
package org.apache.lucene.search.join;
+import java.io.IOException;
+import java.util.Objects;
+
import org.apache.lucene.index.FilteredTermsEnum;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum;
@@ -25,8 +28,6 @@ import org.apache.lucene.util.AttributeSource;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefHash;
-import java.io.IOException;
-
/**
* A query that has an array of terms from a specific field. This query will match documents have one or more terms in
* the specified field that match with the terms specified in the array.
@@ -37,17 +38,25 @@ class TermsQuery extends MultiTermQuery {
private final BytesRefHash terms;
private final int[] ords;
- private final Query fromQuery; // Used for equals() only
+
+ // These fields are used for equals() and hashcode() only
+ private final String fromField;
+ private final Query fromQuery;
+ // id of the context rather than the context itself in order not to hold references to index readers
+ private final Object indexReaderContextId;
/**
- * @param field The field that should contain terms that are specified in the previous parameter
- * @param terms The terms that matching documents should have. The terms must be sorted by natural order.
+ * @param toField The field that should contain terms that are specified in the next parameter.
+ * @param terms The terms that matching documents should have. The terms must be sorted by natural order.
+ * @param indexReaderContextId Refers to the top level index reader used to create the set of terms in the previous parameter.
*/
- TermsQuery(String field, Query fromQuery, BytesRefHash terms) {
- super(field);
- this.fromQuery = fromQuery;
+ TermsQuery(String toField, BytesRefHash terms, String fromField, Query fromQuery, Object indexReaderContextId) {
+ super(toField);
this.terms = terms;
ords = terms.sort();
+ this.fromField = fromField;
+ this.fromQuery = fromQuery;
+ this.indexReaderContextId = indexReaderContextId;
}
@Override
@@ -63,6 +72,7 @@ class TermsQuery extends MultiTermQuery {
public String toString(String string) {
return "TermsQuery{" +
"field=" + field +
+ "fromQuery=" + fromQuery.toString(field) +
'}';
}
@@ -77,18 +87,15 @@ class TermsQuery extends MultiTermQuery {
}
TermsQuery other = (TermsQuery) obj;
- if (!fromQuery.equals(other.fromQuery)) {
- return false;
- }
- return true;
+ return Objects.equals(field, other.field) &&
+ Objects.equals(fromField, other.fromField) &&
+ Objects.equals(fromQuery, other.fromQuery) &&
+ Objects.equals(indexReaderContextId, other.indexReaderContextId);
}
@Override
public int hashCode() {
- final int prime = 31;
- int result = super.hashCode();
- result += prime * fromQuery.hashCode();
- return result;
+ return classHash() + Objects.hash(field, fromField, fromQuery, indexReaderContextId);
}
static class SeekingTermSetTermsEnum extends FilteredTermsEnum {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/85c1319c/lucene/join/src/test/org/apache/lucene/search/join/TestJoinUtil.java
----------------------------------------------------------------------
diff --git a/lucene/join/src/test/org/apache/lucene/search/join/TestJoinUtil.java b/lucene/join/src/test/org/apache/lucene/search/join/TestJoinUtil.java
index 72b6bf5..c95e144 100644
--- a/lucene/join/src/test/org/apache/lucene/search/join/TestJoinUtil.java
+++ b/lucene/join/src/test/org/apache/lucene/search/join/TestJoinUtil.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -922,6 +923,251 @@ public class TestJoinUtil extends LuceneTestCase {
dir.close();
}
+ public void testEquals() throws Exception {
+ final int numDocs = atLeast(random(), 50);
+ try (final Directory dir = newDirectory()) {
+ try (final RandomIndexWriter w = new RandomIndexWriter(random(), dir,
+ newIndexWriterConfig(new MockAnalyzer(random()))
+ .setMergePolicy(newLogMergePolicy()))) {
+ boolean multiValued = random().nextBoolean();
+ String joinField = multiValued ? "mvField" : "svField";
+ for (int id = 0; id < numDocs; id++) {
+ Document doc = new Document();
+ doc.add(new TextField("id", "" + id, Field.Store.NO));
+ doc.add(new TextField("name", "name" + (id % 7), Field.Store.NO));
+ if (multiValued) {
+ int numValues = 1 + random().nextInt(2);
+ for (int i = 0; i < numValues; i++) {
+ doc.add(new SortedSetDocValuesField(joinField, new BytesRef("" + random().nextInt(13))));
+ }
+ } else {
+ doc.add(new SortedDocValuesField(joinField, new BytesRef("" + random().nextInt(13))));
+ }
+ w.addDocument(doc);
+ }
+
+ Set<ScoreMode> scoreModes = EnumSet.allOf(ScoreMode.class);
+ ScoreMode scoreMode1 = RandomPicks.randomFrom(random(), scoreModes);
+ scoreModes.remove(scoreMode1);
+ ScoreMode scoreMode2 = RandomPicks.randomFrom(random(), scoreModes);
+
+ final Query x;
+ try (IndexReader r = w.getReader()) {
+ IndexSearcher indexSearcher = new IndexSearcher(r);
+ x = JoinUtil.createJoinQuery(joinField, multiValued, joinField,
+ new TermQuery(new Term("name", "name5")),
+ indexSearcher, scoreMode1);
+ assertEquals("identical calls to createJoinQuery",
+ x, JoinUtil.createJoinQuery(joinField, multiValued, joinField,
+ new TermQuery(new Term("name", "name5")),
+ indexSearcher, scoreMode1));
+
+ assertFalse("score mode (" + scoreMode1 + " != " + scoreMode2 + "), but queries are equal",
+ x.equals(JoinUtil.createJoinQuery(joinField, multiValued, joinField,
+ new TermQuery(new Term("name", "name5")),
+ indexSearcher, scoreMode2)));
+
+
+ assertFalse("from fields (joinField != \"other_field\") but queries equals",
+ x.equals(JoinUtil.createJoinQuery(joinField, multiValued, "other_field",
+ new TermQuery(new Term("name", "name5")),
+ indexSearcher, scoreMode1)));
+
+ assertFalse("from fields (\"other_field\" != joinField) but queries equals",
+ x.equals(JoinUtil.createJoinQuery("other_field", multiValued, joinField,
+ new TermQuery(new Term("name", "name5")),
+ indexSearcher, scoreMode1)));
+
+ assertFalse("fromQuery (name:name5 != name:name6) but queries equals",
+ x.equals(JoinUtil.createJoinQuery("other_field", multiValued, joinField,
+ new TermQuery(new Term("name", "name6")),
+ indexSearcher, scoreMode1)));
+ }
+
+ for (int i = 0; i < 13; i++) {
+ Document doc = new Document();
+ doc.add(new TextField("id", "new_id" , Field.Store.NO));
+ doc.add(new TextField("name", "name5", Field.Store.NO));
+ if (multiValued) {
+ int numValues = 1 + random().nextInt(2);
+ for (int j = 0; j < numValues; j++) {
+ doc.add(new SortedSetDocValuesField(joinField, new BytesRef("" + i)));
+ }
+ } else {
+ doc.add(new SortedDocValuesField(joinField, new BytesRef("" + i)));
+ }
+ w.addDocument(doc);
+ }
+ try (IndexReader r = w.getReader()) {
+ IndexSearcher indexSearcher = new IndexSearcher(r);
+ assertFalse("Query shouldn't be equal, because different index readers ",
+ x.equals(JoinUtil.createJoinQuery(joinField, multiValued, joinField,
+ new TermQuery(new Term("name", "name5")),
+ indexSearcher, scoreMode1)));
+ }
+ }
+ }
+ }
+
+ public void testEquals_globalOrdinalsJoin() throws Exception {
+ final int numDocs = atLeast(random(), 50);
+ try (final Directory dir = newDirectory()) {
+ try (final RandomIndexWriter w = new RandomIndexWriter(random(), dir,
+ newIndexWriterConfig(new MockAnalyzer(random()))
+ .setMergePolicy(newLogMergePolicy()))) {
+ String joinField = "field";
+ for (int id = 0; id < numDocs; id++) {
+ Document doc = new Document();
+ doc.add(new TextField("id", "" + id, Field.Store.NO));
+ doc.add(new TextField("name", "name" + (id % 7), Field.Store.NO));
+ doc.add(new SortedDocValuesField(joinField, new BytesRef("" + random().nextInt(13))));
+ w.addDocument(doc);
+ }
+
+ Set<ScoreMode> scoreModes = EnumSet.allOf(ScoreMode.class);
+ ScoreMode scoreMode1 = RandomPicks.randomFrom(random(), scoreModes);
+ scoreModes.remove(scoreMode1);
+ ScoreMode scoreMode2 = RandomPicks.randomFrom(random(), scoreModes);
+
+ final Query x;
+ try (IndexReader r = w.getReader()) {
+ SortedDocValues[] values = new SortedDocValues[r.leaves().size()];
+ for (int i = 0; i < values.length; i++) {
+ LeafReader leafReader = r.leaves().get(i).reader();
+ values[i] = DocValues.getSorted(leafReader, joinField);
+ }
+ MultiDocValues.OrdinalMap ordinalMap = MultiDocValues.OrdinalMap.build(
+ null, values, PackedInts.DEFAULT
+ );
+ IndexSearcher indexSearcher = new IndexSearcher(r);
+ x = JoinUtil.createJoinQuery(joinField, new TermQuery(new Term("name", "name5")), new MatchAllDocsQuery(),
+ indexSearcher, scoreMode1, ordinalMap);
+ assertEquals("identical calls to createJoinQuery",
+ x, JoinUtil.createJoinQuery(joinField, new TermQuery(new Term("name", "name5")), new MatchAllDocsQuery(),
+ indexSearcher, scoreMode1, ordinalMap));
+
+ assertFalse("score mode (" + scoreMode1 + " != " + scoreMode2 + "), but queries are equal",
+ x.equals(JoinUtil.createJoinQuery(joinField, new TermQuery(new Term("name", "name5")), new MatchAllDocsQuery(),
+ indexSearcher, scoreMode2, ordinalMap)));
+ assertFalse("fromQuery (name:name5 != name:name6) but queries equals",
+ x.equals(JoinUtil.createJoinQuery(joinField, new TermQuery(new Term("name", "name6")), new MatchAllDocsQuery(),
+ indexSearcher, scoreMode1, ordinalMap)));
+ }
+
+ for (int i = 0; i < 13; i++) {
+ Document doc = new Document();
+ doc.add(new TextField("id", "new_id" , Field.Store.NO));
+ doc.add(new TextField("name", "name5", Field.Store.NO));
+ doc.add(new SortedDocValuesField(joinField, new BytesRef("" + i)));
+ w.addDocument(doc);
+ }
+ try (IndexReader r = w.getReader()) {
+ SortedDocValues[] values = new SortedDocValues[r.leaves().size()];
+ for (int i = 0; i < values.length; i++) {
+ LeafReader leafReader = r.leaves().get(i).reader();
+ values[i] = DocValues.getSorted(leafReader, joinField);
+ }
+ MultiDocValues.OrdinalMap ordinalMap = MultiDocValues.OrdinalMap.build(
+ null, values, PackedInts.DEFAULT
+ );
+ IndexSearcher indexSearcher = new IndexSearcher(r);
+ assertFalse("Query shouldn't be equal, because different index readers ",
+ x.equals(JoinUtil.createJoinQuery(joinField, new TermQuery(new Term("name", "name5")), new MatchAllDocsQuery(),
+ indexSearcher, scoreMode1, ordinalMap)));
+ }
+ }
+ }
+ }
+
+ public void testEquals_numericJoin() throws Exception {
+ final int numDocs = atLeast(random(), 50);
+ try (final Directory dir = newDirectory()) {
+ try (final RandomIndexWriter w = new RandomIndexWriter(random(), dir,
+ newIndexWriterConfig(new MockAnalyzer(random()))
+ .setMergePolicy(newLogMergePolicy()))) {
+ boolean multiValued = random().nextBoolean();
+ String joinField = multiValued ? "mvField" : "svField";
+ for (int id = 0; id < numDocs; id++) {
+ Document doc = new Document();
+ doc.add(new TextField("id", "" + id, Field.Store.NO));
+ doc.add(new TextField("name", "name" + (id % 7), Field.Store.NO));
+ if (multiValued) {
+ int numValues = 1 + random().nextInt(2);
+ for (int i = 0; i < numValues; i++) {
+ doc.add(new IntPoint(joinField, random().nextInt(13)));
+ doc.add(new SortedNumericDocValuesField(joinField, random().nextInt(13)));
+ }
+ } else {
+ doc.add(new IntPoint(joinField, random().nextInt(13)));
+ doc.add(new NumericDocValuesField(joinField, random().nextInt(13)));
+ }
+ w.addDocument(doc);
+ }
+
+ Set<ScoreMode> scoreModes = EnumSet.allOf(ScoreMode.class);
+ ScoreMode scoreMode1 = scoreModes.toArray(new ScoreMode[0])[random().nextInt(scoreModes.size())];
+ scoreModes.remove(scoreMode1);
+ ScoreMode scoreMode2 = scoreModes.toArray(new ScoreMode[0])[random().nextInt(scoreModes.size())];
+
+ final Query x;
+ try (IndexReader r = w.getReader()) {
+ IndexSearcher indexSearcher = new IndexSearcher(r);
+ x = JoinUtil.createJoinQuery(joinField, multiValued, joinField,
+ Integer.class, new TermQuery(new Term("name", "name5")),
+ indexSearcher, scoreMode1);
+ assertEquals("identical calls to createJoinQuery",
+ x, JoinUtil.createJoinQuery(joinField, multiValued, joinField,
+ Integer.class, new TermQuery(new Term("name", "name5")),
+ indexSearcher, scoreMode1));
+
+ assertFalse("score mode (" + scoreMode1 + " != " + scoreMode2 + "), but queries are equal",
+ x.equals(JoinUtil.createJoinQuery(joinField, multiValued, joinField,
+ Integer.class, new TermQuery(new Term("name", "name5")),
+ indexSearcher, scoreMode2)));
+
+ assertFalse("from fields (joinField != \"other_field\") but queries equals",
+ x.equals(JoinUtil.createJoinQuery(joinField, multiValued, "other_field",
+ Integer.class, new TermQuery(new Term("name", "name5")),
+ indexSearcher, scoreMode1)));
+
+ assertFalse("from fields (\"other_field\" != joinField) but queries equals",
+ x.equals(JoinUtil.createJoinQuery("other_field", multiValued, joinField,
+ Integer.class, new TermQuery(new Term("name", "name5")),
+ indexSearcher, scoreMode1)));
+
+ assertFalse("fromQuery (name:name5 != name:name6) but queries equals",
+ x.equals(JoinUtil.createJoinQuery("other_field", multiValued, joinField,
+ Integer.class, new TermQuery(new Term("name", "name6")),
+ indexSearcher, scoreMode1)));
+ }
+
+ for (int i = 0; i < 13; i++) {
+ Document doc = new Document();
+ doc.add(new TextField("id", "new_id" , Field.Store.NO));
+ doc.add(new TextField("name", "name5", Field.Store.NO));
+ if (multiValued) {
+ int numValues = 1 + random().nextInt(2);
+ for (int j = 0; j < numValues; j++) {
+ doc.add(new SortedNumericDocValuesField(joinField, i));
+ doc.add(new IntPoint(joinField, i));
+ }
+ } else {
+ doc.add(new NumericDocValuesField(joinField, i));
+ doc.add(new IntPoint(joinField, i));
+ }
+ w.addDocument(doc);
+ }
+ try (IndexReader r = w.getReader()) {
+ IndexSearcher indexSearcher = new IndexSearcher(r);
+ assertFalse("Query shouldn't be equal, because different index readers ",
+ x.equals(JoinUtil.createJoinQuery(joinField, multiValued, joinField,
+ Integer.class, new TermQuery(new Term("name", "name5")),
+ indexSearcher, scoreMode1)));
+ }
+ }
+ }
+ }
+
@Test
@Slow
public void testSingleValueRandomJoin() throws Exception {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/85c1319c/solr/core/src/test/org/apache/solr/search/join/TestScoreJoinQPNoScore.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/join/TestScoreJoinQPNoScore.java b/solr/core/src/test/org/apache/solr/search/join/TestScoreJoinQPNoScore.java
index 0d9801e..38c111a 100644
--- a/solr/core/src/test/org/apache/solr/search/join/TestScoreJoinQPNoScore.java
+++ b/solr/core/src/test/org/apache/solr/search/join/TestScoreJoinQPNoScore.java
@@ -158,6 +158,15 @@ public class TestScoreJoinQPNoScore extends SolrTestCaseJ4 {
}
+ public void testNotEquals() throws SyntaxError, IOException{
+ try (SolrQueryRequest req = req("*:*")) {
+ Query x = QParser.getParser("{!join from=dept_id_s to=dept_ss score=none}text_t:develop", req).getQuery();
+ Query y = QParser.getParser("{!join from=dept_ss to=dept_ss score=none}text_t:develop", req).getQuery();
+ assertFalse("diff from fields produce equal queries",
+ x.equals(y));
+ }
+ }
+
public void testJoinQueryType() throws SyntaxError, IOException{
SolrQueryRequest req = null;
try{