AMQL Docs
Reusability

Implement Reusable Metric Store

This document describes how to use AML Extend to reuse metrics

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:

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

// Add individual metrics to the dataset
// highlight-next-line
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
// highlight-next-line
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
// highlight-next-line
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
// highlight-next-line
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
// highlight-next-line
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"
    // highlight-next-line
    definition: @aql orders | sum(order_item.quantity * products_us.price)
  }

  metric order_value_uk {
    label: "Order Value (UK)"
    type: "number"
    // highlight-next-line
    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
// highlight-next-line
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
      // highlight-next-line
      definition: @aql orders | sum(order_item.quantity * ${product_model.name}.price)
    }

    metric gmv {
      label: "Gross Merchandise Value"
      type: "number"
      // highlight-next-line
      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
// highlight-next-line
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
// highlight-next-line
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

On this page