diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterAggregator.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterAggregator.java index 00a6abec1b6..777f8f603cb 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterAggregator.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterAggregator.java @@ -22,7 +22,11 @@ import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.Query; import org.apache.lucene.search.Weight; import org.apache.lucene.util.Bits; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.lucene.Lucene; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.search.aggregations.Aggregator; import org.elasticsearch.search.aggregations.AggregatorFactories; import org.elasticsearch.search.aggregations.AggregatorFactory; @@ -36,6 +40,7 @@ import org.elasticsearch.search.aggregations.support.AggregationContext; import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.Objects; /** * Aggregate all docs that match a filter. @@ -82,19 +87,66 @@ public class FilterAggregator extends SingleBucketAggregator { public static class Factory extends AggregatorFactory { - private final Query filter; + private QueryBuilder filter; - public Factory(String name, Query filter) { + public Factory(String name) { super(name, InternalFilter.TYPE); + } + + /** + * Set the filter to use, only documents that match this filter will + * fall into the bucket defined by this {@link Filter} aggregation. + */ + public void filter(QueryBuilder filter) { this.filter = filter; } + /** + * Get the filter to use, only documents that match this filter will + * fall into the bucket defined by this {@link Filter} aggregation. + */ + public QueryBuilder filter() { + return filter; + } + @Override public Aggregator createInternal(AggregationContext context, Aggregator parent, boolean collectsFromSingleBucket, List pipelineAggregators, Map metaData) throws IOException { + Query filter = this.filter.toQuery(context.searchContext().indexShard().getQueryShardContext()); return new FilterAggregator(name, filter, factories, context, parent, pipelineAggregators, metaData); } + @Override + protected XContentBuilder internalXContent(XContentBuilder builder, Params params) throws IOException { + if (filter != null) { + filter.toXContent(builder, params); + } + return builder; + } + + @Override + protected AggregatorFactory doReadFrom(String name, StreamInput in) throws IOException { + Factory factory = new Factory(name); + factory.filter = in.readQuery(); + return factory; + } + + @Override + protected void doWriteTo(StreamOutput out) throws IOException { + out.writeQuery(filter); + } + + @Override + protected int doHashCode() { + return Objects.hash(filter); + } + + @Override + protected boolean doEquals(Object obj) { + Factory other = (Factory) obj; + return Objects.equals(filter, other.filter); + } + } } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterParser.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterParser.java index 7fc826f0ba8..9060bdca39d 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterParser.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterParser.java @@ -18,9 +18,12 @@ */ package org.elasticsearch.search.aggregations.bucket.filter; -import org.apache.lucene.search.MatchAllDocsQuery; +import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.index.query.ParsedQuery; +import org.elasticsearch.index.query.MatchAllQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryParseContext; +import org.elasticsearch.indices.query.IndicesQueriesRegistry; import org.elasticsearch.search.aggregations.Aggregator; import org.elasticsearch.search.aggregations.AggregatorFactory; import org.elasticsearch.search.internal.SearchContext; @@ -32,6 +35,13 @@ import java.io.IOException; */ public class FilterParser implements Aggregator.Parser { + private IndicesQueriesRegistry queriesRegistry; + + @Inject + public FilterParser(IndicesQueriesRegistry queriesRegistry) { + this.queriesRegistry = queriesRegistry; + } + @Override public String type() { return InternalFilter.TYPE.name(); @@ -39,15 +49,20 @@ public class FilterParser implements Aggregator.Parser { @Override public AggregatorFactory parse(String aggregationName, XContentParser parser, SearchContext context) throws IOException { - ParsedQuery filter = context.indexShard().getQueryShardContext().parseInnerFilter(parser); + QueryParseContext queryParseContext = new QueryParseContext(queriesRegistry); + queryParseContext.reset(parser); + queryParseContext.parseFieldMatcher(context.parseFieldMatcher()); + QueryBuilder filter = queryParseContext.parseInnerQueryBuilder(); - return new FilterAggregator.Factory(aggregationName, filter == null ? new MatchAllDocsQuery() : filter.query()); + FilterAggregator.Factory factory = new FilterAggregator.Factory(aggregationName); + factory.filter(filter == null ? new MatchAllQueryBuilder() : filter); + return factory; } // NORELEASE implement this method when refactoring this aggregation @Override public AggregatorFactory[] getFactoryPrototypes() { - return null; + return new AggregatorFactory[] { new FilterAggregator.Factory(null) }; } } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/FilterTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/FilterTests.java new file mode 100644 index 00000000000..3362c1cc6c9 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/FilterTests.java @@ -0,0 +1,39 @@ +/* + * 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.elasticsearch.search.aggregations.metrics; + +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.aggregations.BaseAggregationTestCase; +import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregator; +import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregator.Factory; + +public class FilterTests extends BaseAggregationTestCase { + + @Override + protected Factory createTestAggregatorFactory() { + Factory factory = new Factory(randomAsciiOfLengthBetween(1, 20)); + // NORELEASE make RandomQueryBuilder work outside of the + // AbstractQueryTestCase + // builder.query(RandomQueryBuilder.createQuery(getRandom())); + factory.filter(QueryBuilders.termQuery(randomAsciiOfLengthBetween(5, 20), randomAsciiOfLengthBetween(5, 20))); + return factory; + } + +}