percolator: Take filters from index aliases into account when selecting queries to run on a document.
The filter from an indexed alias is as if you would filter on the metadata of a percolator query, but then the filter is defined in the index alias instead of the percolate request. Closes #6241
This commit is contained in:
parent
4393939f5e
commit
ef3cb2d436
|
@ -90,6 +90,7 @@ public class PercolateContext extends SearchContext {
|
||||||
private final ScriptService scriptService;
|
private final ScriptService scriptService;
|
||||||
private final ConcurrentMap<BytesRef, Query> percolateQueries;
|
private final ConcurrentMap<BytesRef, Query> percolateQueries;
|
||||||
private final int numberOfShards;
|
private final int numberOfShards;
|
||||||
|
private final Filter aliasFilter;
|
||||||
private String[] types;
|
private String[] types;
|
||||||
|
|
||||||
private Engine.Searcher docSearcher;
|
private Engine.Searcher docSearcher;
|
||||||
|
@ -109,7 +110,7 @@ public class PercolateContext extends SearchContext {
|
||||||
|
|
||||||
public PercolateContext(PercolateShardRequest request, SearchShardTarget searchShardTarget, IndexShard indexShard,
|
public PercolateContext(PercolateShardRequest request, SearchShardTarget searchShardTarget, IndexShard indexShard,
|
||||||
IndexService indexService, PageCacheRecycler pageCacheRecycler,
|
IndexService indexService, PageCacheRecycler pageCacheRecycler,
|
||||||
BigArrays bigArrays, ScriptService scriptService) {
|
BigArrays bigArrays, ScriptService scriptService, Filter aliasFilter) {
|
||||||
this.indexShard = indexShard;
|
this.indexShard = indexShard;
|
||||||
this.indexService = indexService;
|
this.indexService = indexService;
|
||||||
this.fieldDataService = indexService.fieldData();
|
this.fieldDataService = indexService.fieldData();
|
||||||
|
@ -123,6 +124,7 @@ public class PercolateContext extends SearchContext {
|
||||||
this.searcher = new ContextIndexSearcher(this, engineSearcher);
|
this.searcher = new ContextIndexSearcher(this, engineSearcher);
|
||||||
this.scriptService = scriptService;
|
this.scriptService = scriptService;
|
||||||
this.numberOfShards = request.getNumberOfShards();
|
this.numberOfShards = request.getNumberOfShards();
|
||||||
|
this.aliasFilter = aliasFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IndexSearcher docSearcher() {
|
public IndexSearcher docSearcher() {
|
||||||
|
@ -277,7 +279,7 @@ public class PercolateContext extends SearchContext {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Filter searchFilter(String[] types) {
|
public Filter searchFilter(String[] types) {
|
||||||
throw new UnsupportedOperationException();
|
return aliasFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -509,7 +511,7 @@ public class PercolateContext extends SearchContext {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Filter aliasFilter() {
|
public Filter aliasFilter() {
|
||||||
throw new UnsupportedOperationException();
|
return aliasFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -23,13 +23,7 @@ import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.index.ReaderUtil;
|
import org.apache.lucene.index.ReaderUtil;
|
||||||
import org.apache.lucene.index.memory.ExtendedMemoryIndex;
|
import org.apache.lucene.index.memory.ExtendedMemoryIndex;
|
||||||
import org.apache.lucene.index.memory.MemoryIndex;
|
import org.apache.lucene.index.memory.MemoryIndex;
|
||||||
import org.apache.lucene.search.ConstantScoreQuery;
|
import org.apache.lucene.search.*;
|
||||||
import org.apache.lucene.search.Filter;
|
|
||||||
import org.apache.lucene.search.FilteredQuery;
|
|
||||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
|
||||||
import org.apache.lucene.search.Query;
|
|
||||||
import org.apache.lucene.search.ScoreDoc;
|
|
||||||
import org.apache.lucene.search.TopDocs;
|
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.apache.lucene.util.CloseableThreadLocal;
|
import org.apache.lucene.util.CloseableThreadLocal;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
|
@ -48,6 +42,7 @@ import org.elasticsearch.common.component.AbstractComponent;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||||
import org.elasticsearch.common.lucene.Lucene;
|
import org.elasticsearch.common.lucene.Lucene;
|
||||||
|
import org.elasticsearch.common.lucene.search.XBooleanFilter;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.text.BytesText;
|
import org.elasticsearch.common.text.BytesText;
|
||||||
import org.elasticsearch.common.text.StringText;
|
import org.elasticsearch.common.text.StringText;
|
||||||
|
@ -63,22 +58,14 @@ import org.elasticsearch.index.IndexService;
|
||||||
import org.elasticsearch.index.engine.Engine;
|
import org.elasticsearch.index.engine.Engine;
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
||||||
import org.elasticsearch.index.mapper.DocumentMapper;
|
import org.elasticsearch.index.mapper.*;
|
||||||
import org.elasticsearch.index.mapper.FieldMapper;
|
|
||||||
import org.elasticsearch.index.mapper.MapperService;
|
|
||||||
import org.elasticsearch.index.mapper.ParsedDocument;
|
|
||||||
import org.elasticsearch.index.mapper.Uid;
|
|
||||||
import org.elasticsearch.index.mapper.internal.IdFieldMapper;
|
|
||||||
import org.elasticsearch.index.mapper.internal.UidFieldMapper;
|
import org.elasticsearch.index.mapper.internal.UidFieldMapper;
|
||||||
import org.elasticsearch.index.percolator.stats.ShardPercolateService;
|
import org.elasticsearch.index.percolator.stats.ShardPercolateService;
|
||||||
import org.elasticsearch.index.query.ParsedQuery;
|
import org.elasticsearch.index.query.ParsedQuery;
|
||||||
import org.elasticsearch.index.search.nested.NonNestedDocsFilter;
|
import org.elasticsearch.index.search.nested.NonNestedDocsFilter;
|
||||||
import org.elasticsearch.index.shard.IndexShard;
|
import org.elasticsearch.index.shard.IndexShard;
|
||||||
import org.elasticsearch.indices.IndicesService;
|
import org.elasticsearch.indices.IndicesService;
|
||||||
import org.elasticsearch.percolator.QueryCollector.Count;
|
import org.elasticsearch.percolator.QueryCollector.*;
|
||||||
import org.elasticsearch.percolator.QueryCollector.Match;
|
|
||||||
import org.elasticsearch.percolator.QueryCollector.MatchAndScore;
|
|
||||||
import org.elasticsearch.percolator.QueryCollector.MatchAndSort;
|
|
||||||
import org.elasticsearch.script.ScriptService;
|
import org.elasticsearch.script.ScriptService;
|
||||||
import org.elasticsearch.search.SearchParseElement;
|
import org.elasticsearch.search.SearchParseElement;
|
||||||
import org.elasticsearch.search.SearchShardTarget;
|
import org.elasticsearch.search.SearchShardTarget;
|
||||||
|
@ -96,9 +83,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.elasticsearch.index.mapper.SourceToParse.source;
|
import static org.elasticsearch.index.mapper.SourceToParse.source;
|
||||||
import static org.elasticsearch.percolator.QueryCollector.count;
|
import static org.elasticsearch.percolator.QueryCollector.*;
|
||||||
import static org.elasticsearch.percolator.QueryCollector.match;
|
|
||||||
import static org.elasticsearch.percolator.QueryCollector.matchAndScore;
|
|
||||||
|
|
||||||
public class PercolatorService extends AbstractComponent {
|
public class PercolatorService extends AbstractComponent {
|
||||||
|
|
||||||
|
@ -174,9 +159,15 @@ public class PercolatorService extends AbstractComponent {
|
||||||
shardPercolateService.prePercolate();
|
shardPercolateService.prePercolate();
|
||||||
long startTime = System.nanoTime();
|
long startTime = System.nanoTime();
|
||||||
|
|
||||||
|
String[] filteringAliases = clusterService.state().getMetaData().filteringAliases(
|
||||||
|
indexShard.shardId().index().name(),
|
||||||
|
request.indices()
|
||||||
|
);
|
||||||
|
Filter aliasFilter = percolateIndexService.aliasesService().aliasFilter(filteringAliases);
|
||||||
|
|
||||||
SearchShardTarget searchShardTarget = new SearchShardTarget(clusterService.localNode().id(), request.shardId().getIndex(), request.shardId().id());
|
SearchShardTarget searchShardTarget = new SearchShardTarget(clusterService.localNode().id(), request.shardId().getIndex(), request.shardId().id());
|
||||||
final PercolateContext context = new PercolateContext(
|
final PercolateContext context = new PercolateContext(
|
||||||
request, searchShardTarget, indexShard, percolateIndexService, pageCacheRecycler, bigArrays, scriptService
|
request, searchShardTarget, indexShard, percolateIndexService, pageCacheRecycler, bigArrays, scriptService, aliasFilter
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
ParsedDocument parsedDocument = parseRequest(percolateIndexService, request, context);
|
ParsedDocument parsedDocument = parseRequest(percolateIndexService, request, context);
|
||||||
|
@ -190,7 +181,7 @@ public class PercolatorService extends AbstractComponent {
|
||||||
throw new ElasticsearchIllegalArgumentException("Nothing to percolate");
|
throw new ElasticsearchIllegalArgumentException("Nothing to percolate");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.percolateQuery() == null && (context.trackScores() || context.doSort || context.aggregations() != null)) {
|
if (context.percolateQuery() == null && (context.trackScores() || context.doSort || context.aggregations() != null) || context.aliasFilter() != null) {
|
||||||
context.percolateQuery(new MatchAllDocsQuery());
|
context.percolateQuery(new MatchAllDocsQuery());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -779,8 +770,19 @@ public class PercolatorService extends AbstractComponent {
|
||||||
|
|
||||||
private void queryBasedPercolating(Engine.Searcher percolatorSearcher, PercolateContext context, QueryCollector percolateCollector) throws IOException {
|
private void queryBasedPercolating(Engine.Searcher percolatorSearcher, PercolateContext context, QueryCollector percolateCollector) throws IOException {
|
||||||
Filter percolatorTypeFilter = context.indexService().mapperService().documentMapper(TYPE_NAME).typeFilter();
|
Filter percolatorTypeFilter = context.indexService().mapperService().documentMapper(TYPE_NAME).typeFilter();
|
||||||
percolatorTypeFilter = context.indexService().cache().filter().cache(percolatorTypeFilter, null, context.indexService().queryParserService().autoFilterCachePolicy());
|
percolatorTypeFilter = context.indexService().cache().filter().cache(percolatorTypeFilter, null, context.queryParserService().autoFilterCachePolicy());
|
||||||
FilteredQuery query = new FilteredQuery(context.percolateQuery(), percolatorTypeFilter);
|
|
||||||
|
final Filter filter;
|
||||||
|
if (context.aliasFilter() != null) {
|
||||||
|
XBooleanFilter booleanFilter = new XBooleanFilter();
|
||||||
|
booleanFilter.add(context.aliasFilter(), BooleanClause.Occur.MUST);
|
||||||
|
booleanFilter.add(percolatorTypeFilter, BooleanClause.Occur.MUST);
|
||||||
|
filter = booleanFilter;
|
||||||
|
} else {
|
||||||
|
filter = percolatorTypeFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
FilteredQuery query = new FilteredQuery(context.percolateQuery(), filter);
|
||||||
percolatorSearcher.searcher().search(query, percolateCollector);
|
percolatorSearcher.searcher().search(query, percolateCollector);
|
||||||
percolateCollector.aggregatorCollector.postCollection();
|
percolateCollector.aggregatorCollector.postCollection();
|
||||||
if (context.aggregations() != null) {
|
if (context.aggregations() != null) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import com.google.common.base.Predicate;
|
||||||
import org.elasticsearch.action.ShardOperationFailedException;
|
import org.elasticsearch.action.ShardOperationFailedException;
|
||||||
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
|
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
|
||||||
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
|
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
|
||||||
|
import org.elasticsearch.action.admin.indices.alias.Alias;
|
||||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
|
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
|
||||||
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
|
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
|
||||||
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
|
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
|
||||||
|
@ -50,7 +51,6 @@ import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.search.highlight.HighlightBuilder;
|
import org.elasticsearch.search.highlight.HighlightBuilder;
|
||||||
import org.elasticsearch.search.sort.SortBuilders;
|
import org.elasticsearch.search.sort.SortBuilders;
|
||||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||||
import org.elasticsearch.test.junit.annotations.TestLogging;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -950,7 +950,84 @@ public class PercolatorTests extends ElasticsearchIntegrationTest {
|
||||||
for (PercolateResponse.Match match : response) {
|
for (PercolateResponse.Match match : response) {
|
||||||
assertThat(match.getIndex().string(), equalTo("test2"));
|
assertThat(match.getIndex().string(), equalTo("test2"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPercolateWithAliasFilter() throws Exception {
|
||||||
|
assertAcked(prepareCreate("my-index")
|
||||||
|
.addMapping(PercolatorService.TYPE_NAME, "a", "type=string,index=not_analyzed")
|
||||||
|
.addAlias(new Alias("a").filter(FilterBuilders.termFilter("a", "a")))
|
||||||
|
.addAlias(new Alias("b").filter(FilterBuilders.termFilter("a", "b")))
|
||||||
|
.addAlias(new Alias("c").filter(FilterBuilders.termFilter("a", "c")))
|
||||||
|
);
|
||||||
|
client().prepareIndex("my-index", PercolatorService.TYPE_NAME, "1")
|
||||||
|
.setSource(jsonBuilder().startObject().field("query", matchAllQuery()).field("a", "a").endObject())
|
||||||
|
.get();
|
||||||
|
client().prepareIndex("my-index", PercolatorService.TYPE_NAME, "2")
|
||||||
|
.setSource(jsonBuilder().startObject().field("query", matchAllQuery()).field("a", "b").endObject())
|
||||||
|
.get();
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
// Specifying only the document to percolate and no filter, sorting or aggs, the queries are retrieved from
|
||||||
|
// memory directly. Otherwise we need to retrieve those queries from lucene to be able to execute filters,
|
||||||
|
// aggregations and sorting on top of them. So this test a different code execution path.
|
||||||
|
PercolateResponse response = client().preparePercolate()
|
||||||
|
.setIndices("a")
|
||||||
|
.setDocumentType("my-type")
|
||||||
|
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
|
||||||
|
.get();
|
||||||
|
assertNoFailures(response);
|
||||||
|
assertThat(response.getCount(), equalTo(1l));
|
||||||
|
assertThat(response.getMatches()[0].getId().string(), equalTo("1"));
|
||||||
|
|
||||||
|
response = client().preparePercolate()
|
||||||
|
.setIndices("b")
|
||||||
|
.setDocumentType("my-type")
|
||||||
|
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
|
||||||
|
.get();
|
||||||
|
assertNoFailures(response);
|
||||||
|
assertThat(response.getCount(), equalTo(1l));
|
||||||
|
assertThat(response.getMatches()[0].getId().string(), equalTo("2"));
|
||||||
|
|
||||||
|
|
||||||
|
response = client().preparePercolate()
|
||||||
|
.setIndices("c")
|
||||||
|
.setDocumentType("my-type")
|
||||||
|
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
|
||||||
|
.get();
|
||||||
|
assertNoFailures(response);
|
||||||
|
assertThat(response.getCount(), equalTo(0l));
|
||||||
|
|
||||||
|
// Testing that the alias filter and the filter specified while percolating are both taken into account.
|
||||||
|
response = client().preparePercolate()
|
||||||
|
.setIndices("a")
|
||||||
|
.setDocumentType("my-type")
|
||||||
|
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
|
||||||
|
.setPercolateFilter(FilterBuilders.matchAllFilter())
|
||||||
|
.get();
|
||||||
|
assertNoFailures(response);
|
||||||
|
assertThat(response.getCount(), equalTo(1l));
|
||||||
|
assertThat(response.getMatches()[0].getId().string(), equalTo("1"));
|
||||||
|
|
||||||
|
response = client().preparePercolate()
|
||||||
|
.setIndices("b")
|
||||||
|
.setDocumentType("my-type")
|
||||||
|
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
|
||||||
|
.setPercolateFilter(FilterBuilders.matchAllFilter())
|
||||||
|
.get();
|
||||||
|
assertNoFailures(response);
|
||||||
|
assertThat(response.getCount(), equalTo(1l));
|
||||||
|
assertThat(response.getMatches()[0].getId().string(), equalTo("2"));
|
||||||
|
|
||||||
|
|
||||||
|
response = client().preparePercolate()
|
||||||
|
.setIndices("c")
|
||||||
|
.setDocumentType("my-type")
|
||||||
|
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
|
||||||
|
.setPercolateFilter(FilterBuilders.matchAllFilter())
|
||||||
|
.get();
|
||||||
|
assertNoFailures(response);
|
||||||
|
assertThat(response.getCount(), equalTo(0l));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue