262 lines
8.0 KiB
Markdown
262 lines
8.0 KiB
Markdown
---
|
|
title: Create custom aggregate functions
|
|
description: Create your own custom aggregate functions in Flux using the `reduce()` function.
|
|
v2.0/tags: [functions, custom, flux, aggregates]
|
|
menu:
|
|
v2_0:
|
|
name: Custom aggregate functions
|
|
parent: Create custom functions
|
|
weight: 301
|
|
---
|
|
|
|
To aggregate your data, use the Flux
|
|
[built-in aggregate functions](/v2.0/reference/flux/functions/built-in/transformations/aggregates/)
|
|
or create custom aggregate functions using the
|
|
[`reduce()`function](/v2.0/reference/flux/functions/built-in/transformations/aggregates/reduce/).
|
|
|
|
## Aggregate function characteristics
|
|
Aggregate functions all have the same basic characteristics:
|
|
|
|
- They operate on individual input tables and transform all records into a single record.
|
|
- The output table has the same [group key](/v2.0/query-data/get-started/#group-keys) as the input table.
|
|
|
|
## How reduce() works
|
|
The `reduce()` function operates on one row at a time using the function defined in
|
|
the [`fn` parameter](/v2.0/reference/flux/functions/built-in/transformations/aggregates/reduce/#fn).
|
|
The `fn` function maps keys to specific values using two [objects](/v2.0/query-data/get-started/syntax-basics/#objects)
|
|
specified by the following parameters:
|
|
|
|
| Parameter | Description |
|
|
|:---------: |:----------- |
|
|
| `r` | An object that represents the row or record. |
|
|
| `accumulator` | An object that contains values used in each row's aggregate calculation. |
|
|
|
|
{{% note %}}
|
|
The `reduce()` function's [`identity` parameter](/v2.0/reference/flux/functions/built-in/transformations/aggregates/reduce/#identity)
|
|
defines the initial `accumulator` object.
|
|
{{% /note %}}
|
|
|
|
### Example reduce() function
|
|
The following example `reduce()` function produces a sum and product of all values
|
|
in an input table.
|
|
|
|
```js
|
|
|> reduce(fn: (r, accumulator) => ({
|
|
sum: r._value + accumulator.sum,
|
|
product: r._value * accumulator.product
|
|
})
|
|
identity: {sum: 0.0, product: 1.0}
|
|
)
|
|
```
|
|
|
|
{{% note %}}
|
|
To preserve existing columns, [use the `with` operator](/v2.0/reference/flux/functions/built-in/transformations/aggregates/reduce/#preserve-columns)
|
|
when mapping values in the `r` object.
|
|
{{% /note %}}
|
|
|
|
To illustrate how this function works, take this simplified table for example:
|
|
|
|
```txt
|
|
_time _value
|
|
----------------------- -------
|
|
2019-04-23T16:10:49.00Z 1.6
|
|
2019-04-23T16:10:59.00Z 2.3
|
|
2019-04-23T16:11:09.00Z 0.7
|
|
2019-04-23T16:11:19.00Z 1.2
|
|
2019-04-23T16:11:29.00Z 3.8
|
|
```
|
|
|
|
###### Input objects
|
|
The `fn` function uses the data in the first row to define the `r` object.
|
|
It defines the `accumulator` object using the `identity` parameter.
|
|
|
|
```js
|
|
r = { _time: 2019-04-23T16:10:49.00Z, _value: 1.6 }
|
|
accumulator = { sum : 0.0, product : 1.0 }
|
|
```
|
|
|
|
###### Key mappings
|
|
It then uses the `r` and `accumulator` objects to populate values in the key mappings:
|
|
```js
|
|
// sum: r._value + accumulator.sum
|
|
sum: 1.6 + 0.0
|
|
|
|
// product: r._value * accumulator.product
|
|
product: 1.6 * 1.0
|
|
```
|
|
|
|
###### Output object
|
|
This produces an output object with the following key value pairs:
|
|
|
|
```js
|
|
{ sum: 1.6, product: 1.6 }
|
|
```
|
|
|
|
The function then processes the next row using this **output object** as the `accumulator`.
|
|
|
|
{{% note %}}
|
|
Because `reduce()` uses the output object as the `accumulator` when processing the next row,
|
|
keys mapped in the `fn` function must match keys in the `identity` and `accumulator` objects.
|
|
{{% /note %}}
|
|
|
|
###### Processing the next row
|
|
```js
|
|
// Input objects for the second row
|
|
r = { _time: 2019-04-23T16:10:59.00Z, _value: 2.3 }
|
|
accumulator = { sum : 1.6, product : 1.6 }
|
|
|
|
// Key mappings for the second row
|
|
sum: 2.3 + 1.6
|
|
product: 2.3 * 1.6
|
|
|
|
// Output object of the second row
|
|
{ sum: 3.9, product: 3.68 }
|
|
```
|
|
|
|
It then uses the new output object as the `accumulator` for the next row.
|
|
This cycle continues until all rows in the table are processed.
|
|
|
|
##### Final output object and table
|
|
After all records in the table are processed, `reduce()` uses the final output object
|
|
to create a transformed table with one row and columns for each mapped key.
|
|
|
|
```js
|
|
// Final output object
|
|
{ sum: 9.6, product: 11.74656 }
|
|
|
|
// Output table
|
|
sum product
|
|
---- ---------
|
|
9.6 11.74656
|
|
```
|
|
|
|
{{% note %}}
|
|
#### What happened to the \_time column?
|
|
The `reduce()` function only keeps columns that are:
|
|
|
|
1. Are part of the input table's [group key](/v2.0/query-data/get-started/#group-keys).
|
|
2. Explicitly mapped in the `fn` function.
|
|
|
|
It drops all other columns.
|
|
Because `_time` is not part of the group key and is not mapped in the `fn` function,
|
|
it isn't included in the output table.
|
|
{{% /note %}}
|
|
|
|
## Custom aggregate function examples
|
|
To create custom aggregate functions, use principles outlined in
|
|
[Creating custom functions](/v2.0/query-data/guides/custom-functions)
|
|
and the `reduce()` function to aggregate rows in each input table.
|
|
|
|
### Create a custom average function
|
|
This example illustrates how to create a function that averages values in a table.
|
|
_This is meant for demonstration purposes only.
|
|
The built-in [`mean()` function](/v2.0/reference/flux/functions/built-in/transformations/aggregates/mean/)
|
|
does the same thing and is much more performant._
|
|
|
|
{{< code-tabs-wrapper >}}
|
|
{{% code-tabs %}}
|
|
[Comments](#)
|
|
[No Comments](#)
|
|
{{% /code-tabs %}}
|
|
|
|
{{% code-tab-content %}}
|
|
|
|
```js
|
|
average = (tables=<-, outputField="average") =>
|
|
tables
|
|
|> reduce(
|
|
// Define the initial accumulator object
|
|
identity: {
|
|
count: 1.0,
|
|
sum: 0.0,
|
|
avg: 0.0
|
|
}
|
|
fn: (r, accumulator) => ({
|
|
// Increment the counter on each reduce loop
|
|
count: accumulator.count + 1.0,
|
|
// Add the _value to the existing sum
|
|
sum: accumulator.sum + r._value,
|
|
// Divide the existing sum by the existing count for a new average
|
|
avg: accumulator.sum / accumulator.count
|
|
})
|
|
)
|
|
// Drop the sum and the count columns since they are no longer needed
|
|
|> drop(columns: ["sum", "count"])
|
|
// Set the _field column of the output table to to the value
|
|
// provided in the outputField parameter
|
|
|> set(key: "_field", value: outputField)
|
|
// Rename avg column to _value
|
|
|> rename(columns: {avg: "_value"})
|
|
```
|
|
{{% /code-tab-content %}}
|
|
|
|
{{% code-tab-content %}}
|
|
```js
|
|
average = (tables=<-, outputField="average") =>
|
|
tables
|
|
|> reduce(
|
|
identity: {
|
|
count: 1.0,
|
|
sum: 0.0,
|
|
avg: 0.0
|
|
}
|
|
fn: (r, accumulator) => ({
|
|
count: accumulator.count + 1.0,
|
|
sum: accumulator.sum + r._value,
|
|
avg: accumulator.sum / accumulator.count
|
|
})
|
|
)
|
|
|> drop(columns: ["sum", "count"])
|
|
|> set(key: "_field", value: outputField)
|
|
|> rename(columns: {avg: "_value"})
|
|
```
|
|
{{% /code-tab-content %}}
|
|
{{< /code-tabs-wrapper >}}
|
|
|
|
### Aggregate multiple columns
|
|
Built-in aggregate functions only operate on one column.
|
|
Use `reduce()` to create a custom aggregate function that aggregates multiple columns.
|
|
|
|
The following function expects input tables to have `c1_value` and `c2_value`
|
|
columns and generates an average for each.
|
|
|
|
```js
|
|
multiAvg = (tables=<-) =>
|
|
tables
|
|
|> reduce(
|
|
identity: {
|
|
count: 1.0,
|
|
c1_sum: 0.0,
|
|
c1_avg: 0.0,
|
|
c2_sum: 0.0,
|
|
c2_avg: 0.0
|
|
}
|
|
fn: (r, accumulator) => ({
|
|
count: accumulator.count + 1.0,
|
|
c1_sum: accumulator.c1_sum + r.c1_value,
|
|
c1_avg: accumulator.c1_sum / accumulator.count,
|
|
c2_sum: accumulator.c2_sum + r.c2_value,
|
|
c2_avg: accumulator.c2_sum / accumulator.count
|
|
})
|
|
)
|
|
```
|
|
|
|
### Aggregate gross and net profit
|
|
Use `reduce()` to create a function that aggregates gross and net profit.
|
|
This example expects `profit` and `expenses` columns in the input tables.
|
|
|
|
```js
|
|
profitSummary = (tables=<-) =>
|
|
tables
|
|
|> reduce(
|
|
identity: {
|
|
gross: 0.0,
|
|
net: 0.0
|
|
}
|
|
fn: (r, accumulator) => ({
|
|
gross: accumulator.gross + r.profit,
|
|
net: accumulator.net + r.profit - r.expenses
|
|
})
|
|
)
|
|
```
|