Return-Path:
+ * This package contains
+ * These will normally be passed as parameters in constructors to classes
+ * such as {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator}
+ * to allow for customization of aggregation services.
+ *
+ * This package contains the interfaces and utilities needed to implement
+ * an aggregation service.
+ *
+ * Aggregation refers to being able to add data to a data "sink" which
+ * "aggregates" them automatically (e.g. sum them up or average, median etc).
+ *
+ * An example of an aggregation service is being able to average a series
+ * of
+ The aggregator package
+ provides a component which can be "fed" data from various sources and apply various
+ computations to this data to "aggregate" it. The design allows for a pluggable
+ implementation to be used for the purpose of aggregation and also provides flexibility
+ with regards to storing the data being fed to this component.
+ The While the store implementation stores the data in a list, the nostore one
+ stores just a single object -- every time data is fed into the
+ The data an aggregator handles can be "reset" at any point -- in the case of the
+ store implementation this means emptying the
+ Retrieving the data and regular intervals then flush/reset the aggregator was an
+ envisaged scenario for the aggregator -- so the base class
+ AbstractTimedAggregator
+ offers support to start a timer internally to do that. The class offers a listener
+ mechanism where classes can register to receive timer notifications (if timer support was configured) and after all listeners have been
+ notified the aggregator is reset.
+ The result of
+ evaluate()
+ (the result of aggregating data) is passed in to the listeners. This allows for an object
+ to simply register itself as a timer listener to the aggregator and only react to the
+ timer notifications (e.g. write the result to a file for offline analysis etc) while the
+ aggregator itself manages all the internals.
+
+ There are 2 ways the
+ AbstractTimedAggregator
+ can be configured with timer support:
+
+ It is recommended you always invoke stop()
+ at the end of the lifecycle of an aggregator -- regardless of timer support (shared /
+ per instance) or not -- in particular calling An example of usage for this component (though not necessarily the only one) could be in
+ a highly transactional system where, for instance, the average transaction time can be an
+ indication of the system health. While a fully-fledged monitoring system can say monitor
+ the system load, file system etc., you might also want your monitoring system to keep an
+ eye on the average transaction time. One way to do so is have an AbstractTimedAggregator
+ which is capturing each transaction execution time and every say 5 seconds it computes
+ the arithmetic mean (average) and writes that to a log file (which then your monitoring
+ system can tail). To do so you would use a piece of code like this:
+ Now let's assume that you occasionally see the odd spike in transaction times -- which,
+ for the purpose of this example, we'll assume is normal. As such you are not concerned with
+ these spikes, so you want a formula to exclude them. Chances are an arithmetic median
+ would be more appropriate in this case; in which case the code above can suffer just a
+ small change:
+ Or maybe you want to be more precise and ensure that lets say 95% of your transactions
+ take less than a certain execution time, so you replace the median formula with a
+ percentile one:
+ Or maybe your health indicator is the number of transactions going through the system
+ every 5 seconds. In this case you can use a nostore aggregator with a sum formula
+ like this:
+ (Bear in mind that there is also a IntCountAggregatorFunction2 too!)
+ This has the advantage of a lower memory footprint as well (see above). If your healthcheck
+ indicator is based on the maximum transaction time over a 5 seconds interval, then you simply
+ replace the aggregation function with a max value implementation:
+ Or you can simply roll out your own code -- if using the nostore implementation,
+ all you need to do is implement a
+ BinaryFunction and pass
+ it to the Aggregator constructor. This function will receive the already-stored
+ aggregated value as the first parameter, and data just passed in (via add()) as the
+ second parameter; the result of this function will be stored back in the aggregator.
+ Note on class naming : You will notice in the org.apache.commons.functor.aggregate.functions package there are functions with similar names -- e.g.
+ DoubleSumAggregatorFunction and DoubleSumAggregatorFunction2. The naming convention is that if the function takes 2
+ parameters (i.e. it is an instance of BinaryFunction then the
+ name of the class in this package will end in
+ The aggregator package
+ provides a component which can be "fed" data from various sources and apply various
+ computations to this data to "aggregate" it. The design allows for a pluggable
+ implementation to be used for the purpose of aggregation and also provides flexibility
+ with regards to storing the data being fed to this component.
+ The While the store implementation stores the data in a list, the nostore one
+ stores just a single object -- every time data is fed into the
+ The data an aggregator handles can be "reset" at any point -- in the case of the
+ store implementation this means emptying the
+ Retrieving the data and regular intervals then flush/reset the aggregator was an
+ envisaged scenario for the aggregator -- so the base class
+ AbstractTimedAggregator
+ offers support to start a timer internally to do that. The class offers a listener
+ mechanism where classes can register to receive timer notifications (if timer support was configured) and after all listeners have been
+ notified the aggregator is reset.
+ The result of
+ evaluate()
+ (the result of aggregating data) is passed in to the listeners. This allows for an object
+ to simply register itself as a timer listener to the aggregator and only react to the
+ timer notifications (e.g. write the result to a file for offline analysis etc) while the
+ aggregator itself manages all the internals.
+
+ When the data is being flushed/reset, a
+ TimedAggregatorListener
+ can be registered to receive a notification. The notification is sent after the data is reset.
+ Prior to resetting the data, evaluate()
+ is called, and the result of the evaluation is sent to the listener.
+ There are 2 ways the
+ AbstractTimedAggregator
+ can be configured with timer support:
+
+ It is recommended you always invoke stop()
+ at the end of the lifecycle of an aggregator -- regardless of timer support (shared /
+ per instance) or not -- in particular calling An example of usage for this component (though not necessarily the only one) could be in
+ a highly transactional system where, for instance, the average transaction time can be an
+ indication of the system health. While a fully-fledged monitoring system can say monitor
+ the system load, file system etc., you might also want your monitoring system to keep an
+ eye on the average transaction time. One way to do so is have an AbstractTimedAggregator
+ which is capturing each transaction execution time and every say 5 seconds it computes
+ the arithmetic mean (average) and writes that to a log file (which then your monitoring
+ system can tail). To do so you would use a piece of code like this:
+ Now let's assume that you occasionally see the odd spike in transaction times -- which,
+ for the purpose of this example, we'll assume is normal. As such you are not concerned with
+ these spikes, so you want a formula to exclude them. Chances are an arithmetic median
+ would be more appropriate in this case; in which case the code above can suffer just a
+ small change:
+ Or maybe you want to be more precise and ensure that lets say 95% of your transactions
+ take less than a certain execution time, so you replace the median formula with a
+ percentile one:
+ Or maybe your health indicator is the number of transactions going through the system
+ every 5 seconds. In this case you can use a nostore aggregator with a sum formula
+ like this:
+ (Bear in mind that there is also a
+ IntegerCountAggregatorBinaryFunction too!)
+ This has the advantage of a lower memory footprint as well (see above). If your healthcheck
+ indicator is based on the maximum transaction time over a 5 seconds interval, then you simply
+ replace the aggregation
+ function with a max value implementation:
+ Or you can simply roll out your own code -- if using the nostore implementation,
+ all you need to do is implement a
+ BinaryFunction and pass
+ it to the Aggregator
+ constructor. This function will receive the already-stored
+ aggregated value as the first parameter, and data just passed in (via add()) as the
+ second parameter; the result of this function will be stored back in the aggregator.
+ Note on class naming : You will notice in the
+ org.apache.commons.functor.aggregator.functions
+ package there are functions with similar names -- e.g.
+ DoubleSumAggregatorFunction
+ and DoubleSumAggregatorBinaryFunction.
+ The naming convention is that if the function takes 2
+ parameters (i.e. it is an instance of BinaryFunction then the
+ name of the class in this package will contain , Double> {
+ /**
+ * Does the actual adding and returns the result. Please note that caller is
+ * responsible for synchronizing access to the list.
+ *
+ * @param data
+ * List to traverse and sum
+ * @return arithmetic sum of all the data in the list or null if the list is
+ * empty.
+ */
+ public Double evaluate(List
left
by one and returns it.
+ *
+ * @param left
+ * Value to be incremented by 1 and returned. If
+ * null
, null
is returned.
+ * @param right
+ * ignored
+ * @return left + 1
if left != null
otherwise it
+ * returns null
.
+ */
+ public Integer evaluate(Integer left, Integer right) {
+ if (left == null) {
+ return null;
+ }
+ return left + 1;
+ }
+
+ @Override
+ public String toString() {
+ return IntegerCountAggregatorBinaryFunction.class.getName();
+ }
+}
Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerCountAggregatorBinaryFunction.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerCountAggregatorBinaryFunction.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerCountAggregatorBinaryFunction.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java Thu May 31 14:56:47 2012
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.commons.functor.aggregator.functions;
+
+import org.apache.commons.functor.BinaryFunction;
+
+/**
+ * Aggregation function to be used with subclasses of
+ * {@link org.apache.commons.functor.aggregator.AbstractNoStoreAggregator} which
+ * finds the maximum of 2 ints.
+ */
+public class IntegerMaxAggregatorBinaryFunction implements BinaryFunctionnull
, then
+ * right
will be returned.
+ * @param right
+ * second number to add. If null
, then
+ * left
will be returned.
+ * @return max of the 2 integers as described above
+ */
+ public Integer evaluate(Integer left, Integer right) {
+ if (left == null) {
+ return right;
+ }
+ if (right == null) {
+ return left;
+ }
+ if (left.intValue() < right.intValue()) {
+ return right;
+ }
+ return left;
+ }
+
+ @Override
+ public String toString() {
+ return IntegerMaxAggregatorBinaryFunction.class.getName();
+ }
+}
Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorBinaryFunction.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorFunction.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorFunction.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorFunction.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerMaxAggregatorFunction.java Thu May 31 14:56:47 2012
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.commons.functor.aggregator.functions;
+
+import java.util.List;
+
+import org.apache.commons.functor.UnaryFunction;
+
+/**
+ * Aggregator function to be used with subclasses of
+ * {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator}
+ * which finds the maximum number in a list. It does this by traversing the list
+ * (once) -- so the complexity of this will be O(n).
+ */
+public class IntegerMaxAggregatorFunction implements UnaryFunction, Integer> {
+ /**
+ * Does the actual traversal of the list and finds the maximum value then
+ * returns the result. Please note that caller is responsible for
+ * synchronizing access to the list.
+ *
+ * @param data
+ * List to traverse and find max
+ * @return max number in the list or null if the list is empty.
+ */
+ public Integer evaluate(List
, Integer> {
+ /**
+ * Does the actual computation and returns the result. Please note that
+ * caller is responsible for synchronizing access to the list.
+ *
+ * @param data
+ * List to traverse and sum
+ * @return arithmetic mean (average) of all the data in the list or null if
+ * the list is empty.
+ */
+ public Integer evaluate(List
, Integer> {
+ /**
+ * Flag to indicate whether we are going to operate on a copy of the list
+ * given or not. In order to compute the median, we need to sort the list
+ * first (and then choose the item in the middle). This function offers 2
+ * ways of doing the sorting:
+ *
+ *
+ * NOTE: While using a copy ensures the original list is untouched, it does
+ * mean we are creating a temporary list for the purpose of this computation
+ * so it will have an impact on memory!
+ */
+ private boolean useCopy;
+
+ /**
+ * By default create a function which will operate on a copy of the original
+ * list ({@link #useCopy} = true).
+ *
+ * @see #useCopy
+ */
+ public IntegerMedianValueAggregatorFunction() {
+ this(true);
+ }
+
+ /**
+ * Constructor which allows the caller to specify whether to operate on the
+ * original list or a copy of it.
+ *
+ * @param useCopy
+ * Set to true to operate on a copy of the list or false to
+ * operate on the original list.
+ * @see #useCopy
+ */
+ public IntegerMedianValueAggregatorFunction(boolean useCopy) {
+ this.useCopy = useCopy;
+ }
+
+ /**
+ * Getter for {@link #useCopy}.
+ *
+ * @return Current value of {@link #useCopy}.
+ * @see #useCopy
+ */
+ public boolean isUseCopy() {
+ return useCopy;
+ }
+
+ /**
+ * Sorts the given list and chooses the median value. The sorting can be
+ * carried out against the original list or a copy of it, based on the value
+ * of {@link #useCopy}.
+ *
+ * @param data
+ * List to compute the median value for
+ * @return the median value of the given list or useCopy=false
)
+ * useCopy=true
)null
if the
+ * list is null
or empty.
+ */
+ public Integer evaluate(Listn = round((P / 100) * N + 0.5)
where N is the
+ * number of items in a list.
+ */
+public class IntegerPercentileAggregatorFunction implements UnaryFunction, Integer> {
+ /** A percentile goes from 0 to 100% and that's it. */
+ private static final double MAX_PERCENTAGE = 100.0;
+ /**
+ * Percentile value to calculate. 0 < percentile <= 100
+ */
+ private double percentile;
+
+ /**
+ * Flag to indicate whether we are going to operate on a copy of the list
+ * given or not. In order to compute the percentile, we need to sort the
+ * list first (and then choose the item based on the formula given above).
+ * This function offers 2 ways of doing the sorting:
+ *
+ *
+ * NOTE: While using a copy ensures the original list is untouched, it does
+ * mean we are creating a temporary list for the purpose of this computation
+ * so it will have an impact on memory!
+ */
+ private boolean useCopy;
+
+ /**
+ * Similar to {@link #IntegerPercentileAggregatorFunction(double, boolean)
+ * IntPercentilAggregatorFunction(percentile,true)}.
+ *
+ * @param percentile
+ * Percentile this function will return the value for
+ */
+ public IntegerPercentileAggregatorFunction(double percentile) {
+ this(percentile, true);
+ }
+
+ /**
+ * Initializes the function with the given percentile and decides whether
+ * the function will modify the original list or not.
+ *
+ * @param percentile
+ * Percentile this function will return the value for
+ * @param useCopy
+ * If set to true, the original list will not be modified and
+ * will contain the data in sorted order, if false, this instance
+ * will operate on a copy of the list
+ */
+ public IntegerPercentileAggregatorFunction(double percentile, boolean useCopy) {
+ if (percentile < 0.0 || percentile > MAX_PERCENTAGE) {
+ throw new IllegalArgumentException("Invalid value for percentile: " + percentile);
+ }
+ this.percentile = percentile;
+ this.useCopy = useCopy;
+ }
+
+ /**
+ * Used internally to compute the rank of the item in the list for the
+ * requested percentile. This is invoked internally from
+ * {@link #evaluate(List)}.
+ *
+ * @param data
+ * List containing data. This cannot be useCopy=false
)
+ * useCopy=true
)null
(throws
+ * NullPointerException
) or empty (throws
+ * ArrayIndexOutOfBoundsException
).
+ * @return Index of the item for the requested percentile
+ * @see #getPercentile()
+ */
+ final int computeRank(Listnull
+ * or empty (zero size).
+ */
+ public Integer evaluate(Listnull
, then
+ * right
will be returned.
+ * @param right
+ * second number to add. If null
, then
+ * left
will be returned.
+ * @return sum of the 2 int's as described above
+ */
+ public Integer evaluate(Integer left, Integer right) {
+ if (left == null) {
+ return right;
+ }
+ if (right == null) {
+ return left;
+ }
+ return left + right;
+ }
+
+ @Override
+ public String toString() {
+ return IntegerSumAggregatorBinaryFunction.class.getName();
+ }
+}
Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorBinaryFunction.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorBinaryFunction.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorBinaryFunction.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorFunction.java
URL: http://svn.apache.org/viewvc/commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorFunction.java?rev=1344757&view=auto
==============================================================================
--- commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorFunction.java (added)
+++ commons/proper/functor/trunk/src/main/java/org/apache/commons/functor/aggregator/functions/IntegerSumAggregatorFunction.java Thu May 31 14:56:47 2012
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.commons.functor.aggregator.functions;
+
+import java.util.List;
+
+import org.apache.commons.functor.UnaryFunction;
+
+/**
+ * Aggregator function to be used with subclasses of
+ * {@link org.apache.commons.functor.aggregator.AbstractListBackedAggregator}
+ * which sums up all the numbers in the list.
+ */
+public final class IntegerSumAggregatorFunction implements UnaryFunction, Integer> {
+ /**
+ * Does the actual adding and returns the result. Please note that caller is
+ * responsible for synchronizing access to the list.
+ *
+ * @param data
+ * List to traverse and sum
+ * @return arithmetic sum of all the data in the list or null if the list is
+ * empty.
+ */
+ public Integer evaluate(List
UnaryFunction
's used by aggregators
+ * defined in org.apache.commons.functor.aggregator
.
+ * int
values (perhaps generated from a monitoring component)
+ * and be able to constantly report on the average (or mean) value of
+ * this series. There is no specification about the maximum amount of data that
+ * can be aggregated -- some subclasses might impose such restrictions,
+ * if that is the case then that will be specified in their JavaDoc's.
+ *
+ There are 2 implementations as far as storage is concerned : nostore and
+ ArrayList
-backed store. The former should be used when the aggregation
+ formula is simple enough to be applied on-the-fly without having to traverse a series
+ of data -- e.g. summarizing / adding the data (TODO need more explanation).
+ ArrayList
-backed store implementation stores the whole data series in a
+ growing ArrayList
such that when data is aggregated one can traverse the
+ series and apply complex formulas (find the median of a set of numeric values for instance).
+ Aggregator
,
+ the data stored in this object and the data
+ passed in
+ are "aggregated" there and then using the supplied formula and the result of this operation
+ is stored back in the object this implementation uses to store data.
+
+ This has the implication that unlike the list-backed storage implementation (where the
+ result of aggregating the data is not known until evaluate()
+ is called) with the nostore implementation the result is known (and saved back) at
+ any moment. This arguably makes this class "faster", however this comes at the cost of a
+ slower add()
+ operation, as the aggregation formula is applied. Also, let's remind ourselves that not all
+ formulas can be implemented using the nostore implementation (see above).
+ ArrayList
; in the case
+ of nostore this means setting the "start value" to a "neutral" value -- for
+ instance 0 for implementations which involve additions (Y + 0 = Y
), 1 for
+ multiplication (Y * 1 = Y
) etc. This operation ultimately resets the
+ aggregator to the initial state it was in when created in the first place. This feature
+ allows for a caller to schedule regular resets to free up resources etc.
+
+
+ Timer
object internally and schedule the regular task of resetting the
+ aggregator under this Timer
. While this helps preventing memory leaks
+ (both Aggregator
and Timer
will be recycled together) it
+ does increase the threading level in the system with each aggregator object created.
+ If your system creates a lot of AbstractTimedAggregator
instances with
+ timer support, you might want to consider using the shared timer (see below).stop()
on an aggregator with
+ no timer support has no effect, however doing so ensures code uniformity and cleanliness.
+
+ For the list-based aggregators, use an instance of AbstractListBackedAggregator and pass in an instance of UnaryFunction
+ which accepts a List
and returns a single object.
+
+ Have a look at the
+ org.apache.commons.functor.aggregate.functions package which includes a set of functions to achieve
+ various of these tasks already.
+ 2
, otherwise, if it is an instance
+ of UnaryFunction then the
+ name will not end in a 2
.
+ The reason behind it is that instances of BinaryFunction
can be used with
+ AbstractNoStoreAggregator whereas the instances of UnaryFunction
can be used
+ with AbstractTimedAggregator.
+
+ There are 2 implementations as far as storage is concerned : nostore and
+ List
-backed store. The former should be used when the aggregation
+ formula is simple enough to be applied on-the-fly without having to traverse a series
+ of data -- e.g. summarizing / adding the data -- while the latter can perform more advanced processing -- e.g.
+ statistical calculations: median, average, percentile etc.
+ List
-backed store implementation stores the whole data series in a
+ growing List
such that when data is aggregated one can traverse the
+ series and apply complex formulas (find the median of a set of numeric values for instance).
+
+ The framework allows for any List
-based implementation to be plugged in, by
+ implementing createList(),
+ however, there is also an ArrayList
-based implementation provided in
+ ArrayListBackedAggregator
+ which can be used out-of-the-box.
+ Aggregator
,
+ the data stored in this object and the data
+ passed in
+ are "aggregated" there and then using the supplied
+ formula and the result of this operation
+ is stored back in the object this implementation uses to store data.
+
+ This has the implication that unlike the list-backed storage implementation (where the
+ result of aggregating the data is not known until evaluate()
+ is called), with the nostore implementation the result is known (and saved back) at
+ any moment. This arguably makes this class "faster", however this comes at the cost of a
+ slower add()
+ operation, as the aggregation formula is applied. Also, let's remind ourselves that not all
+ formulas can be implemented using the nostore implementation (see above).
+ List
; in the case
+ of nostore this means setting the "start value" to a "neutral" value -- for
+ instance 0 for implementations which involve additions (Y + 0 = Y
), 1 for
+ multiplication (Y * 1 = Y
) etc. This operation ultimately resets the
+ aggregator to the initial state it was in when created in the first place. This feature
+ allows for a caller to schedule regular resets to free up resources etc.
+
+ This allows for data aggregated periodically to be processed (e.g. logged, written into a database etc) without
+ worrying about what happens in between.
+
+
+ Timer
object internally and schedule the regular task of resetting the
+ aggregator under this Timer
. While this helps preventing memory leaks
+ (both Aggregator
and Timer
will be recycled together) it
+ does increase the threading level in the system with each aggregator object created.
+ If your system creates a lot of AbstractTimedAggregator
instances with
+ timer support, you might want to consider using the shared timer (see below).stop()
on an aggregator with
+ no timer support has no effect, however doing so ensures code uniformity and cleanliness.
+
+ For the list-based aggregators, use an instance of
+ AbstractListBackedAggregator
+ and pass in an instance of UnaryFunction
+ which accepts a List
and returns a single object.
+
+ Have a look at the
+ org.apache.commons.functor.aggregator.functions
+ package which includes a set of functions to achieve various of these tasks already.
+ BinaryFunction
, otherwise, if it is an instance
+ of UnaryFunction then the
+ name will only contain Function
.
+ The reason behind it is that instances of BinaryFunction
can be used with
+ AbstractNoStoreAggregator
+ whereas the instances of UnaryFunction
can be used
+ with AbstractTimedAggregator.
+
+ There are some code snippets / examples for the org.apache.commons.functor.aggregator
package
+ available on this page. Also, to exemplify the usage of the Aggregator
+ classes, there are code examples in the test section.
+
+ First such set of example involves the usage of the nostore Aggregator
. Code can be found in
+ org.apache.commons.functor.example.aggregator.nostore.
+ This shows how can you use an aggregator which doesn't store the data series and processes them on the fly.
+ Also, there are examples provided which show how can you implement your own aggregation function
+ to be used with this Aggregator
type.
+
+ For using an Aggregator
which stores the data series in a list, examples are in
+ org.apache.commons.functor.example.aggregator.list.
+ This shows how can you use the ArrayList
-backed aggregator or provide your own List
-based implementation.
+ Also, there are examples provided which show how can you implement your own aggregation function
+ to be used with this Aggregator
type.
+