protected final InternalAggregations buildEmptySubAggregations() { List<InternalAggregation> aggs = new ArrayList<>(); for (Aggregator aggregator : subAggregators) { aggs.add(aggregator.buildEmptyAggregation()); } return new InternalAggregations(aggs); }
/** * Returns whether any of the parent aggregators has {@link BucketAggregationMode#PER_BUCKET} as a * bucket aggregation mode. */ public static boolean hasParentBucketAggregator(Aggregator parent) { if (parent == null) { return false; } else if (parent.bucketAggregationMode() == BucketAggregationMode.PER_BUCKET) { return true; } else { return hasParentBucketAggregator(parent.parent()); } }
/** Create all aggregators so that they can be consumed with multiple buckets. */ public Aggregator[] createSubAggregators(Aggregator parent) throws IOException { Aggregator[] aggregators = new Aggregator[count()]; for (int i = 0; i < factories.length; ++i) { // TODO: sometimes even sub aggregations always get called with bucket 0, eg. if // you have a terms agg under a top-level filter agg. We should have a way to // propagate the fact that only bucket 0 will be collected with single-bucket // aggs final boolean collectsFromSingleBucket = false; aggregators[i] = factories[i].create(parent.context(), parent, collectsFromSingleBucket); } return aggregators; }
@Override public Aggregator create( AggregationContext context, Aggregator parent, long expectedBucketsCount) { if (parent != null) { throw new AggregationExecutionException( "Aggregation [" + parent.name() + "] cannot have a global " + "sub-aggregation [" + name + "]. Global aggregations can only be defined as top level aggregations"); } return new GlobalAggregator(name, factories, context); }
/** * Constructs a new Aggregator. * * @param name The name of the aggregation * @param bucketAggregationMode The nature of execution as a sub-aggregator (see {@link * BucketAggregationMode}) * @param factories The factories for all the sub-aggregators under this aggregator * @param estimatedBucketsCount When served as a sub-aggregator, indicate how many buckets the * parent aggregator will generate. * @param context The aggregation context * @param parent The parent aggregator (may be {@code null} for top level aggregators) */ protected Aggregator( String name, BucketAggregationMode bucketAggregationMode, AggregatorFactories factories, long estimatedBucketsCount, AggregationContext context, Aggregator parent) { this.name = name; this.parent = parent; this.estimatedBucketCount = estimatedBucketsCount; this.context = context; this.bigArrays = context.bigArrays(); this.depth = parent == null ? 0 : 1 + parent.depth(); this.bucketAggregationMode = bucketAggregationMode; assert factories != null : "sub-factories provided to BucketAggregator must not be null, use AggragatorFactories.EMPTY instead"; this.factories = factories; this.subAggregators = factories.createSubAggregators(this, estimatedBucketsCount); collectableSugAggregators = BucketCollector.wrap( Iterables.filter(Arrays.asList(subAggregators), COLLECTABLE_AGGREGATOR)); context.searchContext().addReleasable(this, Lifetime.PHASE); }
@Override public boolean apply(Aggregator aggregator) { return aggregator.shouldCollect(); }
@Override protected boolean shouldDefer(Aggregator aggregator) { return collectMode == SubAggCollectionMode.BREADTH_FIRST && aggregator.needsScores() == false && !aggsUsedForSorting.contains(aggregator); }
@Override public void execute(SearchContext context) { if (context.aggregations() == null) { context.queryResult().aggregations(null); return; } if (context.queryResult().aggregations() != null) { // no need to compute the aggs twice, they should be computed on a per context basis return; } Aggregator[] aggregators = context.aggregations().aggregators(); List<Aggregator> globals = new ArrayList<>(); for (int i = 0; i < aggregators.length; i++) { if (aggregators[i] instanceof GlobalAggregator) { globals.add(aggregators[i]); } } // optimize the global collector based execution if (!globals.isEmpty()) { BucketCollector globalsCollector = BucketCollector.wrap(globals); Query query = Queries.newMatchAllQuery(); Query searchFilter = context.searchFilter(context.types()); if (searchFilter != null) { BooleanQuery filtered = new BooleanQuery.Builder() .add(query, Occur.MUST) .add(searchFilter, Occur.FILTER) .build(); query = filtered; } try { final Collector collector; if (context.getProfilers() == null) { collector = globalsCollector; } else { InternalProfileCollector profileCollector = new InternalProfileCollector( globalsCollector, CollectorResult.REASON_AGGREGATION_GLOBAL, // TODO: report on sub collectors Collections.emptyList()); collector = profileCollector; // start a new profile with this collector context.getProfilers().addProfiler().setCollector(profileCollector); } globalsCollector.preCollection(); context.searcher().search(query, collector); } catch (Exception e) { throw new QueryPhaseExecutionException(context, "Failed to execute global aggregators", e); } finally { context.clearReleasables(SearchContext.Lifetime.COLLECTION); } } List<InternalAggregation> aggregations = new ArrayList<>(aggregators.length); for (Aggregator aggregator : context.aggregations().aggregators()) { try { aggregator.postCollection(); aggregations.add(aggregator.buildAggregation(0)); } catch (IOException e) { throw new AggregationExecutionException( "Failed to build aggregation [" + aggregator.name() + "]", e); } } context.queryResult().aggregations(new InternalAggregations(aggregations)); try { List<PipelineAggregator> pipelineAggregators = context.aggregations().factories().createPipelineAggregators(); List<SiblingPipelineAggregator> siblingPipelineAggregators = new ArrayList<>(pipelineAggregators.size()); for (PipelineAggregator pipelineAggregator : pipelineAggregators) { if (pipelineAggregator instanceof SiblingPipelineAggregator) { siblingPipelineAggregators.add((SiblingPipelineAggregator) pipelineAggregator); } else { throw new AggregationExecutionException( "Invalid pipeline aggregation named [" + pipelineAggregator.name() + "] of type [" + pipelineAggregator.type().name() + "]. Only sibling pipeline aggregations are allowed at the top level"); } } context.queryResult().pipelineAggregators(siblingPipelineAggregators); } catch (IOException e) { throw new AggregationExecutionException("Failed to build top level pipeline aggregators", e); } // disable aggregations so that they don't run on next pages in case of scrolling context.aggregations(null); context.queryCollectors().remove(AggregationPhase.class); }
@Override public final void close() { try (Releasable releasable = docCounts) { super.close(); } }
@Override protected Aggregator doCreateInternal( ValuesSource valuesSource, AggregationContext aggregationContext, Aggregator parent, boolean collectsFromSingleBucket, List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) throws IOException { if (collectsFromSingleBucket == false) { return asMultiBucketAggregator(this, aggregationContext, parent); } numberOfAggregatorsCreated++; if (valuesSource instanceof ValuesSource.Bytes) { ExecutionMode execution = null; if (executionHint != null) { execution = ExecutionMode.fromString( executionHint, aggregationContext.searchContext().parseFieldMatcher()); } if (!(valuesSource instanceof ValuesSource.Bytes.WithOrdinals)) { execution = ExecutionMode.MAP; } if (execution == null) { if (Aggregator.descendsFromBucketAggregator(parent)) { execution = ExecutionMode.GLOBAL_ORDINALS_HASH; } else { execution = ExecutionMode.GLOBAL_ORDINALS; } } assert execution != null; return execution.create( name, factories, valuesSource, bucketCountThresholds, includeExclude, aggregationContext, parent, this, pipelineAggregators, metaData); } if ((includeExclude != null) && (includeExclude.isRegexBased())) { throw new AggregationExecutionException( "Aggregation [" + name + "] cannot support regular expression style include/exclude " + "settings as they can only be applied to string fields. Use an array of numeric values for include/exclude clauses used to filter numeric fields"); } if (valuesSource instanceof ValuesSource.Numeric) { if (((ValuesSource.Numeric) valuesSource).isFloatingPoint()) { throw new UnsupportedOperationException("No support for examining floating point numerics"); } IncludeExclude.LongFilter longFilter = null; if (includeExclude != null) { longFilter = includeExclude.convertToLongFilter(); } return new SignificantLongTermsAggregator( name, factories, (ValuesSource.Numeric) valuesSource, config.format(), bucketCountThresholds, aggregationContext, parent, this, longFilter, pipelineAggregators, metaData); } throw new AggregationExecutionException( "sigfnificant_terms aggregation cannot be applied to field [" + config.fieldContext().field() + "]. It can only be applied to numeric or string fields."); }