Create a custom aggregation(创建自定义聚合(custom aggregation))¶
Functions can be used to compute custom aggregations based on data in the ontology, which can then be surfaced in a chart widget in Workshop. This guide walks through how to write custom aggregation logic that loads aggregated data from the ontology, manipulates the results to create a projection of future results, and returns the modified results.
These references may be useful while working through this section:
- Reference for Object Set aggregations
- Reference for aggregation types
Loading an aggregation¶
In this example, assume you have an ontology consisting of expenses, with each expense object having properties for department name, expense date, and expense amount. If you want to estimate the monthly spend by department over the next six months, you can begin by loading the aggregated data for the monthly spend:
const result = await Objects.search()
.expenses()
.groupBy(expense => expense.departmentName.topValues())
.segmentBy(expense => expense.date.byMonth())
.sum(expense => expense.amount);
Manipulating aggregation results¶
Next, you can extrapolate the spend for each department for the next six months. For this example, you can take a simple approach of using the final month's value as the estimate for the next six months.
const modifiedBuckets = result.buckets.map(bucket => {
// Find the bucket corresponding to the most recent month
const lastBucket = bucket.value[bucket.value.length - 1];
let nextSixMonths: IBaseBucket<IRange<Timestamp>, Double>[] = [];
let currentMonth = lastBucket.key.max!;
// Loop six times
for (let i = 0; i < 6; i++) {
// Find the end of this range (the following month)
const nextMonth = currentMonth.plusMonths(1);
// Add a new bucket which uses the next month as the date range
// and the most recent month as the value
nextSixMonths.push({
key: {
min: currentMonth,
max: nextMonth,
},
value: lastBucket.value,
});
currentMonth = nextMonth;
}
// Return the modified results
return { key: bucket.key, value: nextSixMonths };
});
Returning the aggregation¶
Now that you have created an estimate for the next six months, you can return these estimated values:
return { buckets: modifiedBuckets };
The full example code for this function is as follows:
@Function()
public async estimatedDepartmentExpenses(): Promise<ThreeDimensionalAggregation<string, IRange<Timestamp>>> {
const result = await Objects.search()
.expenses()
.groupBy(expense => expense.departmentName.topValues())
.segmentBy(expense => expense.date.byMonths())
.sum(expense => expense.amount);
const modifiedBuckets = result.buckets.map(bucket => {
// Find the bucket corresponding to the most recent month
const lastBucket = bucket.value[bucket.value.length - 1];
let nextSixMonths: IBaseBucket<IRange<Timestamp>, Double>[] = [];
let currentMonth = lastBucket.key.max!;
// Loop six times
for (let i = 0; i < 6; i++) {
// Find the end of this range (the following month)
const nextMonth = currentMonth.plusMonths(1);
// Add a new bucket which uses the next month as the date range
// and the most recent month as the value
nextSixMonths.push({
key: {
min: currentMonth,
max: nextMonth,
},
value: lastBucket.value,
});
currentMonth = nextMonth;
}
// Return the modified results
return { key: bucket.key, value: nextSixMonths };
});
return { buckets: modifiedBuckets };
}
The resulting aggregation can be used in a Workshop chart to show the monthly spend estimate for the next six months.
中文翻译¶
创建自定义聚合(custom aggregation)¶
利用函数可基于本体(ontology)中的数据计算自定义聚合,并在 Workshop 的图表组件(chart widget)中呈现。本指南将介绍如何编写自定义聚合逻辑:从本体加载聚合数据,对结果进行处理以生成未来结果的预测,并返回修改后的结果。
以下参考资料可能对理解本节内容有所帮助:
加载聚合(aggregation)¶
假设在本例中,您有一个包含费用数据的本体,每个 expense 对象具有部门名称、费用日期和费用金额属性。若要估算未来六个月内各部门的月度支出,可先加载月度支出的聚合数据:
const result = await Objects.search()
.expenses()
.groupBy(expense => expense.departmentName.topValues())
.segmentBy(expense => expense.date.byMonth())
.sum(expense => expense.amount);
处理聚合结果¶
接下来,您可以推算每个部门未来六个月的支出。本例采用简单方法:将最后一个月的数值作为未来六个月的估算值。
const modifiedBuckets = result.buckets.map(bucket => {
// 找到对应最近月份的桶(bucket)
const lastBucket = bucket.value[bucket.value.length - 1];
let nextSixMonths: IBaseBucket<IRange<Timestamp>, Double>[] = [];
let currentMonth = lastBucket.key.max!;
// 循环六次
for (let i = 0; i < 6; i++) {
// 找到该范围的结束时间(下个月)
const nextMonth = currentMonth.plusMonths(1);
// 添加新桶:日期范围设为下个月,数值沿用最近月份的值
nextSixMonths.push({
key: {
min: currentMonth,
max: nextMonth,
},
value: lastBucket.value,
});
currentMonth = nextMonth;
}
// 返回修改后的结果
return { key: bucket.key, value: nextSixMonths };
});
返回聚合结果¶
现在已生成未来六个月的估算值,您可以返回这些估算结果:
return { buckets: modifiedBuckets };
该函数的完整示例代码如下:
@Function()
public async estimatedDepartmentExpenses(): Promise<ThreeDimensionalAggregation<string, IRange<Timestamp>>> {
const result = await Objects.search()
.expenses()
.groupBy(expense => expense.departmentName.topValues())
.segmentBy(expense => expense.date.byMonths())
.sum(expense => expense.amount);
const modifiedBuckets = result.buckets.map(bucket => {
// 找到对应最近月份的桶
const lastBucket = bucket.value[bucket.value.length - 1];
let nextSixMonths: IBaseBucket<IRange<Timestamp>, Double>[] = [];
let currentMonth = lastBucket.key.max!;
// 循环六次
for (let i = 0; i < 6; i++) {
// 找到该范围的结束时间(下个月)
const nextMonth = currentMonth.plusMonths(1);
// 添加新桶:日期范围设为下个月,数值沿用最近月份的值
nextSixMonths.push({
key: {
min: currentMonth,
max: nextMonth,
},
value: lastBucket.value,
});
currentMonth = nextMonth;
}
// 返回修改后的结果
return { key: bucket.key, value: nextSixMonths };
});
return { buckets: modifiedBuckets };
}
生成的聚合结果可用于 Workshop 图表,展示未来六个月的月度支出估算。