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);
|
||||
final IndexReader r = w.getReader();
|
||||
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();
|
||||
for(int term=0;term<33;term++) {
|
||||
|
@ -154,7 +155,7 @@ public class TestBooleanScorer extends LuceneTestCase {
|
|||
@Override
|
||||
public void setScorer(Scorer scorer) {
|
||||
// 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());
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,8 @@ public class TestConstantScoreQuery extends LuceneTestCase {
|
|||
|
||||
reader = writer.getReader();
|
||||
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
|
||||
searcher.setSimilarity(new DefaultSimilarity() {
|
||||
|
|
|
@ -18,93 +18,37 @@ package org.apache.lucene.search;
|
|||
*/
|
||||
|
||||
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.WeakHashMap;
|
||||
|
||||
import org.apache.lucene.index.DocsEnum;
|
||||
import org.apache.lucene.util.VirtualMethod;
|
||||
|
||||
/** A crazy {@link BulkScorer} that wraps a {@link Scorer}
|
||||
/** A crazy {@link BulkScorer} that wraps another {@link BulkScorer}
|
||||
* but shuffles the order of the collected documents. */
|
||||
public class AssertingBulkOutOfOrderScorer extends BulkScorer {
|
||||
|
||||
final BulkScorer in;
|
||||
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.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
|
||||
public boolean score(LeafCollector collector, int max) throws IOException {
|
||||
if (scorer.docID() == -1) {
|
||||
scorer.nextDoc();
|
||||
}
|
||||
final RandomOrderCollector randomCollector = new RandomOrderCollector(random, collector);
|
||||
final boolean remaining = in.score(randomCollector, max);
|
||||
randomCollector.flush();
|
||||
return remaining;
|
||||
}
|
||||
|
||||
FakeScorer fake = new FakeScorer();
|
||||
collector.setScorer(fake);
|
||||
|
||||
final int bufferSize = 1 + random.nextInt(100);
|
||||
final int[] docIDs = new int[bufferSize];
|
||||
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
|
||||
public void score(LeafCollector collector) throws IOException {
|
||||
final RandomOrderCollector randomCollector = new RandomOrderCollector(random, collector);
|
||||
in.score(randomCollector);
|
||||
randomCollector.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AssertingBulkOutOfOrderScorer(" + scorer + ")";
|
||||
return "AssertingBulkOutOfOrderScorer(" + in + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,22 +79,20 @@ class AssertingWeight extends Weight {
|
|||
if (AssertingBulkScorer.shouldWrap(inScorer)) {
|
||||
// The incoming scorer already has a specialized
|
||||
// implementation for BulkScorer, so we should use it:
|
||||
return AssertingBulkScorer.wrap(new Random(random.nextLong()), inScorer);
|
||||
} else if (scoreDocsInOrder == false && random.nextBoolean()) {
|
||||
inScorer = AssertingBulkScorer.wrap(new Random(random.nextLong()), inScorer);
|
||||
} 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
|
||||
// docs; let's confirm that by pulling docs and
|
||||
// randomly shuffling them before collection:
|
||||
//Scorer scorer = in.scorer(context, acceptDocs);
|
||||
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);
|
||||
inScorer = new AssertingBulkOutOfOrderScorer(new Random(random.nextLong()), inScorer);
|
||||
}
|
||||
return inScorer;
|
||||
}
|
||||
|
||||
@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) {
|
||||
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
|
||||
* 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();
|
||||
if (usually()) {
|
||||
if (maybeWrap) {
|
||||
|
@ -1314,7 +1324,12 @@ public abstract class LuceneTestCase extends Assert {
|
|||
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);
|
||||
return ret;
|
||||
} else {
|
||||
|
@ -1341,9 +1356,16 @@ public abstract class LuceneTestCase extends Assert {
|
|||
}
|
||||
});
|
||||
}
|
||||
IndexSearcher ret = random.nextBoolean()
|
||||
? new AssertingIndexSearcher(random, r, ex)
|
||||
: new AssertingIndexSearcher(random, r.getContext(), ex);
|
||||
IndexSearcher ret;
|
||||
if (wrapWithAssertions) {
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue