mirror of https://github.com/apache/lucene.git
LUCENE-5501: Improved out-of-order collection testing.
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1584829 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
6414781969
commit
f49524fb57
|
@ -138,7 +138,8 @@ public class TestBooleanScorer extends LuceneTestCase {
|
||||||
w.addDocument(doc);
|
w.addDocument(doc);
|
||||||
final IndexReader r = w.getReader();
|
final IndexReader r = w.getReader();
|
||||||
w.close();
|
w.close();
|
||||||
final IndexSearcher s = newSearcher(r);
|
// we don't wrap with AssertingIndexSearcher in order to have the original scorer in setScorer.
|
||||||
|
final IndexSearcher s = newSearcher(r, true, false);
|
||||||
|
|
||||||
final BooleanQuery q = new BooleanQuery();
|
final BooleanQuery q = new BooleanQuery();
|
||||||
for(int term=0;term<33;term++) {
|
for(int term=0;term<33;term++) {
|
||||||
|
@ -154,7 +155,7 @@ public class TestBooleanScorer extends LuceneTestCase {
|
||||||
@Override
|
@Override
|
||||||
public void setScorer(Scorer scorer) {
|
public void setScorer(Scorer scorer) {
|
||||||
// Make sure we got BooleanScorer:
|
// Make sure we got BooleanScorer:
|
||||||
final Class<?> clazz = scorer instanceof AssertingScorer ? ((AssertingScorer) scorer).getIn().getClass() : scorer.getClass();
|
final Class<?> clazz = scorer.getClass();
|
||||||
assertEquals("Scorer is implemented by wrong class", FakeScorer.class.getName(), clazz.getName());
|
assertEquals("Scorer is implemented by wrong class", FakeScorer.class.getName(), clazz.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,8 @@ public class TestConstantScoreQuery extends LuceneTestCase {
|
||||||
|
|
||||||
reader = writer.getReader();
|
reader = writer.getReader();
|
||||||
writer.close();
|
writer.close();
|
||||||
searcher = newSearcher(reader);
|
// we don't wrap with AssertingIndexSearcher in order to have the original scorer in setScorer.
|
||||||
|
searcher = newSearcher(reader, true, false);
|
||||||
|
|
||||||
// set a similarity that does not normalize our boost away
|
// set a similarity that does not normalize our boost away
|
||||||
searcher.setSimilarity(new DefaultSimilarity() {
|
searcher.setSimilarity(new DefaultSimilarity() {
|
||||||
|
|
|
@ -18,93 +18,37 @@ package org.apache.lucene.search;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.WeakHashMap;
|
|
||||||
|
|
||||||
import org.apache.lucene.index.DocsEnum;
|
/** A crazy {@link BulkScorer} that wraps another {@link BulkScorer}
|
||||||
import org.apache.lucene.util.VirtualMethod;
|
|
||||||
|
|
||||||
/** A crazy {@link BulkScorer} that wraps a {@link Scorer}
|
|
||||||
* but shuffles the order of the collected documents. */
|
* but shuffles the order of the collected documents. */
|
||||||
public class AssertingBulkOutOfOrderScorer extends BulkScorer {
|
public class AssertingBulkOutOfOrderScorer extends BulkScorer {
|
||||||
|
|
||||||
|
final BulkScorer in;
|
||||||
final Random random;
|
final Random random;
|
||||||
final Scorer scorer;
|
|
||||||
|
|
||||||
public AssertingBulkOutOfOrderScorer(Random random, Scorer scorer) {
|
public AssertingBulkOutOfOrderScorer(Random random, BulkScorer in) {
|
||||||
|
this.in = in;
|
||||||
this.random = random;
|
this.random = random;
|
||||||
this.scorer = scorer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void shuffle(int[] docIDs, float[] scores, int[] freqs, int size) {
|
|
||||||
for (int i = size - 1; i > 0; --i) {
|
|
||||||
final int other = random.nextInt(i + 1);
|
|
||||||
|
|
||||||
final int tmpDoc = docIDs[i];
|
|
||||||
docIDs[i] = docIDs[other];
|
|
||||||
docIDs[other] = tmpDoc;
|
|
||||||
|
|
||||||
final float tmpScore = scores[i];
|
|
||||||
scores[i] = scores[other];
|
|
||||||
scores[other] = tmpScore;
|
|
||||||
|
|
||||||
final int tmpFreq = freqs[i];
|
|
||||||
freqs[i] = freqs[other];
|
|
||||||
freqs[other] = tmpFreq;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void flush(int[] docIDs, float[] scores, int[] freqs, int size,
|
|
||||||
FakeScorer scorer, LeafCollector collector) throws IOException {
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
scorer.doc = docIDs[i];
|
|
||||||
scorer.freq = freqs[i];
|
|
||||||
scorer.score = scores[i];
|
|
||||||
collector.collect(scorer.doc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean score(LeafCollector collector, int max) throws IOException {
|
public boolean score(LeafCollector collector, int max) throws IOException {
|
||||||
if (scorer.docID() == -1) {
|
final RandomOrderCollector randomCollector = new RandomOrderCollector(random, collector);
|
||||||
scorer.nextDoc();
|
final boolean remaining = in.score(randomCollector, max);
|
||||||
}
|
randomCollector.flush();
|
||||||
|
return remaining;
|
||||||
|
}
|
||||||
|
|
||||||
FakeScorer fake = new FakeScorer();
|
@Override
|
||||||
collector.setScorer(fake);
|
public void score(LeafCollector collector) throws IOException {
|
||||||
|
final RandomOrderCollector randomCollector = new RandomOrderCollector(random, collector);
|
||||||
final int bufferSize = 1 + random.nextInt(100);
|
in.score(randomCollector);
|
||||||
final int[] docIDs = new int[bufferSize];
|
randomCollector.flush();
|
||||||
final float[] scores = new float[bufferSize];
|
|
||||||
final int[] freqs = new int[bufferSize];
|
|
||||||
|
|
||||||
int buffered = 0;
|
|
||||||
int doc = scorer.docID();
|
|
||||||
while (doc < max) {
|
|
||||||
docIDs[buffered] = doc;
|
|
||||||
scores[buffered] = scorer.score();
|
|
||||||
freqs[buffered] = scorer.freq();
|
|
||||||
|
|
||||||
if (++buffered == bufferSize) {
|
|
||||||
shuffle(docIDs, scores, freqs, buffered);
|
|
||||||
flush(docIDs, scores, freqs, buffered, fake, collector);
|
|
||||||
buffered = 0;
|
|
||||||
}
|
|
||||||
doc = scorer.nextDoc();
|
|
||||||
}
|
|
||||||
|
|
||||||
shuffle(docIDs, scores, freqs, buffered);
|
|
||||||
flush(docIDs, scores, freqs, buffered, fake, collector);
|
|
||||||
|
|
||||||
return doc != Scorer.NO_MORE_DOCS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "AssertingBulkOutOfOrderScorer(" + scorer + ")";
|
return "AssertingBulkOutOfOrderScorer(" + in + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,22 +79,20 @@ class AssertingWeight extends Weight {
|
||||||
if (AssertingBulkScorer.shouldWrap(inScorer)) {
|
if (AssertingBulkScorer.shouldWrap(inScorer)) {
|
||||||
// The incoming scorer already has a specialized
|
// The incoming scorer already has a specialized
|
||||||
// implementation for BulkScorer, so we should use it:
|
// implementation for BulkScorer, so we should use it:
|
||||||
return AssertingBulkScorer.wrap(new Random(random.nextLong()), inScorer);
|
inScorer = AssertingBulkScorer.wrap(new Random(random.nextLong()), inScorer);
|
||||||
} else if (scoreDocsInOrder == false && random.nextBoolean()) {
|
} else if (random.nextBoolean()) {
|
||||||
|
// Let super wrap this.scorer instead, so we use
|
||||||
|
// AssertingScorer:
|
||||||
|
inScorer = super.bulkScorer(context, scoreDocsInOrder, acceptDocs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scoreDocsInOrder == false && random.nextBoolean()) {
|
||||||
// The caller claims it can handle out-of-order
|
// The caller claims it can handle out-of-order
|
||||||
// docs; let's confirm that by pulling docs and
|
// docs; let's confirm that by pulling docs and
|
||||||
// randomly shuffling them before collection:
|
// randomly shuffling them before collection:
|
||||||
//Scorer scorer = in.scorer(context, acceptDocs);
|
inScorer = new AssertingBulkOutOfOrderScorer(new Random(random.nextLong()), inScorer);
|
||||||
Scorer scorer = scorer(context, acceptDocs);
|
|
||||||
|
|
||||||
// Scorer should not be null if bulkScorer wasn't:
|
|
||||||
assert scorer != null;
|
|
||||||
return new AssertingBulkOutOfOrderScorer(new Random(random.nextLong()), scorer);
|
|
||||||
} else {
|
|
||||||
// Let super wrap this.scorer instead, so we use
|
|
||||||
// AssertingScorer:
|
|
||||||
return super.bulkScorer(context, scoreDocsInOrder, acceptDocs);
|
|
||||||
}
|
}
|
||||||
|
return inScorer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
package org.apache.lucene.search;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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 java.io.IOException;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/** Randomize collection order. Don't forget to call {@link #flush()} when
|
||||||
|
* collection is finished to collect buffered documents. */
|
||||||
|
final class RandomOrderCollector extends FilterLeafCollector {
|
||||||
|
|
||||||
|
final Random random;
|
||||||
|
Scorer scorer;
|
||||||
|
FakeScorer fakeScorer;
|
||||||
|
|
||||||
|
int buffered;
|
||||||
|
final int bufferSize;
|
||||||
|
final int[] docIDs;
|
||||||
|
final float[] scores;
|
||||||
|
final int[] freqs;
|
||||||
|
|
||||||
|
RandomOrderCollector(Random random, LeafCollector in) {
|
||||||
|
super(in);
|
||||||
|
if (!in.acceptsDocsOutOfOrder()) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
this.random = random;
|
||||||
|
bufferSize = 1 + random.nextInt(100);
|
||||||
|
docIDs = new int[bufferSize];
|
||||||
|
scores = new float[bufferSize];
|
||||||
|
freqs = new int[bufferSize];
|
||||||
|
buffered = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setScorer(Scorer scorer) throws IOException {
|
||||||
|
this.scorer = scorer;
|
||||||
|
fakeScorer = new FakeScorer();
|
||||||
|
in.setScorer(fakeScorer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shuffle() {
|
||||||
|
for (int i = buffered - 1; i > 0; --i) {
|
||||||
|
final int other = random.nextInt(i + 1);
|
||||||
|
|
||||||
|
final int tmpDoc = docIDs[i];
|
||||||
|
docIDs[i] = docIDs[other];
|
||||||
|
docIDs[other] = tmpDoc;
|
||||||
|
|
||||||
|
final float tmpScore = scores[i];
|
||||||
|
scores[i] = scores[other];
|
||||||
|
scores[other] = tmpScore;
|
||||||
|
|
||||||
|
final int tmpFreq = freqs[i];
|
||||||
|
freqs[i] = freqs[other];
|
||||||
|
freqs[other] = tmpFreq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() throws IOException {
|
||||||
|
shuffle();
|
||||||
|
for (int i = 0; i < buffered; ++i) {
|
||||||
|
fakeScorer.doc = docIDs[i];
|
||||||
|
fakeScorer.freq = freqs[i];
|
||||||
|
fakeScorer.score = scores[i];
|
||||||
|
in.collect(fakeScorer.doc);
|
||||||
|
}
|
||||||
|
buffered = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void collect(int doc) throws IOException {
|
||||||
|
docIDs[buffered] = doc;
|
||||||
|
scores[buffered] = scorer.score();
|
||||||
|
try {
|
||||||
|
freqs[buffered] = scorer.freq();
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
freqs[buffered] = -1;
|
||||||
|
}
|
||||||
|
if (++buffered == bufferSize) {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptsDocsOutOfOrder() {
|
||||||
|
return in.acceptsDocsOutOfOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1287,13 +1287,23 @@ public abstract class LuceneTestCase extends Assert {
|
||||||
public static IndexSearcher newSearcher(IndexReader r) {
|
public static IndexSearcher newSearcher(IndexReader r) {
|
||||||
return newSearcher(r, true);
|
return newSearcher(r, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new searcher over the reader. This searcher might randomly use
|
||||||
|
* threads.
|
||||||
|
*/
|
||||||
|
public static IndexSearcher newSearcher(IndexReader r, boolean maybeWrap) {
|
||||||
|
return newSearcher(r, maybeWrap, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new searcher over the reader. This searcher might randomly use
|
* Create a new searcher over the reader. This searcher might randomly use
|
||||||
* threads. if <code>maybeWrap</code> is true, this searcher might wrap the
|
* threads. if <code>maybeWrap</code> is true, this searcher might wrap the
|
||||||
* reader with one that returns null for getSequentialSubReaders.
|
* reader with one that returns null for getSequentialSubReaders. If
|
||||||
|
* <code>wrapWithAssertions</code> is true, this searcher might be an
|
||||||
|
* {@link AssertingIndexSearcher} instance.
|
||||||
*/
|
*/
|
||||||
public static IndexSearcher newSearcher(IndexReader r, boolean maybeWrap) {
|
public static IndexSearcher newSearcher(IndexReader r, boolean maybeWrap, boolean wrapWithAssertions) {
|
||||||
Random random = random();
|
Random random = random();
|
||||||
if (usually()) {
|
if (usually()) {
|
||||||
if (maybeWrap) {
|
if (maybeWrap) {
|
||||||
|
@ -1314,7 +1324,12 @@ public abstract class LuceneTestCase extends Assert {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IndexSearcher ret = random.nextBoolean() ? new AssertingIndexSearcher(random, r) : new AssertingIndexSearcher(random, r.getContext());
|
final IndexSearcher ret;
|
||||||
|
if (wrapWithAssertions) {
|
||||||
|
ret = random.nextBoolean() ? new AssertingIndexSearcher(random, r) : new AssertingIndexSearcher(random, r.getContext());
|
||||||
|
} else {
|
||||||
|
ret = random.nextBoolean() ? new IndexSearcher(r) : new IndexSearcher(r.getContext());
|
||||||
|
}
|
||||||
ret.setSimilarity(classEnvRule.similarity);
|
ret.setSimilarity(classEnvRule.similarity);
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1341,9 +1356,16 @@ public abstract class LuceneTestCase extends Assert {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IndexSearcher ret = random.nextBoolean()
|
IndexSearcher ret;
|
||||||
? new AssertingIndexSearcher(random, r, ex)
|
if (wrapWithAssertions) {
|
||||||
: new AssertingIndexSearcher(random, r.getContext(), ex);
|
ret = random.nextBoolean()
|
||||||
|
? new AssertingIndexSearcher(random, r, ex)
|
||||||
|
: new AssertingIndexSearcher(random, r.getContext(), ex);
|
||||||
|
} else {
|
||||||
|
ret = random.nextBoolean()
|
||||||
|
? new IndexSearcher(r, ex)
|
||||||
|
: new IndexSearcher(r.getContext(), ex);
|
||||||
|
}
|
||||||
ret.setSimilarity(classEnvRule.similarity);
|
ret.setSimilarity(classEnvRule.similarity);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue