Skip to content

Commit

Permalink
Search: Allow to pass a search filter, applying only on the query (an…
Browse files Browse the repository at this point in the history
…d not on facets for example), closes #650.
  • Loading branch information
kimchy committed Jan 26, 2011
1 parent 10ff150 commit 5a4686a
Show file tree
Hide file tree
Showing 12 changed files with 297 additions and 3 deletions.
Expand Up @@ -28,6 +28,7 @@
import org.elasticsearch.client.Client;
import org.elasticsearch.client.action.support.BaseRequestBuilder;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.xcontent.XContentFilterBuilder;
import org.elasticsearch.index.query.xcontent.XContentQueryBuilder;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.builder.SearchSourceBuilder;
Expand Down Expand Up @@ -201,6 +202,33 @@ public SearchRequestBuilder setQuery(byte[] queryBinary) {
return this;
}

/**
* Sets a filter on the query executed that only applies to the search query
* (and not facets for example).
*/
public SearchRequestBuilder setFilter(XContentFilterBuilder filter) {
sourceBuilder().filter(filter);
return this;
}

/**
* Sets a filter on the query executed that only applies to the search query
* (and not facets for example).
*/
public SearchRequestBuilder setFilter(String filter) {
sourceBuilder().filter(filter);
return this;
}

/**
* Sets a filter on the query executed that only applies to the search query
* (and not facets for example).
*/
public SearchRequestBuilder setFilter(byte[] filter) {
sourceBuilder().filter(filter);
return this;
}

/**
* From index to start the search from. Defaults to <tt>0</tt>.
*/
Expand Down
@@ -0,0 +1,64 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.common.lucene.search;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.Scorer;
import org.elasticsearch.common.lucene.docset.DocSet;
import org.elasticsearch.common.lucene.docset.DocSets;

import java.io.IOException;

/**
* @author kimchy (shay.banon)
*/
public class FilteredCollector extends Collector {

private final Collector collector;

private final Filter filter;

private DocSet docSet;

public FilteredCollector(Collector collector, Filter filter) {
this.collector = collector;
this.filter = filter;
}

@Override public void setScorer(Scorer scorer) throws IOException {
collector.setScorer(scorer);
}

@Override public void collect(int doc) throws IOException {
if (docSet.get(doc)) {
collector.collect(doc);
}
}

@Override public void setNextReader(IndexReader reader, int docBase) throws IOException {
docSet = DocSets.convert(reader, filter.getDocIdSet(reader));
}

@Override public boolean acceptsDocsOutOfOrder() {
return collector.acceptsDocsOutOfOrder();
}
}
Expand Up @@ -30,6 +30,7 @@
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.xcontent.XContentFilterBuilder;
import org.elasticsearch.index.query.xcontent.XContentQueryBuilder;
import org.elasticsearch.search.facet.AbstractFacetBuilder;
import org.elasticsearch.search.highlight.HighlightBuilder;
Expand Down Expand Up @@ -69,6 +70,10 @@ public static HighlightBuilder highlight() {

private byte[] queryBinary;

private XContentFilterBuilder filterBuilder;

private byte[] filterBinary;

private int from = -1;

private int size = -1;
Expand Down Expand Up @@ -122,6 +127,33 @@ public SearchSourceBuilder query(String queryString) {
return this;
}

/**
* Sets a filter on the query executed that only applies to the search query
* (and not facets for example).
*/
public SearchSourceBuilder filter(XContentFilterBuilder filter) {
this.filterBuilder = filter;
return this;
}

/**
* Sets a filter on the query executed that only applies to the search query
* (and not facets for example).
*/
public SearchSourceBuilder filter(String filterString) {
this.filterBinary = Unicode.fromStringAsBytes(filterString);
return this;
}

/**
* Sets a filter on the query executed that only applies to the search query
* (and not facets for example).
*/
public SearchSourceBuilder filter(byte[] filter) {
this.filterBinary = filter;
return this;
}

/**
* From index to start the search from. Defaults to <tt>0</tt>.
*/
Expand Down Expand Up @@ -357,6 +389,19 @@ public byte[] buildAsBytes(XContentType contentType) throws SearchSourceBuilderE
}
}

if (filterBuilder != null) {
builder.field("filter");
filterBuilder.toXContent(builder, params);
}

if (filterBinary != null) {
if (XContentFactory.xContentType(queryBinary) == builder.contentType()) {
builder.rawField("filter", filterBinary);
} else {
builder.field("filter_binary", queryBinary);
}
}

if (explain != null) {
builder.field("explain", explain);
}
Expand Down
Expand Up @@ -7,7 +7,7 @@
* "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
* 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
Expand Down
Expand Up @@ -7,7 +7,7 @@
* "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
* 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
Expand Down
Expand Up @@ -24,6 +24,7 @@
import org.elasticsearch.common.collect.Maps;
import org.elasticsearch.common.lucene.MultiCollector;
import org.elasticsearch.common.lucene.search.ExtendedIndexSearcher;
import org.elasticsearch.common.lucene.search.FilteredCollector;
import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.search.dfs.CachedDfSource;

Expand Down Expand Up @@ -116,6 +117,11 @@ public void processedScope() {
}

@Override public void search(Weight weight, Filter filter, Collector collector) throws IOException {
if (searchContext.parsedFilter() != null) {
// this will only get applied to the actual search collector and not
// to any scoped collectors
collector = new FilteredCollector(collector, searchContext.parsedFilter());
}
if (searchContext.timeout() != null) {
collector = new TimeLimitingCollector(collector, searchContext.timeout().millis());
}
Expand Down
Expand Up @@ -19,6 +19,7 @@

package org.elasticsearch.search.internal;

import org.apache.lucene.search.Filter;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.elasticsearch.ElasticSearchException;
Expand Down Expand Up @@ -115,6 +116,8 @@ public static SearchContext current() {

private Query query;

private Filter filter;

private int[] docIdsToLoad;

private int docsIdsToLoadFrom;
Expand Down Expand Up @@ -291,6 +294,15 @@ public Sort sort() {
return this.sort;
}

public SearchContext parsedFilter(Filter filter) {
this.filter = filter;
return this;
}

public Filter parsedFilter() {
return this.filter;
}

public String queryParserName() {
return queryParserName;
}
Expand Down
@@ -0,0 +1,43 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.search.query;

import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.xcontent.XContentIndexQueryParser;
import org.elasticsearch.search.SearchParseElement;
import org.elasticsearch.search.internal.SearchContext;

/**
* @author kimchy (shay.banon)
*/
public class FilterBinaryParseElement implements SearchParseElement {

@Override public void parse(XContentParser parser, SearchContext context) throws Exception {
XContentIndexQueryParser indexQueryParser = (XContentIndexQueryParser) context.queryParser();
byte[] filterSource = parser.binaryValue();
XContentParser fSourceParser = XContentFactory.xContent(filterSource).createParser(filterSource);
try {
context.parsedFilter(indexQueryParser.parseInnerFilter(fSourceParser));
} finally {
fSourceParser.close();
}
}
}
@@ -0,0 +1,36 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.search.query;

import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.xcontent.XContentIndexQueryParser;
import org.elasticsearch.search.SearchParseElement;
import org.elasticsearch.search.internal.SearchContext;

/**
* @author kimchy (shay.banon)
*/
public class FilterParseElement implements SearchParseElement {

@Override public void parse(XContentParser parser, SearchContext context) throws Exception {
XContentIndexQueryParser indexQueryParser = (XContentIndexQueryParser) context.queryParser();
context.parsedFilter(indexQueryParser.parseInnerFilter(parser));
}
}
Expand Up @@ -34,6 +34,10 @@ public class QueryBinaryParseElement implements SearchParseElement {
XContentIndexQueryParser indexQueryParser = (XContentIndexQueryParser) context.queryParser();
byte[] querySource = parser.binaryValue();
XContentParser qSourceParser = XContentFactory.xContent(querySource).createParser(querySource);
context.parsedQuery(indexQueryParser.parse(qSourceParser));
try {
context.parsedQuery(indexQueryParser.parse(qSourceParser));
} finally {
qSourceParser.close();
}
}
}
Expand Up @@ -57,6 +57,9 @@ public class QueryPhase implements SearchPhase {
.put("query", new QueryParseElement())
.put("queryBinary", new QueryBinaryParseElement())
.put("query_binary", new QueryBinaryParseElement())
.put("filter", new FilterParseElement())
.put("filterBinary", new FilterBinaryParseElement())
.put("filter_binary", new FilterBinaryParseElement())
.put("sort", new SortParseElement())
.putAll(facetPhase.parseElements());
return parseElements.build();
Expand All @@ -73,6 +76,7 @@ public class QueryPhase implements SearchPhase {
}

public void execute(SearchContext searchContext) throws QueryPhaseExecutionException {
// set the filter on the searcher
if (searchContext.parsedQuery().scopePhases().length > 0) {
// we have scoped queries, refresh the id cache
try {
Expand Down

0 comments on commit 5a4686a

Please sign in to comment.