public interface UserDefinedAggregationFunctionAdapterFactory
UserDefinedAggregationFunctionAdapter
for
a given aggregation function call.
When a query string with a reference to a user-defined aggregation function is translated into an executable query, the
parser first looks-up the aggregation function factory for the given function identifier and calls
getSignature(FieldMetaData[], JavaTypes.Type[], Object[])
to determine, whether or not that factory can provide an aggregation function adapter for the given input
parameters. If this check fails, the whole query is already rejected by the query parser.
If however the check succeeded the query translator later on uses the same factory and calls
createInstance(FieldMetaData[], JavaTypes.Type[], Object[])
to actually create an instance of a suitable UserDefinedAggregationFunctionAdapter
.
Some aggregation functions may be optimized for Sliding Window Aggregations (see UserDefinedAggregationFunctionAdapter.supportsPN()
). If this
factory creates such aggregation function adapter instances its supportsPN()
method
shall return true
.
Registration of a UserDefinedAggregationFunctionAdapterFactory
at the engine bears the following advantages over
registration of a UserDefinedAggregationFunctionAdapter
:
getAggregateType()
, e.g.
AVG(Type.DOUBLE value) -> Type.DOUBLE,
AVG(Type.BIGDECIMAL value) -> Type.BIGDECIMAL,
UserDefinedAggregationFunctionAdapterFactory
may also take static instantiation parameters into account.
The values of such parameters are constant and are already present at parse time (see UserDefinedFunctionAdapterFactory
documentation for an example).
Average
aggregation function which may be called with any numeric input type.
It would have been sufficient if the aggregation function was only provided through a single adapter accepting the most general numeric type,
which is BigDecimal. As however BigDecimal arithmetics is by far more computationally expensive, the factory overloads the function and provides
an adapter which employs simple double arithmetics and accepts any numeric input parameter type except for BigDecimal. For the sake of completeness
the factory additionally provides an adapter accepting input parameters of type BigDecimal.
The adapter implementations can be found at the end of the class. Beforehand, the getSignature(FieldMetaData[], Type[], Object[])
checks
whether there is exactly one input parameter given and if this parameter is of a numeric type. Based on this type it then chooses the correct
signature for the aggregation function. Note: The parser will check if the returned signature is compatible with the actual parameters and
otherwise reject it.
Finally, createInstance(FieldMetaData[], Type[], Object[])
instantiates either a BigDecimalAverageAdapter
or a AverageAdapter
.
public class AverageAggregationFunctionFactory implements UserDefinedAggregationFunctionAdapterFactory {@Override
public Signature getSignature(FieldMetaData[] parameterMetaData, Type[] instantiationParameterTypes, Object[] instantiationParameters) throws UserDefinedAggregationFunctionException { if (parameterMetaData.length != 1) throw new UserDefinedAggregationFunctionException("The AverageAggregationFunction expects exactly 1 numeric input parameter."); Type inputType = parameterMetaData[0].getJavaType(); if (JavaTypes.isNumericType(inputType)) { if (Type.BIG_DECIMAL.equals(inputType)) return new DefaultSignature(Type.BIG_DECIMAL, new Type[] {Type.BIG_DECIMAL}); else return new DefaultSignature(Type.DOUBLE, new Type[] {Type.DOUBLE}); } throw new UserDefinedAggregationFunctionException("Unable to create an aggregation factory instance for input types " + Arrays.toString(FieldMetaDatas.getJavaTypes(parameterMetaData))); }@Override
public UserDefinedAggregationFunctionAdapter extends Serializable> createInstance(FieldMetaData[] parameterMetaData, Type[] instantiationParameterTypes, Object[] instantiationParameters) { if (parameterMetaData.length != 1) throw new IllegalArgumentException("The AverageAggregationFunction expects exactly 1 numeric input parameter."); Type inputType = parameterMetaData[0].getJavaType(); if (JavaTypes.isNumericType(inputType)) { if (Type.BIG_DECIMAL.equals(inputType)) return new BigDecimalAverageAdapter(); else return new AverageAdapter(); } throw new IllegalArgumentException("Unable to create an aggregation factory instance for input types " + Arrays.toString(FieldMetaDatas.getJavaTypes(parameterMetaData))); }@Override
public boolean supportsPN() { return true; } private static class AverageAdapter implements UserDefinedAggregationFunctionAdapter{ @Override
public Type[] getParameterTypes() { return new Type[] {Type.DOUBLE}; }@Override
public Type getAggregateType() { return Type.DOUBLE; }@Override
public Number[] createInitialState() { // the first value is the count and the second the cumulative sum return new Number[] {0l, 0d}; }@Override
public Number[] aggregate(Number[] state, Serializable[] values) { Long n = (Long) state[0]; Double sum = (Double) state[1]; // null-aware handling of input values if (values[0] != null) { sum += (Double) values[0]; n += 1; } // always return a new state return new Number[] {n, sum}; }@Override
public Object getAggregate(Number[] state) { long n = (Long) state[0]; double sum = (Double) state[1]; // the average of an empty data set is null if (n == 0l) return null; return sum/n; }@Override
public Number[] negativeCall(Number[] state, Serializable[] values) { if (values[0] == null) return state; long n = (Long) state[0]; double sum = (Double) state[1]; n--; sum -= (Double) values[0]; // always return a new state return new Number[] {n, sum}; }@Override
public boolean supportsPN() { return true; }@Override
public boolean isEmptyAggregate(Number[] state) { if ((Long) state[0] == 0) return true; return false; } } private static class BigDecimalAverageAdapter implements UserDefinedAggregationFunctionAdapter{ @Override
public Type[] getParameterTypes() { return new Type[] {Type.BIG_DECIMAL}; }@Override
public Type getAggregateType() { return Type.BIG_DECIMAL; }@Override
public Number[] createInitialState() { // the first value is the count and the second the cumulative sum return new Number[] {0L, BigDecimal.ZERO}; }@Override
public Number[] aggregate(Number[] state, Serializable[] values) { Long n = (Long) state[0]; BigDecimal sum = (BigDecimal) state[1]; // null-aware handling of input values if (values[0] != null) { sum = sum.add((BigDecimal) values[0]); n += 1; } // always return a new state return new Number[] {n, sum}; }@Override
public Object getAggregate(Number[] state) { long n = (Long) state[0]; BigDecimal sum = (BigDecimal) state[1]; // the average of an empty data set is null if (n == 0l) return null; return sum.divide(BigDecimal.valueOf(n)); }@Override
public Number[] negativeCall(Number[] state, Serializable[] values) { if (values[0] == null) return state; long n = (Long) state[0]; BigDecimal sum = (BigDecimal) state[1]; n--; sum = sum.subtract((BigDecimal) values[0]); // always return a new state return new Number[] {n, sum}; }@Override
public boolean supportsPN() { return true; }@Override
public boolean isEmptyAggregate(Number[] state) { if ((Long) state[0] == 0) return true; return false; } } }
Modifier and Type | Method and Description |
---|---|
UserDefinedAggregationFunctionAdapter<? extends Serializable> |
createInstance(FieldMetaData[] parameterMetaData,
JavaTypes.Type[] instantiationParameterTypes,
Object[] instantiationParameters)
Instantiates a
UserDefinedAggregationFunctionAdapter for the given runtime parameter types and instantiation parameters. |
Signature |
getSignature(FieldMetaData[] parameterMetaData,
JavaTypes.Type[] instantiationParameterTypes,
Object[] instantiationParameters)
Determines, whether or not this factory is able to instantiate a
UserDefinedAggregationFunctionAdapter for
the given runtime parameter types and the additional instantiation parameter types and values. |
boolean |
supportsPN()
Determines, whether or not adapters created by this factory implement the methods
UserDefinedAggregationFunctionAdapter.negativeCall(Serializable, Serializable[]) and
UserDefinedAggregationFunctionAdapter.isEmptyAggregate(Serializable) and hence
can be used for queries running in Approach#PN approach. |
Signature getSignature(FieldMetaData[] parameterMetaData, JavaTypes.Type[] instantiationParameterTypes, Object[] instantiationParameters) throws UserDefinedAggregationFunctionException
UserDefinedAggregationFunctionAdapter
for
the given runtime parameter types and the additional instantiation parameter types and values. If an
adapter could be instantiated, the exact Signature
of this aggregation function adapter is returned, otherwise
an UserDefinedAggregationFunctionAdapter
is thrown.
UserDefinedAggregationFunctionAdapter.aggregate(Serializable, Serializable[])
method. Besides the parameter
type, the FieldMetaData
object corresponding to each runtime parameter offers additional information, e.g.
the name of the parameter or flags describing the "null-ability" and case-sensitivity of the parameter.
createInstance(FieldMetaData[], JavaTypes.Type[], Object[])
method so that the concrete adapter instance can be created depending on those instantiation parameters. Their types
and values are also given to getSignature(FieldMetaData[], JavaTypes.Type[], Object[])
so
that the decision, whether or not an adapter could be instantiated, can also take those information into account.parameterMetaData
- An array of FieldMetaData
objects describing the runtime parameters that the
adapter should be able to acceptinstantiationParameterTypes
- The instantiation parameter types that a matching aggregation function adapter is to be
searched forinstantiationParameters
- The actual values of the instantiation parametersSignature
object describing the actual parameters types, instantiation parameter types and the return
type of the adapter that this factory would return for the given arguments.
UserDefinedAggregationFunctionException
- if this factory would not be able to instantiate a UserDefinedAggregationFunctionAdapter
for the given argumentsUserDefinedAggregationFunctionAdapter<? extends Serializable> createInstance(FieldMetaData[] parameterMetaData, JavaTypes.Type[] instantiationParameterTypes, Object[] instantiationParameters)
UserDefinedAggregationFunctionAdapter
for the given runtime parameter types and instantiation parameters.
If getSignature(FieldMetaData[], JavaTypes.Type[], Object[])
did not throw an UserDefinedAggregationFunctionException
, calling createInstance()
with the same arguments
shall succeed and return a valid adapter.
getSignature(FieldMetaData[], JavaTypes.Type[], Object[])
failed with an
UserDefinedAggregationFunctionException
, createInstance()
will equally fail with a corresponding
RuntimeException
.parameterMetaData
- An array of FieldMetaData
objects describing the runtime parameters that the
adapter should be able to acceptinstantiationParameterTypes
- The instantiation parameter typesinstantiationParameters
- The actual values of the instantiation parametersUserDefinedAggregationFunctionAdapter
objectboolean supportsPN()
UserDefinedAggregationFunctionAdapter.negativeCall(Serializable, Serializable[])
and
UserDefinedAggregationFunctionAdapter.isEmptyAggregate(Serializable)
and hence
can be used for queries running in Approach#PN
approach.