This change adds a wrapper for IndexSearcher that makes IndexSearcher#search(List, Weight, Collector) visible by sub-classes. The wrapper is used by the ContextIndexSearcher to call this protected method on a searcher created by a plugin. This ensures that an override of the protected method in an IndexSearcherWrapper plugin is called when a search is executed. Closes #30758
This commit is contained in:
parent
8a3f87bdcd
commit
eb540125ea
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.lucene.search;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper for {@link IndexSearcher} that makes {@link IndexSearcher#search(List, Weight, Collector)}
|
||||||
|
* visible by sub-classes.
|
||||||
|
*/
|
||||||
|
public class XIndexSearcher extends IndexSearcher {
|
||||||
|
private final IndexSearcher in;
|
||||||
|
|
||||||
|
public XIndexSearcher(IndexSearcher in) {
|
||||||
|
super(in.getIndexReader());
|
||||||
|
this.in = in;
|
||||||
|
setSimilarity(in.getSimilarity());
|
||||||
|
setQueryCache(in.getQueryCache());
|
||||||
|
setQueryCachingPolicy(in.getQueryCachingPolicy());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void search(List<LeafReaderContext> leaves, Weight weight, Collector collector) throws IOException {
|
||||||
|
in.search(leaves, weight, collector);
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,6 +35,7 @@ import org.apache.lucene.search.ScoreMode;
|
||||||
import org.apache.lucene.search.Scorer;
|
import org.apache.lucene.search.Scorer;
|
||||||
import org.apache.lucene.search.TermStatistics;
|
import org.apache.lucene.search.TermStatistics;
|
||||||
import org.apache.lucene.search.Weight;
|
import org.apache.lucene.search.Weight;
|
||||||
|
import org.apache.lucene.search.XIndexSearcher;
|
||||||
import org.elasticsearch.common.lease.Releasable;
|
import org.elasticsearch.common.lease.Releasable;
|
||||||
import org.elasticsearch.index.engine.Engine;
|
import org.elasticsearch.index.engine.Engine;
|
||||||
import org.elasticsearch.search.dfs.AggregatedDfs;
|
import org.elasticsearch.search.dfs.AggregatedDfs;
|
||||||
|
@ -56,7 +57,7 @@ public class ContextIndexSearcher extends IndexSearcher implements Releasable {
|
||||||
/** The wrapped {@link IndexSearcher}. The reason why we sometimes prefer delegating to this searcher instead of {@code super} is that
|
/** The wrapped {@link IndexSearcher}. The reason why we sometimes prefer delegating to this searcher instead of {@code super} is that
|
||||||
* this instance may have more assertions, for example if it comes from MockInternalEngine which wraps the IndexSearcher into an
|
* this instance may have more assertions, for example if it comes from MockInternalEngine which wraps the IndexSearcher into an
|
||||||
* AssertingIndexSearcher. */
|
* AssertingIndexSearcher. */
|
||||||
private final IndexSearcher in;
|
private final XIndexSearcher in;
|
||||||
|
|
||||||
private AggregatedDfs aggregatedDfs;
|
private AggregatedDfs aggregatedDfs;
|
||||||
|
|
||||||
|
@ -67,11 +68,10 @@ public class ContextIndexSearcher extends IndexSearcher implements Releasable {
|
||||||
|
|
||||||
private Runnable checkCancelled;
|
private Runnable checkCancelled;
|
||||||
|
|
||||||
public ContextIndexSearcher(Engine.Searcher searcher,
|
public ContextIndexSearcher(Engine.Searcher searcher, QueryCache queryCache, QueryCachingPolicy queryCachingPolicy) {
|
||||||
QueryCache queryCache, QueryCachingPolicy queryCachingPolicy) {
|
|
||||||
super(searcher.reader());
|
super(searcher.reader());
|
||||||
in = searcher.searcher();
|
|
||||||
engineSearcher = searcher;
|
engineSearcher = searcher;
|
||||||
|
in = new XIndexSearcher(searcher.searcher());
|
||||||
setSimilarity(searcher.searcher().getSimilarity());
|
setSimilarity(searcher.searcher().getSimilarity());
|
||||||
setQueryCache(queryCache);
|
setQueryCache(queryCache);
|
||||||
setQueryCachingPolicy(queryCachingPolicy);
|
setQueryCachingPolicy(queryCachingPolicy);
|
||||||
|
@ -174,7 +174,7 @@ public class ContextIndexSearcher extends IndexSearcher implements Releasable {
|
||||||
} else {
|
} else {
|
||||||
cancellableWeight = weight;
|
cancellableWeight = weight;
|
||||||
}
|
}
|
||||||
super.search(leaves, cancellableWeight, collector);
|
in.search(leaves, cancellableWeight, collector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -28,23 +28,31 @@ import org.apache.lucene.index.FilterDirectoryReader;
|
||||||
import org.apache.lucene.index.IndexWriter;
|
import org.apache.lucene.index.IndexWriter;
|
||||||
import org.apache.lucene.index.IndexWriterConfig;
|
import org.apache.lucene.index.IndexWriterConfig;
|
||||||
import org.apache.lucene.index.LeafReader;
|
import org.apache.lucene.index.LeafReader;
|
||||||
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
|
import org.apache.lucene.search.Collector;
|
||||||
import org.apache.lucene.search.IndexSearcher;
|
import org.apache.lucene.search.IndexSearcher;
|
||||||
import org.apache.lucene.search.TermQuery;
|
import org.apache.lucene.search.TermQuery;
|
||||||
import org.apache.lucene.search.TopDocs;
|
import org.apache.lucene.search.TopDocs;
|
||||||
|
import org.apache.lucene.search.TotalHitCountCollector;
|
||||||
|
import org.apache.lucene.search.Weight;
|
||||||
import org.apache.lucene.store.Directory;
|
import org.apache.lucene.store.Directory;
|
||||||
import org.elasticsearch.core.internal.io.IOUtils;
|
import org.elasticsearch.core.internal.io.IOUtils;
|
||||||
import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
|
import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
|
||||||
import org.elasticsearch.index.engine.Engine;
|
import org.elasticsearch.index.engine.Engine;
|
||||||
import org.elasticsearch.index.engine.EngineException;
|
import org.elasticsearch.index.engine.EngineException;
|
||||||
|
import org.elasticsearch.search.internal.ContextIndexSearcher;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
public class IndexSearcherWrapperTests extends ESTestCase {
|
public class IndexSearcherWrapperTests extends ESTestCase {
|
||||||
|
|
||||||
public void testReaderCloseListenerIsCalled() throws IOException {
|
public void testReaderCloseListenerIsCalled() throws IOException {
|
||||||
|
@ -159,6 +167,50 @@ public class IndexSearcherWrapperTests extends ESTestCase {
|
||||||
IOUtils.close(writer, dir);
|
IOUtils.close(writer, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testWrapVisibility() throws IOException {
|
||||||
|
Directory dir = newDirectory();
|
||||||
|
IndexWriterConfig iwc = newIndexWriterConfig();
|
||||||
|
IndexWriter writer = new IndexWriter(dir, iwc);
|
||||||
|
Document doc = new Document();
|
||||||
|
doc.add(new StringField("id", "1", random().nextBoolean() ? Field.Store.YES : Field.Store.NO));
|
||||||
|
doc.add(new TextField("field", "doc", random().nextBoolean() ? Field.Store.YES : Field.Store.NO));
|
||||||
|
writer.addDocument(doc);
|
||||||
|
DirectoryReader open = ElasticsearchDirectoryReader.wrap(DirectoryReader.open(writer), new ShardId("foo", "_na_", 1));
|
||||||
|
IndexSearcher searcher = new IndexSearcher(open);
|
||||||
|
assertEquals(1, searcher.search(new TermQuery(new Term("field", "doc")), 1).totalHits.value);
|
||||||
|
IndexSearcherWrapper wrapper = new IndexSearcherWrapper() {
|
||||||
|
@Override
|
||||||
|
public DirectoryReader wrap(DirectoryReader reader) throws IOException {
|
||||||
|
return reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IndexSearcher wrap(IndexSearcher searcher) throws EngineException {
|
||||||
|
return new IndexSearcher(searcher.getIndexReader()) {
|
||||||
|
@Override
|
||||||
|
protected void search(List<LeafReaderContext> leaves, Weight weight, Collector collector) throws IOException {
|
||||||
|
throw new IllegalStateException("boum");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
final AtomicBoolean closeCalled = new AtomicBoolean(false);
|
||||||
|
final Engine.Searcher wrap = wrapper.wrap(new Engine.Searcher("foo", searcher, () -> closeCalled.set(true)));
|
||||||
|
assertEquals(1, wrap.reader().getRefCount());
|
||||||
|
ContextIndexSearcher contextSearcher = new ContextIndexSearcher(wrap, wrap.searcher().getQueryCache(),
|
||||||
|
wrap.searcher().getQueryCachingPolicy());
|
||||||
|
IllegalStateException exc = expectThrows(IllegalStateException.class,
|
||||||
|
() -> contextSearcher.search(new TermQuery(new Term("field", "doc")), new TotalHitCountCollector()));
|
||||||
|
assertThat(exc.getMessage(), equalTo("boum"));
|
||||||
|
wrap.close();
|
||||||
|
assertFalse("wrapped reader is closed", wrap.reader().tryIncRef());
|
||||||
|
assertTrue(closeCalled.get());
|
||||||
|
|
||||||
|
IOUtils.close(open, writer, dir);
|
||||||
|
assertEquals(0, open.getRefCount());
|
||||||
|
}
|
||||||
|
|
||||||
private static class FieldMaskingReader extends FilterDirectoryReader {
|
private static class FieldMaskingReader extends FilterDirectoryReader {
|
||||||
private final String field;
|
private final String field;
|
||||||
private final AtomicInteger closeCalls;
|
private final AtomicInteger closeCalls;
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.apache.lucene.search.QueryCache;
|
||||||
import org.apache.lucene.search.QueryCachingPolicy;
|
import org.apache.lucene.search.QueryCachingPolicy;
|
||||||
import org.apache.lucene.search.ScoreMode;
|
import org.apache.lucene.search.ScoreMode;
|
||||||
import org.apache.lucene.search.Weight;
|
import org.apache.lucene.search.Weight;
|
||||||
|
import org.apache.lucene.search.XIndexSearcher;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
import org.elasticsearch.common.lease.Releasable;
|
import org.elasticsearch.common.lease.Releasable;
|
||||||
|
@ -447,7 +448,16 @@ public abstract class AggregatorTestCase extends ESTestCase {
|
||||||
*/
|
*/
|
||||||
protected static IndexSearcher newIndexSearcher(IndexReader indexReader) {
|
protected static IndexSearcher newIndexSearcher(IndexReader indexReader) {
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
return new AssertingIndexSearcher(random(), indexReader);
|
final IndexSearcher delegate = new IndexSearcher(indexReader);
|
||||||
|
final XIndexSearcher wrappedSearcher = new XIndexSearcher(delegate);
|
||||||
|
// this executes basic query checks and asserts that weights are normalized only once etc.
|
||||||
|
return new AssertingIndexSearcher(random(), indexReader) {
|
||||||
|
@Override
|
||||||
|
protected void search(List<LeafReaderContext> leaves, Weight weight, Collector collector) throws IOException {
|
||||||
|
// we cannot use the asserting searcher because the weight is created by the ContextIndexSearcher
|
||||||
|
wrappedSearcher.search(leaves, weight, collector);
|
||||||
|
}
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return new IndexSearcher(indexReader);
|
return new IndexSearcher(indexReader);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,14 @@ import org.apache.lucene.index.AssertingDirectoryReader;
|
||||||
import org.apache.lucene.index.DirectoryReader;
|
import org.apache.lucene.index.DirectoryReader;
|
||||||
import org.apache.lucene.index.FilterDirectoryReader;
|
import org.apache.lucene.index.FilterDirectoryReader;
|
||||||
import org.apache.lucene.index.IndexReader;
|
import org.apache.lucene.index.IndexReader;
|
||||||
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.search.AssertingIndexSearcher;
|
import org.apache.lucene.search.AssertingIndexSearcher;
|
||||||
|
import org.apache.lucene.search.Collector;
|
||||||
|
import org.apache.lucene.search.IndexSearcher;
|
||||||
import org.apache.lucene.search.QueryCache;
|
import org.apache.lucene.search.QueryCache;
|
||||||
import org.apache.lucene.search.QueryCachingPolicy;
|
import org.apache.lucene.search.QueryCachingPolicy;
|
||||||
|
import org.apache.lucene.search.Weight;
|
||||||
|
import org.apache.lucene.search.XIndexSearcher;
|
||||||
import org.apache.lucene.util.LuceneTestCase;
|
import org.apache.lucene.util.LuceneTestCase;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.common.settings.Setting;
|
import org.elasticsearch.common.settings.Setting;
|
||||||
|
@ -42,6 +47,7 @@ import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
@ -145,8 +151,19 @@ public final class MockEngineSupport {
|
||||||
if (reader instanceof DirectoryReader && mockContext.wrapReader) {
|
if (reader instanceof DirectoryReader && mockContext.wrapReader) {
|
||||||
wrappedReader = wrapReader((DirectoryReader) reader);
|
wrappedReader = wrapReader((DirectoryReader) reader);
|
||||||
}
|
}
|
||||||
|
final IndexSearcher delegate = new IndexSearcher(wrappedReader);
|
||||||
|
delegate.setSimilarity(searcher.searcher().getSimilarity());
|
||||||
|
delegate.setQueryCache(filterCache);
|
||||||
|
delegate.setQueryCachingPolicy(filterCachingPolicy);
|
||||||
|
final XIndexSearcher wrappedSearcher = new XIndexSearcher(delegate);
|
||||||
// this executes basic query checks and asserts that weights are normalized only once etc.
|
// this executes basic query checks and asserts that weights are normalized only once etc.
|
||||||
final AssertingIndexSearcher assertingIndexSearcher = new AssertingIndexSearcher(mockContext.random, wrappedReader);
|
final AssertingIndexSearcher assertingIndexSearcher = new AssertingIndexSearcher(mockContext.random, wrappedReader) {
|
||||||
|
@Override
|
||||||
|
protected void search(List<LeafReaderContext> leaves, Weight weight, Collector collector) throws IOException {
|
||||||
|
// we cannot use the asserting searcher because the weight is created by the ContextIndexSearcher
|
||||||
|
wrappedSearcher.search(leaves, weight, collector);
|
||||||
|
}
|
||||||
|
};
|
||||||
assertingIndexSearcher.setSimilarity(searcher.searcher().getSimilarity());
|
assertingIndexSearcher.setSimilarity(searcher.searcher().getSimilarity());
|
||||||
assertingIndexSearcher.setQueryCache(filterCache);
|
assertingIndexSearcher.setQueryCache(filterCache);
|
||||||
assertingIndexSearcher.setQueryCachingPolicy(filterCachingPolicy);
|
assertingIndexSearcher.setQueryCachingPolicy(filterCachingPolicy);
|
||||||
|
|
Loading…
Reference in New Issue