Search Facets: Facets to allow to define filters on them, closes #217.

This commit is contained in:
kimchy 2010-06-08 22:30:21 +03:00
parent 6257b78243
commit 5ca050ffcb
13 changed files with 256 additions and 37 deletions

View File

@ -28,6 +28,7 @@ import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.support.PlainListenableActionFuture; import org.elasticsearch.action.support.PlainListenableActionFuture;
import org.elasticsearch.client.internal.InternalClient; import org.elasticsearch.client.internal.InternalClient;
import org.elasticsearch.index.query.xcontent.XContentFilterBuilder;
import org.elasticsearch.index.query.xcontent.XContentQueryBuilder; import org.elasticsearch.index.query.xcontent.XContentQueryBuilder;
import org.elasticsearch.search.Scroll; import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder;
@ -36,6 +37,8 @@ import org.elasticsearch.search.builder.SearchSourceHighlightBuilder;
import org.elasticsearch.search.facets.histogram.HistogramFacet; import org.elasticsearch.search.facets.histogram.HistogramFacet;
import org.elasticsearch.util.TimeValue; import org.elasticsearch.util.TimeValue;
import javax.annotation.Nullable;
/** /**
* A search action request builder. * A search action request builder.
* *
@ -261,6 +264,11 @@ public class SearchRequestBuilder {
return this; return this;
} }
public SearchRequestBuilder addFacetQuery(String name, XContentQueryBuilder query, @Nullable XContentFilterBuilder filter) {
facetsBuilder().queryFacet(name, query, filter);
return this;
}
/** /**
* Adds a query facet (which results in a count facet returned) with an option to * Adds a query facet (which results in a count facet returned) with an option to
* be global on the index or bounded by the search query. * be global on the index or bounded by the search query.
@ -274,6 +282,11 @@ public class SearchRequestBuilder {
return this; return this;
} }
public SearchRequestBuilder addFacetGlobalQuery(String name, XContentQueryBuilder query, @Nullable XContentFilterBuilder filter) {
facetsBuilder().queryFacetGlobal(name, query, filter);
return this;
}
/** /**
* Adds a term facet for the provided field name. * Adds a term facet for the provided field name.
* *
@ -287,6 +300,11 @@ public class SearchRequestBuilder {
return this; return this;
} }
public SearchRequestBuilder addFacetTerms(String name, String fieldName, int size, @Nullable XContentFilterBuilder filter) {
facetsBuilder().termsFacet(name, fieldName, size, filter);
return this;
}
/** /**
* Adds a <b>global</b> term facet for the provided field name. * Adds a <b>global</b> term facet for the provided field name.
* *
@ -300,6 +318,11 @@ public class SearchRequestBuilder {
return this; return this;
} }
public SearchRequestBuilder addFacetGlobalTerms(String name, String fieldName, int size, @Nullable XContentFilterBuilder filter) {
facetsBuilder().termsFacetGlobal(name, fieldName, size, filter);
return this;
}
/** /**
* Adds a numeric statistical facet for the provided field name. * Adds a numeric statistical facet for the provided field name.
* *
@ -312,6 +335,11 @@ public class SearchRequestBuilder {
return this; return this;
} }
public SearchRequestBuilder addFacetStatistical(String name, String fieldName, @Nullable XContentFilterBuilder filter) {
facetsBuilder().statisticalFacet(name, fieldName, filter);
return this;
}
/** /**
* Adds a numeric statistical <b>global</b> facet for the provided field name. * Adds a numeric statistical <b>global</b> facet for the provided field name.
* *
@ -324,26 +352,53 @@ public class SearchRequestBuilder {
return this; return this;
} }
public SearchRequestBuilder addFacetGlobalStatistical(String name, String fieldName, @Nullable XContentFilterBuilder filter) {
facetsBuilder().statisticalFacetGlobal(name, fieldName, filter);
return this;
}
public SearchRequestBuilder addFacetHistogram(String name, String fieldName, long interval) { public SearchRequestBuilder addFacetHistogram(String name, String fieldName, long interval) {
facetsBuilder().histogramFacet(name, fieldName, interval); facetsBuilder().histogramFacet(name, fieldName, interval);
return this; return this;
} }
public SearchRequestBuilder addFacetHistogram(String name, String fieldName, long interval, @Nullable XContentFilterBuilder filter) {
facetsBuilder().histogramFacet(name, fieldName, interval, filter);
return this;
}
public SearchRequestBuilder addFacetHistogram(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType) { public SearchRequestBuilder addFacetHistogram(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType) {
facetsBuilder().histogramFacet(name, fieldName, interval, comparatorType); facetsBuilder().histogramFacet(name, fieldName, interval, comparatorType);
return this; return this;
} }
public SearchRequestBuilder addFacetHistogram(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType,
@Nullable XContentFilterBuilder filter) {
facetsBuilder().histogramFacet(name, fieldName, interval, comparatorType, filter);
return this;
}
public SearchRequestBuilder addFacetHistogramGlobal(String name, String fieldName, long interval) { public SearchRequestBuilder addFacetHistogramGlobal(String name, String fieldName, long interval) {
facetsBuilder().histogramFacetGlobal(name, fieldName, interval); facetsBuilder().histogramFacetGlobal(name, fieldName, interval);
return this; return this;
} }
public SearchRequestBuilder addFacetHistogramGlobal(String name, String fieldName, long interval, @Nullable XContentFilterBuilder filter) {
facetsBuilder().histogramFacetGlobal(name, fieldName, interval, filter);
return this;
}
public SearchRequestBuilder addFacetHistogramGlobal(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType) { public SearchRequestBuilder addFacetHistogramGlobal(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType) {
facetsBuilder().histogramFacetGlobal(name, fieldName, interval, comparatorType); facetsBuilder().histogramFacetGlobal(name, fieldName, interval, comparatorType);
return this; return this;
} }
public SearchRequestBuilder addFacetHistogramGlobal(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType,
@Nullable XContentFilterBuilder filter) {
facetsBuilder().histogramFacetGlobal(name, fieldName, interval, comparatorType, filter);
return this;
}
/** /**
* Adds a field to be highlighted with default fragment size of 100 characters, and * Adds a field to be highlighted with default fragment size of 100 characters, and
* default number of fragments of 5. * default number of fragments of 5.

View File

@ -19,6 +19,7 @@
package org.elasticsearch.index.query.xcontent; package org.elasticsearch.index.query.xcontent;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticSearchException; import org.elasticsearch.ElasticSearchException;
import org.elasticsearch.index.AbstractIndexComponent; import org.elasticsearch.index.AbstractIndexComponent;
@ -190,6 +191,18 @@ public class XContentIndexQueryParser extends AbstractIndexComponent implements
} }
} }
public Filter parseInnerFilter(XContentParser parser) throws IOException {
QueryParseContext context = cache.get().get();
context.reset(parser);
return context.parseInnerFilter();
}
public Query parseInnerQuery(XContentParser parser) throws IOException {
QueryParseContext context = cache.get().get();
context.reset(parser);
return context.parseInnerQuery();
}
private Query parse(QueryParseContext parseContext, XContentParser parser) throws IOException, QueryParsingException { private Query parse(QueryParseContext parseContext, XContentParser parser) throws IOException, QueryParsingException {
parseContext.reset(parser); parseContext.reset(parser);
return parseContext.parseInnerQuery(); return parseContext.parseInnerQuery();

View File

@ -19,6 +19,7 @@
package org.elasticsearch.search.builder; package org.elasticsearch.search.builder;
import org.elasticsearch.index.query.xcontent.XContentFilterBuilder;
import org.elasticsearch.index.query.xcontent.XContentQueryBuilder; import org.elasticsearch.index.query.xcontent.XContentQueryBuilder;
import org.elasticsearch.search.facets.histogram.HistogramFacet; import org.elasticsearch.search.facets.histogram.HistogramFacet;
import org.elasticsearch.search.facets.histogram.HistogramFacetCollectorParser; import org.elasticsearch.search.facets.histogram.HistogramFacetCollectorParser;
@ -28,6 +29,7 @@ import org.elasticsearch.search.facets.terms.TermsFacetCollectorParser;
import org.elasticsearch.util.xcontent.ToXContent; import org.elasticsearch.util.xcontent.ToXContent;
import org.elasticsearch.util.xcontent.builder.XContentBuilder; import org.elasticsearch.util.xcontent.builder.XContentBuilder;
import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -46,20 +48,28 @@ public class SearchSourceFacetsBuilder implements ToXContent {
private List<BuilderStatisticalFacet> statisticalFacets; private List<BuilderStatisticalFacet> statisticalFacets;
private List<BuilderHistogramFacet> histogramFacets; private List<BuilderHistogramFacet> histogramFacets;
public SearchSourceFacetsBuilder queryFacet(String name, XContentQueryBuilder query) {
return queryFacet(name, query, null);
}
/** /**
* Adds a query facet (which results in a count facet returned). * Adds a query facet (which results in a count facet returned).
* *
* @param name The logical name of the facet, it will be returned under the name * @param name The logical name of the facet, it will be returned under the name
* @param query The query facet * @param query The query facet
*/ */
public SearchSourceFacetsBuilder queryFacet(String name, XContentQueryBuilder query) { public SearchSourceFacetsBuilder queryFacet(String name, XContentQueryBuilder query, @Nullable XContentFilterBuilder filter) {
if (queryFacets == null) { if (queryFacets == null) {
queryFacets = newArrayListWithCapacity(2); queryFacets = newArrayListWithCapacity(2);
} }
queryFacets.add(new BuilderQueryFacet(name, query, false)); queryFacets.add(new BuilderQueryFacet(name, query, filter, false));
return this; return this;
} }
public SearchSourceFacetsBuilder queryFacetGlobal(String name, XContentQueryBuilder query) {
return queryFacetGlobal(name, query, null);
}
/** /**
* Adds a query facet (which results in a count facet returned) with an option to * Adds a query facet (which results in a count facet returned) with an option to
* be global on the index or bounded by the search query. * be global on the index or bounded by the search query.
@ -67,67 +77,101 @@ public class SearchSourceFacetsBuilder implements ToXContent {
* @param name The logical name of the facet, it will be returned under the name * @param name The logical name of the facet, it will be returned under the name
* @param query The query facet * @param query The query facet
*/ */
public SearchSourceFacetsBuilder queryFacetGlobal(String name, XContentQueryBuilder query) { public SearchSourceFacetsBuilder queryFacetGlobal(String name, XContentQueryBuilder query, @Nullable XContentFilterBuilder filter) {
if (queryFacets == null) { if (queryFacets == null) {
queryFacets = newArrayListWithCapacity(2); queryFacets = newArrayListWithCapacity(2);
} }
queryFacets.add(new BuilderQueryFacet(name, query, true)); queryFacets.add(new BuilderQueryFacet(name, query, filter, true));
return this; return this;
} }
public SearchSourceFacetsBuilder termsFacet(String name, String fieldName, int size) { public SearchSourceFacetsBuilder termsFacet(String name, String fieldName, int size) {
return termsFacet(name, fieldName, size, null);
}
public SearchSourceFacetsBuilder termsFacet(String name, String fieldName, int size, @Nullable XContentFilterBuilder filter) {
if (termsFacets == null) { if (termsFacets == null) {
termsFacets = newArrayListWithCapacity(2); termsFacets = newArrayListWithCapacity(2);
} }
termsFacets.add(new BuilderTermsFacet(name, fieldName, size, false)); termsFacets.add(new BuilderTermsFacet(name, fieldName, size, filter, false));
return this; return this;
} }
public SearchSourceFacetsBuilder termsFacetGlobal(String name, String fieldName, int size) { public SearchSourceFacetsBuilder termsFacetGlobal(String name, String fieldName, int size) {
return termsFacetGlobal(name, fieldName, size, null);
}
public SearchSourceFacetsBuilder termsFacetGlobal(String name, String fieldName, int size, @Nullable XContentFilterBuilder filter) {
if (termsFacets == null) { if (termsFacets == null) {
termsFacets = newArrayListWithCapacity(2); termsFacets = newArrayListWithCapacity(2);
} }
termsFacets.add(new BuilderTermsFacet(name, fieldName, size, true)); termsFacets.add(new BuilderTermsFacet(name, fieldName, size, filter, true));
return this; return this;
} }
public SearchSourceFacetsBuilder statisticalFacet(String name, String fieldName) { public SearchSourceFacetsBuilder statisticalFacet(String name, String fieldName) {
return statisticalFacet(name, fieldName, null);
}
public SearchSourceFacetsBuilder statisticalFacet(String name, String fieldName, @Nullable XContentFilterBuilder filter) {
if (statisticalFacets == null) { if (statisticalFacets == null) {
statisticalFacets = newArrayListWithCapacity(2); statisticalFacets = newArrayListWithCapacity(2);
} }
statisticalFacets.add(new BuilderStatisticalFacet(name, fieldName, false)); statisticalFacets.add(new BuilderStatisticalFacet(name, fieldName, filter, false));
return this; return this;
} }
public SearchSourceFacetsBuilder statisticalFacetGlobal(String name, String fieldName) { public SearchSourceFacetsBuilder statisticalFacetGlobal(String name, String fieldName) {
return statisticalFacetGlobal(name, fieldName, null);
}
public SearchSourceFacetsBuilder statisticalFacetGlobal(String name, String fieldName, @Nullable XContentFilterBuilder filter) {
if (statisticalFacets == null) { if (statisticalFacets == null) {
statisticalFacets = newArrayListWithCapacity(2); statisticalFacets = newArrayListWithCapacity(2);
} }
statisticalFacets.add(new BuilderStatisticalFacet(name, fieldName, true)); statisticalFacets.add(new BuilderStatisticalFacet(name, fieldName, filter, true));
return this; return this;
} }
public SearchSourceFacetsBuilder histogramFacet(String name, String fieldName, long interval) { public SearchSourceFacetsBuilder histogramFacet(String name, String fieldName, long interval) {
return histogramFacet(name, fieldName, interval, HistogramFacet.ComparatorType.VALUE); return histogramFacet(name, fieldName, interval, HistogramFacet.ComparatorType.VALUE, null);
}
public SearchSourceFacetsBuilder histogramFacet(String name, String fieldName, long interval, @Nullable XContentFilterBuilder filter) {
return histogramFacet(name, fieldName, interval, HistogramFacet.ComparatorType.VALUE, filter);
} }
public SearchSourceFacetsBuilder histogramFacet(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType) { public SearchSourceFacetsBuilder histogramFacet(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType) {
return histogramFacet(name, fieldName, interval, comparatorType, null);
}
public SearchSourceFacetsBuilder histogramFacet(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType,
@Nullable XContentFilterBuilder filter) {
if (histogramFacets == null) { if (histogramFacets == null) {
histogramFacets = newArrayListWithCapacity(2); histogramFacets = newArrayListWithCapacity(2);
} }
histogramFacets.add(new BuilderHistogramFacet(name, fieldName, interval, comparatorType, false)); histogramFacets.add(new BuilderHistogramFacet(name, fieldName, interval, comparatorType, filter, false));
return this; return this;
} }
public SearchSourceFacetsBuilder histogramFacetGlobal(String name, String fieldName, long interval) { public SearchSourceFacetsBuilder histogramFacetGlobal(String name, String fieldName, long interval) {
return histogramFacet(name, fieldName, interval, HistogramFacet.ComparatorType.VALUE); return histogramFacet(name, fieldName, interval, HistogramFacet.ComparatorType.VALUE, null);
}
public SearchSourceFacetsBuilder histogramFacetGlobal(String name, String fieldName, long interval, @Nullable XContentFilterBuilder filter) {
return histogramFacet(name, fieldName, interval, HistogramFacet.ComparatorType.VALUE, filter);
} }
public SearchSourceFacetsBuilder histogramFacetGlobal(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType) { public SearchSourceFacetsBuilder histogramFacetGlobal(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType) {
return histogramFacetGlobal(name, fieldName, interval, comparatorType, null);
}
public SearchSourceFacetsBuilder histogramFacetGlobal(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType,
@Nullable XContentFilterBuilder filter) {
if (histogramFacets == null) { if (histogramFacets == null) {
histogramFacets = newArrayListWithCapacity(2); histogramFacets = newArrayListWithCapacity(2);
} }
histogramFacets.add(new BuilderHistogramFacet(name, fieldName, interval, comparatorType, true)); histogramFacets.add(new BuilderHistogramFacet(name, fieldName, interval, comparatorType, filter, true));
return this; return this;
} }
@ -144,6 +188,12 @@ public class SearchSourceFacetsBuilder implements ToXContent {
builder.startObject(queryFacet.name()); builder.startObject(queryFacet.name());
builder.field(QueryFacetCollectorParser.NAME); builder.field(QueryFacetCollectorParser.NAME);
queryFacet.queryBuilder().toXContent(builder, params); queryFacet.queryBuilder().toXContent(builder, params);
if (queryFacet.filter() != null) {
builder.field("filter");
queryFacet.filter().toXContent(builder, params);
}
if (queryFacet.global() != null) { if (queryFacet.global() != null) {
builder.field("global", queryFacet.global()); builder.field("global", queryFacet.global());
} }
@ -159,6 +209,10 @@ public class SearchSourceFacetsBuilder implements ToXContent {
builder.field("size", termsFacet.size()); builder.field("size", termsFacet.size());
builder.endObject(); builder.endObject();
if (termsFacet.filter() != null) {
builder.field("filter");
termsFacet.filter().toXContent(builder, params);
}
if (termsFacet.global() != null) { if (termsFacet.global() != null) {
builder.field("global", termsFacet.global()); builder.field("global", termsFacet.global());
} }
@ -175,6 +229,11 @@ public class SearchSourceFacetsBuilder implements ToXContent {
builder.field("field", statisticalFacet.fieldName()); builder.field("field", statisticalFacet.fieldName());
builder.endObject(); builder.endObject();
if (statisticalFacet.filter() != null) {
builder.field("filter");
statisticalFacet.filter().toXContent(builder, params);
}
if (statisticalFacet.global() != null) { if (statisticalFacet.global() != null) {
builder.field("global", statisticalFacet.global()); builder.field("global", statisticalFacet.global());
} }
@ -193,6 +252,11 @@ public class SearchSourceFacetsBuilder implements ToXContent {
builder.field("comparator", histogramFacet.comparatorType().description()); builder.field("comparator", histogramFacet.comparatorType().description());
builder.endObject(); builder.endObject();
if (histogramFacet.filter() != null) {
builder.field("filter");
histogramFacet.filter().toXContent(builder, params);
}
if (histogramFacet.global() != null) { if (histogramFacet.global() != null) {
builder.field("global", histogramFacet.global()); builder.field("global", histogramFacet.global());
} }
@ -209,11 +273,13 @@ public class SearchSourceFacetsBuilder implements ToXContent {
private final String fieldName; private final String fieldName;
private final int size; private final int size;
private final Boolean global; private final Boolean global;
private final XContentFilterBuilder filter;
private BuilderTermsFacet(String name, String fieldName, int size, Boolean global) { private BuilderTermsFacet(String name, String fieldName, int size, XContentFilterBuilder filter, Boolean global) {
this.name = name; this.name = name;
this.fieldName = fieldName; this.fieldName = fieldName;
this.size = size; this.size = size;
this.filter = filter;
this.global = global; this.global = global;
} }
@ -229,6 +295,10 @@ public class SearchSourceFacetsBuilder implements ToXContent {
return size; return size;
} }
public XContentFilterBuilder filter() {
return filter;
}
public Boolean global() { public Boolean global() {
return global; return global;
} }
@ -237,11 +307,13 @@ public class SearchSourceFacetsBuilder implements ToXContent {
private static class BuilderQueryFacet { private static class BuilderQueryFacet {
private final String name; private final String name;
private final XContentQueryBuilder queryBuilder; private final XContentQueryBuilder queryBuilder;
private final XContentFilterBuilder filter;
private final Boolean global; private final Boolean global;
private BuilderQueryFacet(String name, XContentQueryBuilder queryBuilder, Boolean global) { private BuilderQueryFacet(String name, XContentQueryBuilder queryBuilder, XContentFilterBuilder filter, Boolean global) {
this.name = name; this.name = name;
this.queryBuilder = queryBuilder; this.queryBuilder = queryBuilder;
this.filter = filter;
this.global = global; this.global = global;
} }
@ -253,6 +325,10 @@ public class SearchSourceFacetsBuilder implements ToXContent {
return queryBuilder; return queryBuilder;
} }
public XContentFilterBuilder filter() {
return filter;
}
public Boolean global() { public Boolean global() {
return this.global; return this.global;
} }
@ -261,11 +337,13 @@ public class SearchSourceFacetsBuilder implements ToXContent {
private static class BuilderStatisticalFacet { private static class BuilderStatisticalFacet {
private final String name; private final String name;
private final String fieldName; private final String fieldName;
private final XContentFilterBuilder filter;
private final Boolean global; private final Boolean global;
private BuilderStatisticalFacet(String name, String fieldName, Boolean global) { private BuilderStatisticalFacet(String name, String fieldName, XContentFilterBuilder filter, Boolean global) {
this.name = name; this.name = name;
this.fieldName = fieldName; this.fieldName = fieldName;
this.filter = filter;
this.global = global; this.global = global;
} }
@ -277,6 +355,10 @@ public class SearchSourceFacetsBuilder implements ToXContent {
return fieldName; return fieldName;
} }
public XContentFilterBuilder filter() {
return this.filter;
}
public Boolean global() { public Boolean global() {
return this.global; return this.global;
} }
@ -287,17 +369,20 @@ public class SearchSourceFacetsBuilder implements ToXContent {
private final String fieldName; private final String fieldName;
private final long interval; private final long interval;
private final HistogramFacet.ComparatorType comparatorType; private final HistogramFacet.ComparatorType comparatorType;
private final XContentFilterBuilder filter;
private final Boolean global; private final Boolean global;
private BuilderHistogramFacet(String name, String fieldName, long interval, Boolean global) { private BuilderHistogramFacet(String name, String fieldName, long interval, XContentFilterBuilder filter, Boolean global) {
this(name, fieldName, interval, HistogramFacet.ComparatorType.VALUE, global); this(name, fieldName, interval, HistogramFacet.ComparatorType.VALUE, filter, global);
} }
private BuilderHistogramFacet(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType, Boolean global) { private BuilderHistogramFacet(String name, String fieldName, long interval, HistogramFacet.ComparatorType comparatorType,
XContentFilterBuilder filter, Boolean global) {
this.name = name; this.name = name;
this.fieldName = fieldName; this.fieldName = fieldName;
this.interval = interval; this.interval = interval;
this.comparatorType = comparatorType; this.comparatorType = comparatorType;
this.filter = filter;
this.global = global; this.global = global;
} }
@ -317,6 +402,10 @@ public class SearchSourceFacetsBuilder implements ToXContent {
return this.comparatorType; return this.comparatorType;
} }
public XContentFilterBuilder filter() {
return this.filter;
}
public Boolean global() { public Boolean global() {
return this.global; return this.global;
} }

View File

@ -19,6 +19,8 @@
package org.elasticsearch.search.facets; package org.elasticsearch.search.facets;
import org.apache.lucene.search.Filter;
import org.elasticsearch.index.query.xcontent.XContentIndexQueryParser;
import org.elasticsearch.search.SearchParseElement; import org.elasticsearch.search.SearchParseElement;
import org.elasticsearch.search.SearchParseException; import org.elasticsearch.search.SearchParseException;
import org.elasticsearch.search.facets.collector.FacetCollector; import org.elasticsearch.search.facets.collector.FacetCollector;
@ -82,21 +84,36 @@ public class FacetsParseElement implements SearchParseElement {
FacetCollector facet = null; FacetCollector facet = null;
boolean global = false; boolean global = false;
String facetFieldName = null; String facetFieldName = null;
Filter filter = null;
boolean cacheFilter = true;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) { if (token == XContentParser.Token.FIELD_NAME) {
facetFieldName = parser.currentName(); facetFieldName = parser.currentName();
} else if (token == XContentParser.Token.START_OBJECT) { } else if (token == XContentParser.Token.START_OBJECT) {
FacetCollectorParser facetCollectorParser = facetCollectorParsers.get(facetFieldName); if ("filter".equals(facetFieldName)) {
if (facetCollectorParser == null) { XContentIndexQueryParser indexQueryParser = (XContentIndexQueryParser) context.queryParser();
throw new SearchParseException(context, "No facet type for [" + facetFieldName + "]"); filter = indexQueryParser.parseInnerFilter(parser);
} else {
FacetCollectorParser facetCollectorParser = facetCollectorParsers.get(facetFieldName);
if (facetCollectorParser == null) {
throw new SearchParseException(context, "No facet type for [" + facetFieldName + "]");
}
facet = facetCollectorParser.parser(topLevelFieldName, parser, context);
} }
facet = facetCollectorParser.parser(topLevelFieldName, parser, context);
} else if (token.isValue()) { } else if (token.isValue()) {
if ("global".equals(facetFieldName)) { if ("global".equals(facetFieldName)) {
global = parser.booleanValue(); global = parser.booleanValue();
} else if ("cache_filter".equals(facetFieldName) || "cacheFilter".equals(facetFieldName)) {
cacheFilter = parser.booleanValue();
} }
} }
} }
if (filter != null) {
if (cacheFilter) {
filter = context.filterCache().cache(filter);
}
facet.setFilter(filter);
}
if (facetCollectors == null) { if (facetCollectors == null) {
facetCollectors = Lists.newArrayList(); facetCollectors = Lists.newArrayList();

View File

@ -20,6 +20,7 @@
package org.elasticsearch.search.facets.collector; package org.elasticsearch.search.facets.collector;
import org.apache.lucene.search.Collector; import org.apache.lucene.search.Collector;
import org.apache.lucene.search.Filter;
import org.elasticsearch.search.facets.Facet; import org.elasticsearch.search.facets.Facet;
/** /**
@ -28,4 +29,6 @@ import org.elasticsearch.search.facets.Facet;
public abstract class FacetCollector extends Collector { public abstract class FacetCollector extends Collector {
public abstract Facet facet(); public abstract Facet facet();
public abstract void setFilter(Filter filter);
} }

View File

@ -70,11 +70,11 @@ public class HistogramFacetCollector extends AbstractFacetCollector {
histoProc = new HistogramProc(interval); histoProc = new HistogramProc(interval);
} }
@Override public void collect(int doc) throws IOException { @Override protected void doCollect(int doc) throws IOException {
fieldData.forEachValueInDoc(doc, histoProc); fieldData.forEachValueInDoc(doc, histoProc);
} }
@Override public void setNextReader(IndexReader reader, int docBase) throws IOException { @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException {
fieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, fieldName, fieldDataOptions().withFreqs(false)); fieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, fieldName, fieldDataOptions().withFreqs(false));
} }

View File

@ -42,9 +42,9 @@ public class HistogramFacetCollectorParser implements FacetCollectorParser {
String field = null; String field = null;
String fieldName = null; String fieldName = null;
XContentParser.Token token;
long interval = -1; long interval = -1;
HistogramFacet.ComparatorType comparatorType = HistogramFacet.ComparatorType.VALUE; HistogramFacet.ComparatorType comparatorType = HistogramFacet.ComparatorType.VALUE;
XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) { if (token == XContentParser.Token.FIELD_NAME) {
fieldName = parser.currentName(); fieldName = parser.currentName();
@ -66,7 +66,6 @@ public class HistogramFacetCollectorParser implements FacetCollectorParser {
if (interval < 0) { if (interval < 0) {
throw new FacetPhaseExecutionException(facetName, "[interval] is required to be positive for histogram facet"); throw new FacetPhaseExecutionException(facetName, "[interval] is required to be positive for histogram facet");
} }
return new HistogramFacetCollector(facetName, field, interval, comparatorType, context.fieldDataCache(), context.mapperService()); return new HistogramFacetCollector(facetName, field, interval, comparatorType, context.fieldDataCache(), context.mapperService());
} }
} }

View File

@ -47,11 +47,11 @@ public class QueryFacetCollector extends AbstractFacetCollector {
this.filter = filterCache.cache(new QueryWrapperFilter(query)); this.filter = filterCache.cache(new QueryWrapperFilter(query));
} }
@Override public void setNextReader(IndexReader reader, int docBase) throws IOException { @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException {
docSet = DocSets.convert(reader, filter.getDocIdSet(reader)); docSet = DocSets.convert(reader, filter.getDocIdSet(reader));
} }
@Override public void collect(int doc) throws IOException { @Override protected void doCollect(int doc) throws IOException {
if (docSet.get(doc)) { if (docSet.get(doc)) {
count++; count++;
} }

View File

@ -60,11 +60,11 @@ public class StatisticalFacetCollector extends AbstractFacetCollector {
fieldDataType = mapper.fieldDataType(); fieldDataType = mapper.fieldDataType();
} }
@Override public void collect(int doc) throws IOException { @Override protected void doCollect(int doc) throws IOException {
fieldData.forEachValueInDoc(doc, statsProc); fieldData.forEachValueInDoc(doc, statsProc);
} }
@Override public void setNextReader(IndexReader reader, int docBase) throws IOException { @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException {
fieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, fieldName, fieldDataOptions().withFreqs(false)); fieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, fieldName, fieldDataOptions().withFreqs(false));
} }

View File

@ -19,8 +19,12 @@
package org.elasticsearch.search.facets.support; package org.elasticsearch.search.facets.support;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Scorer;
import org.elasticsearch.search.facets.collector.FacetCollector; import org.elasticsearch.search.facets.collector.FacetCollector;
import org.elasticsearch.util.lucene.docset.DocSet;
import org.elasticsearch.util.lucene.docset.DocSets;
import java.io.IOException; import java.io.IOException;
@ -31,10 +35,18 @@ public abstract class AbstractFacetCollector extends FacetCollector {
protected final String facetName; protected final String facetName;
protected Filter filter;
private DocSet docSet = null;
public AbstractFacetCollector(String facetName) { public AbstractFacetCollector(String facetName) {
this.facetName = facetName; this.facetName = facetName;
} }
@Override public void setFilter(Filter filter) {
this.filter = filter;
}
@Override public void setScorer(Scorer scorer) throws IOException { @Override public void setScorer(Scorer scorer) throws IOException {
// usually, there is nothing to do here // usually, there is nothing to do here
} }
@ -42,4 +54,23 @@ public abstract class AbstractFacetCollector extends FacetCollector {
@Override public boolean acceptsDocsOutOfOrder() { @Override public boolean acceptsDocsOutOfOrder() {
return true; // when working on FieldData, docs can be out of order return true; // when working on FieldData, docs can be out of order
} }
@Override public void setNextReader(IndexReader reader, int docBase) throws IOException {
if (filter != null) {
docSet = DocSets.convert(reader, filter.getDocIdSet(reader));
}
doSetNextReader(reader, docBase);
}
protected abstract void doSetNextReader(IndexReader reader, int docBase) throws IOException;
@Override public void collect(int doc) throws IOException {
if (docSet == null) {
doCollect(doc);
} else if (docSet.get(doc)) {
doCollect(doc);
}
}
protected abstract void doCollect(int doc) throws IOException;
} }

View File

@ -79,11 +79,11 @@ public class TermsFacetCollector extends AbstractFacetCollector {
aggregator = new AggregatorValueProc(popFacets()); aggregator = new AggregatorValueProc(popFacets());
} }
@Override public void setNextReader(IndexReader reader, int docBase) throws IOException { @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException {
fieldData = fieldDataCache.cache(fieldDataType, reader, fieldName, fieldDataOptions().withFreqs(false)); fieldData = fieldDataCache.cache(fieldDataType, reader, fieldName, fieldDataOptions().withFreqs(false));
} }
@Override public void collect(int doc) throws IOException { @Override protected void doCollect(int doc) throws IOException {
fieldData.forEachValueInDoc(doc, aggregator); fieldData.forEachValueInDoc(doc, aggregator);
} }

View File

@ -41,15 +41,15 @@ public class TermsFacetCollectorParser implements FacetCollectorParser {
String field = null; String field = null;
int size = 10; int size = 10;
String termFieldName = null; String fieldName = null;
XContentParser.Token token; XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) { if (token == XContentParser.Token.FIELD_NAME) {
termFieldName = parser.currentName(); fieldName = parser.currentName();
} else if (token.isValue()) { } else if (token.isValue()) {
if ("field".equals(termFieldName)) { if ("field".equals(fieldName)) {
field = parser.text(); field = parser.text();
} else if ("size".equals(termFieldName)) { } else if ("size".equals(fieldName)) {
size = parser.intValue(); size = parser.intValue();
} }
} }

View File

@ -30,13 +30,14 @@ import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import static org.elasticsearch.index.query.xcontent.FilterBuilders.*;
import static org.elasticsearch.index.query.xcontent.QueryBuilders.*; import static org.elasticsearch.index.query.xcontent.QueryBuilders.*;
import static org.elasticsearch.util.xcontent.XContentFactory.*; import static org.elasticsearch.util.xcontent.XContentFactory.*;
import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
/** /**
* @author kimchy (Shay Banon) * @author kimchy (shay.banon)
*/ */
public class SimpleFacetsTests extends AbstractNodesTests { public class SimpleFacetsTests extends AbstractNodesTests {
@ -96,6 +97,17 @@ public class SimpleFacetsTests extends AbstractNodesTests {
assertThat(facet.entries().size(), equalTo(3)); assertThat(facet.entries().size(), equalTo(3));
assertThat(facet.entries().get(0).term(), equalTo("yyy")); assertThat(facet.entries().get(0).term(), equalTo("yyy"));
assertThat(facet.entries().get(0).count(), equalTo(2)); assertThat(facet.entries().get(0).count(), equalTo(2));
searchResponse = client.prepareSearch()
.setQuery(matchAllQuery())
.addFacetTerms("facet1", "stag", 10, termFilter("tag", "xxx"))
.execute().actionGet();
facet = searchResponse.facets().facet(TermsFacet.class, "facet1");
assertThat(facet.name(), equalTo("facet1"));
assertThat(facet.entries().size(), equalTo(1));
assertThat(facet.entries().get(0).term(), equalTo("111"));
assertThat(facet.entries().get(0).count(), equalTo(1));
} }
@Test public void testStatsFacets() throws Exception { @Test public void testStatsFacets() throws Exception {