AnalyticAggregator

Objects that implement the AnalyticFunction interface are not responsible for maintaining or using the partition, order by, or window clauses. It is AnalyticAggregator's responsibility. Because the Analytic class needs to know all of the partition, order by, and window clauses for every AnalyticFunction, it only accepts AnalyticAggregators. The AnalyticAggregator class does the following:

  • Implements AnalyticFunction.
  • Wraps an AnalyticFunction that is supplied to it. It delegates all AnalyticFunction calls to the wrapped function.
  • Maintains references to a PartitionClause, an OrderByClause, and a WindowClause.

Builder Class

The AnalyticAggregator class defines a static nested class "Builder" that follows the Builder pattern. This Builder class builds an AnalyticAggregator that can be supplied to the Analytic class. It has some methods that can be used to control how the resultant AnalyticAggregator behaves.

  • setAnalyticFunction(AnalyticFunction func) - This method is required, or build() will throw an Exception. This method supplies the AnalyticFunction that the AnalyticAggregator will wrap.
  • setPartition(PartitionClause partition) - This method is optional and supplies a PartitionClause. Create a PartitionClause by supplying a List of properties.
    PartitionClause partition = new PartitionClause(Arrays.asList("prop1", "prop2"));
    
    Separate partitions of data have no effect on each other's processing.
  • setOrderBy(OrderByClause orderBy) - This method is optional and supplies an OrderByClause. Create a OrderByClause by supplying a List of OrderByElements.
    OrderByClause orderBy = new OrderByClause(Arrays.asList(
        new OrderByElement("prop3"),
        new OrderByElement("prop4 DESC NULLS LAST")
    ));
    
    Data is iterated, and the sliding window is populated, in the order specified by the OrderByClause.
  • setWindow(WindowClause window) - This method is optional and supplies a WindowClause. Create a WindowClause by supplying a mode and optional window boundaries.
    WindowClause window1 = new WindowClause(WindowClause.Type.ROWS, 2, 3);
    
    The window window1 describes a sliding window that contains data going back 2 rows and going forward 3 rows. A value of 0 means the current row, and a value of null means unbounded.
    WindowClause window2 = new WindowClause(WindowClause.Type.RANGE, null, 0);
    
    The window window2 describes a sliding window that contains data going back indefinitely (to the beginning of the partition) and stopping at a value that is the same as the the current row. If values for the bounds are supplied that aren't 0 or null, then the OrderByClause is restricted to exactly one numeric element, so that differences may be calculated to determine the start or end of the window. Note that if a WindowClause is not supplied, then it defaults to range(, 0), i.e. "all values from the beginning of the partition through the value of the current row". Also, some AnalyticFunctions may not take a user-given window clause and may supply their own.
  • build() - This method builds an AnalyticAggregator object that can be used to perform the actual analytic operations. This method should be called last, after all of the desired "setter" methods above have been called.

Each setter method above returns the same Builder object, so that calls may be chained, e.g.

AnalyticAggregator ana = new AnalyticAggregator.Builder()
    .setAnalyticFunction(anaFunc)
    .setPartition(partition)
    .setOrderBy(orderBy)
    .setWindow(window)
    .build();

Factory Method

The AnalyticAggregator class defines a static Factory Method called getAnalytic that takes as its only argument an analytic specification string, in the format (no newlines):

ananame(property) [partitionBy(prop1[, prop2, ...])]
    [orderBy(prop1 [ASC|DESC] [NULLS [FIRST|LAST]] [, prop2 ... ]]
    [[rows|range]([start], [end])]

where "ananame" is name of the AnalyticFunction class, minus any suffix such as "Aggregator", "AnalyticAggregator", or "Analytic", and "property" is the property string normally sent to the AnalyticFunction's constructor. This method assumes the following suffixes, in order, until it finds the proper class:

  1. AnalyticAggregator - This is given the highest precedence, to allow a subclass of an Aggregator that doesn't implement AnalyticFunction to be supplied, to take precedence over a same-named Aggregator. E.g. MaxAnalyticAggregator takes precedence over MaxAggregator here.
  2. Aggregator - This is given the second highest precedence, to allow an Aggregator to implement AnalyticFunction without needing to subclass it just to provide a different name. Most built-in Aggregators are like this.
  3. Analytic - This given the lowest precedence, to permit analytic-only AnalyticFunctions to be created. Such names won't be found by Aggregator.getAggregator because they are not intended for aggregate use -- only analytic use. Most built-in AnalyticFunctions are like this.

This factory method is an alternative to directly instantiating AnalyticAggregators in code. It may return an existing, unused AnalyticAggregator that is already in the internal cache. Such a cached AnalyticAggregator would be the desired type and have the same property, partition clause, order by clause, and window clause to process.