Skip to main content

Implement Reusable Metric Store

Overview

With AML Extend, you can define metrics once and reuse them across multiple datasets. This approach helps you:

  • Avoid duplicating logic for every new business question
  • Manage important business logic in one central place
  • Maintain a lean analytics codebase that's easier for new team members to learn

Key Concepts

Before diving into examples, understand these two approaches for organizing reusable metrics:

  1. Define metrics separately - Metrics can be declared as standalone objects, making them independently reusable
  2. Group metrics with PartialDataset - Related metrics can be organized into thematic groups using PartialDataset for easier management and reuse

You can mix both approaches to build a flexible metric store that suits your team's needs.

How to Reuse Metrics

Approach 1: Define Metrics Separately

You can define individual metrics as standalone objects and reference them when needed:

metrics.aml
// Define standalone metrics
Metric total_orders {
label: "Total Orders"
type: "number"
description: "Total number of orders placed"
definition: @aql count(ecommerce_orders.id);;
}

Metric gmv {
label: "GMV (Gross Merchandise Value)"
type: "number"
description: "Total value of all orders before discount"
definition: @aql ecommerce_order_items | sum(ecommerce_order_items.quantity * ecommerce_products.price);;
format: "[\$\$]#,###0"
}

Metric revenue {
label: "Total Revenue"
type: "number"
description: "Total revenue after applying commission rate"
definition: @aql nmv * revenue_commission;;
format: "[\$\$]#,###0"
}

Metric aov {
label: "AOV (Average Order Value)"
type: "number"
description: "Average value per order"
definition: @aql gmv / total_orders;;
format: "[\$\$]#,###0"
}

Then extend your dataset with individual metrics:

Dataset company {
// Base dataset definition
// Omitted for brevity
}

// Add individual metrics to the dataset
Dataset company_with_metrics = company.extend({
metric total_orders: total_orders
metric gmv: gmv
metric revenue: revenue
})

For better organization, group related metrics into thematic PartialDataset objects. This makes it easier to reuse entire groups of metrics:

metrics.aml
// Define individual metrics first
Metric total_orders {
label: "Total Orders"
type: "number"
definition: @aql count(ecommerce_orders.id);;
}

Metric total_delivered_orders {
label: "Total Delivered Orders"
type: "number"
definition: @aql total_orders | where(ecommerce_orders.status is 'delivered');;
}

Metric total_cancelled_orders {
label: "Total Cancelled Orders"
type: "number"
definition: @aql total_orders | where(ecommerce_orders.status is 'cancelled');;
}

Metric gmv {
label: "GMV (Gross Merchandise Value)"
type: "number"
definition: @aql ecommerce_order_items | sum(ecommerce_order_items.quantity * ecommerce_products.price);;
format: "[\$\$]#,###0"
}

Metric revenue {
label: "Total Revenue"
type: "number"
definition: @aql nmv * revenue_commission;;
format: "[\$\$]#,###0"
}

Metric aov {
label: "AOV (Average Order Value)"
type: "number"
definition: @aql gmv / total_orders;;
format: "[\$\$]#,###0"
}

// Group volume-related metrics
PartialDataset volume_metrics {
metric total_orders: total_orders
metric total_delivered_orders: total_delivered_orders
metric total_cancelled_orders: total_cancelled_orders
}

// Group revenue-related metrics
PartialDataset revenue_metrics {
metric gmv: gmv
metric revenue: revenue
metric aov: aov
}

Now you can reuse these metric groups across different datasets:

company.dataset.aml
Dataset company {
// Omitted for brevity
}

// Extend with grouped metrics
Dataset company_analytics = company
.extend(volume_metrics)
.extend(revenue_metrics)

Approach 3: Mix and Match - Chain Extensions

You can combine both approaches, extending datasets with metric groups and individual metrics:

store.dataset.aml
Dataset store {
// Omitted for brevity
}

// Extend with metric groups and add custom metrics
Dataset store_analytics = store
.extend(volume_metrics)
.extend(revenue_metrics)
.extend({
// Add or override individual metrics
metric store_specific_metric {
label: "Store-Specific Metric"
type: "number"
definition: @aql gmv * (1 - store.discount_rate)
}
})

Advanced: Parameterized Metrics with Functions

When you need to reuse the same metric logic across different contexts (e.g., different regions, product lines, or data models), you can use AML Functions to create parameterized metrics.

The Problem: Duplicated Metric Logic

Imagine you price products differently for US and UK markets using separate data models. Without parameterization, you'd duplicate the metric definition:

// Without parameterization - duplicated logic
PartialDataset regional_revenue_metrics {
metric order_value_us {
label: "Order Value (US)"
type: "number"
definition: @aql orders | sum(order_item.quantity * products_us.price)
}

metric order_value_uk {
label: "Order Value (UK)"
type: "number"
definition: @aql orders | sum(order_item.quantity * products_uk.price)
}
}

Notice the formula is identical except for the product model reference. This duplication becomes harder to maintain as you add more regions.

The Solution: Use Functions to Parameterize Metrics

Instead, create a function that returns a PartialDataset with parameterized metrics:

// Declare a function that accepts a product model as parameter
Func getRevenueMetrics(product_model: Model) {
PartialDataset revenue_metrics {
metric order_value {
label: "Order Value"
type: "number"
hidden: false
// Use the product_model parameter in the definition
definition: @aql orders | sum(order_item.quantity * ${product_model.name}.price)
}

metric gmv {
label: "Gross Merchandise Value"
type: "number"
definition: @aql orders | sum(order_item.quantity * ${product_model.name}.price * (1 - orders.discount))
format: "[\$\$]#,###0"
}
}
}

Reuse Parameterized Metrics Across Datasets

Now you can reuse this metric logic for different regions by passing the appropriate product model:

us_data.dataset.aml
Dataset us_market {
// Base dataset definition
// Omitted for brevity
}

// Extend with US product model
Dataset us_market_with_revenue = us_market.extend(getRevenueMetrics(products_us))

// In uk_data.dataset.aml
Dataset uk_market {
// Base dataset definition
// Omitted for brevity
}

// Extend with UK product model
Dataset uk_market_with_revenue = uk_market.extend(getRevenueMetrics(products_uk))

This approach ensures your metric logic stays consistent across regions while remaining flexible enough to adapt to different data models.

Benefits of a Reusable Metric Store

By implementing a metric store using the patterns above, you gain:

  1. Single Source of Truth - Business logic defined once, used everywhere
  2. Easier Maintenance - Update a metric definition in one place, all datasets benefit
  3. Consistency - Same calculations across all reports and dashboards
  4. Scalability - Add new metrics or metric groups without rewriting existing datasets
  5. Flexibility - Mix and match metric groups, add custom metrics, or use parameterization for complex scenarios

Let us know what you think about this document :)