mirror of https://github.com/apache/lucene.git
LUCENE-7810: Fix equals() and hashCode() methods of several join queries.
This commit is contained in:
parent
08d24570a7
commit
85c1319c76
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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;
|
||||
private final ScoreMode scoreMode;
|
||||
private final String toField;
|
||||
private final boolean multipleValuesPerDocument;
|
||||
private final BytesRefHash terms;
|
||||
private final float[] scores;
|
||||
private final int[] ords;
|
||||
|
||||
TermsIncludingScoreQuery(String field, boolean multipleValuesPerDocument, BytesRefHash terms, float[] scores, Query originalQuery) {
|
||||
this.field = field;
|
||||
// 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("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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{
|
||||
|
|
Loading…
Reference in New Issue