Metrics
Overview
A SemanticMetric belongs to a data model and contains its own measures, dimensions, joins, and aggregations. Metrics can be executed independently and support custom SQL queries with extensive configuration options for caching, refresh policies, and data processing.
How metrics fit into the data modeling ecosystem
Relationship to Data Models
Metrics are always associated with a data model and inherit certain properties:
- Data Source: Metrics connect through their parent data model
- Configuration: Shared model-level settings apply to all metrics
- Validation: Model validation includes metric validation
- Versioning: Metric changes are tracked through model versions
- Permissions: Access control is managed at the model level
For detailed information about data models, see Data Models Configuration.
Specification
id
Type: UUID
Default: Auto-generated using uuid4()
Required: No (auto-generated)
Unique identifier for the metric instance. Automatically generated when a new metric is created.
{
"id": "550e8400-e29b-41d4-a716-446655440000"
}
data_model_id
Type: UUID
Required: Yes
Foreign key reference to the parent data model that this metric belongs to.
{
"data_model_id": "550e8400-e29b-41d4-a716-446655440001"
}
name
Type: str
Required: Yes
Unique identifier name for this metric within the data model. Used for API queries and references.
{
"name": "user_revenue_analysis"
}
alias
Type: Optional[str]
Default: None
Required: No
Optional alternative name for display purposes. Can be used in UI components or API responses.
{
"alias": "revenue_by_user"
}
description
Type: Optional[str]
Default: None
Required: No
Human-readable explanation of what this metric represents and its purpose.
{
"description": "Comprehensive revenue analysis by user segments"
}
title
Type: Optional[str]
Default: None
Required: No
Human-readable display name for UI components and documentation.
{
"title": "User Revenue Analysis"
}
query
Type: Optional[str]
Default: None
Required: No
Custom SQL query string that overrides the entire auto-generated query. When provided, this query will be used instead of building a query from measures, dimensions, and joins.
{
"query": "SELECT COUNT(*) FROM users WHERE active = true"
}
table_name
Type: Optional[str]
Default: None
Required: No
Source table or view where this metric's data resides. Used as the primary table for auto-generated queries.
{
"table_name": "users"
}
data_source_id
Type: Optional[UUID]
Default: None
Required: No
Foreign key reference to the data source connection. Specifies which database or data source this metric queries.
{
"data_source_id": "550e8400-e29b-41d4-a716-446655440002"
}
limit
Type: Optional[int]
Default: None
Required: No
Default limit for query results. Applied when no specific limit is provided in the query request.
{
"limit": 1000
}
grouped
Type: Optional[bool]
Default: True
Required: No
Whether to apply GROUP BY when dimensions are present. When True, dimensions will be used to group the results.
{
"grouped": true
}
ordered
Type: Optional[bool]
Default: True
Required: No
Whether to apply ordering to the query results. When True, the order sequences will be used to sort results.
{
"ordered": true
}
order
Type: Optional[List[SemanticOrderSequence]]
Default: None
Required: No
List of order sequences defining how to sort the query results. Each sequence specifies what to sort by and how to sort it.
{
"order": [
{
"reference_type": "MEASURE",
"reference": "total_revenue",
"order_type": "DESC",
"nulls_position": "LAST"
},
{
"reference_type": "DIMENSION",
"reference": "month",
"order_type": "ASC",
"nulls_position": "FIRST"
}
]
}
Order Sequence Properties:
- reference_type: Type of reference (
MEASURE,DIMENSION,COLUMN,POSITION) - reference: Name of the measure, dimension, column, or position number
- order_type: Sort direction (
ASCorDESC) - nulls_position: Where to place null values (
FIRSTorLAST)
version
Type: int
Default: 1
Required: No
Metric version for caching invalidation and change tracking. Incremented when the metric configuration changes.
{
"version": 1
}
extends
Type: Optional[UUID]
Default: None
Required: No
Parent metric ID for inheritance patterns. Allows metrics to inherit configuration from a parent metric.
{
"extends": "550e8400-e29b-41d4-a716-446655440003"
}
public
Type: bool
Default: True
Required: No
Whether this metric can be queried via API. When False, the metric is only accessible internally.
{
"public": true
}
meta
Type: Optional[Dict[str, Any]]
Default: None
Required: No
Custom metadata dictionary for storing additional information about the metric.
{
"meta": {
"category": "revenue",
"owner": "analytics_team",
"tags": ["kpi", "financial"]
}
}
is_valid
Type: bool
Default: False
Required: No
Boolean indicating if the metric configuration is valid. Set to True after successful validation.
{
"is_valid": true
}
validation_errors
Type: Optional[List[str]]
Default: None
Required: No
Array of error messages from validation. Populated when is_valid is False.
{
"validation_errors": [
"Missing required dimension: user_id",
"Invalid join condition: table 'orders' not found"
]
}
compiled_query
Type: Optional[str]
Default: None
Required: No
Generated SQL query after compilation. Shows the final query that will be executed.
{
"compiled_query": "SELECT segment_type, SUM(revenue_amount) as total_revenue FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.status = 'active' GROUP BY segment_type"
}
created_at
Type: datetime
Default: Current UTC timestamp
Required: No
Timestamp when the metric was created.
{
"created_at": "2024-01-15T10:00:00Z"
}
updated_at
Type: datetime
Default: Current UTC timestamp
Required: No
Timestamp when the metric was last updated.
{
"updated_at": "2024-01-15T10:00:00Z"
}
measures
Type: Optional[List[SemanticMeasure]]
Default: None
Required: No
List of quantitative measurements included in this metric. Each measure defines what data should be quantified and how it should be calculated.
{
"measures": [
{
"name": "total_revenue",
"description": "Sum of all revenue",
"type": "sum",
"query": "revenue_amount",
"table": "orders",
"alias": "revenue",
"primary_key": "order_id",
"formatting": [
{
"name": "currency_format",
"type": "format",
"format_type": "currency",
"format_string": "$%.2f"
}
]
}
]
}
Quick Reference
- name: Unique identifier for the measure
- description: Human-readable explanation
- type: Calculation type (sum, avg, count, etc.)
- query: Custom query expression
- table: Source table or view
- alias: Alternative name for results
- primary_key: Primary key column identifier
- formatting: Output transformation rules
Detailed Configuration
For comprehensive information about configuring measures, including all parameters, examples, and best practices, see the Measures Configuration Guide.
Screenshot of the measures configuration interface in the Cortex dashboard
dimensions
Type: Optional[List[SemanticDimension]]
Default: None
Required: No
List of categorical attributes by which the measures can be grouped. Dimensions define how data should be categorized and filtered.
{
"dimensions": [
{
"name": "user_segment",
"description": "User segmentation category",
"query": "segment_type",
"table": "users",
"formatting": [
{
"name": "segment_display",
"type": "format",
"format_type": "custom",
"format_string": "Segment: {value}"
}
]
}
]
}
Quick Reference
- name: Unique identifier for the dimension
- description: Human-readable explanation
- query: Column name or expression
- table: Source table or view
- formatting: Display transformation rules
Detailed Configuration
For comprehensive information about configuring dimensions, including all parameters, examples, and best practices, see the Dimensions Configuration Guide.
Screenshot of the dimensions configuration interface in the Cortex dashboard
joins
Type: Optional[List[SemanticJoin]]
Default: None
Required: No
List of joins to be applied in the query. Defines relationships between tables for data combination.
{
"joins": [
{
"name": "user_orders",
"description": "Join users with their orders",
"join_type": "left",
"left_table": "users",
"right_table": "orders",
"conditions": [
{
"left_table": "users",
"left_column": "id",
"right_table": "orders",
"right_column": "user_id",
"operator": "="
}
],
"alias": "user_orders",
"additional_conditions": [
{
"left_table": "orders",
"left_column": "status",
"right_table": "order_statuses",
"right_column": "status_code",
"operator": "="
}
],
"join_hints": {
"use_index": "idx_user_id",
"force_order": true
}
}
]
}
Quick Reference
- name: Unique identifier for the join
- description: Human-readable explanation
- join_type: Type of join (inner, left, right, full, cross)
- left_table: Primary table name
- right_table: Table to join with
- conditions: Array of join conditions
- alias: Optional alias for the joined table
- additional_conditions: Additional join conditions
- join_hints: Database optimization hints
Detailed Configuration
For comprehensive information about configuring joins, including all parameters, examples, and best practices, see the Joins Configuration Guide.
Screenshot of the visual join builder in the Cortex dashboard
aggregations
Type: Optional[List[SemanticAggregation]]
Default: None
Required: No
List of aggregations to be applied to the data. Defines complex aggregations beyond basic measures.
{
"aggregations": [
{
"name": "revenue_percentile",
"description": "95th percentile of revenue",
"type": "percentile",
"source_columns": ["revenue"],
"target_column": "revenue_p95",
"percentile_value": 0.95,
"where_condition": "status = 'completed'",
"window": {
"partition_by": ["user_segment"],
"order_by": ["created_at"],
"frame_start": "UNBOUNDED PRECEDING",
"frame_end": "CURRENT ROW"
}
},
{
"name": "custom_metric",
"description": "Custom calculation",
"type": "custom",
"source_columns": ["revenue", "cost"],
"target_column": "profit_margin",
"custom_expression": "(revenue - cost) / revenue * 100"
}
]
}
Quick Reference
- name: Unique identifier for the aggregation
- description: Human-readable explanation
- type: Aggregation type (percentile, custom, window functions, etc.)
- source_columns: Columns to aggregate
- target_column: Result column name
- custom_expression: SQL expression for custom aggregations
- window: Window function parameters
- percentile_value: Value for percentile aggregations
- where_condition: SQL condition for conditional aggregations
- group_by_columns: Columns for grouped aggregations
Detailed Configuration
For comprehensive information about configuring aggregations, including all parameters, examples, and best practices, see the Aggregations Configuration Guide.
Screenshot of the aggregations configuration interface in the Cortex dashboard
filters
Type: Optional[List[SemanticFilter]]
Default: None
Required: No
List of filters to be applied to the data. Defines data filtering conditions for WHERE or HAVING clauses.
{
"filters": [
{
"name": "active_users",
"description": "Filter for active users only",
"query": "status",
"table": "users",
"operator": "equals",
"value": "active",
"value_type": "string",
"filter_type": "where",
"is_active": true
},
{
"name": "revenue_range",
"description": "Revenue between limits",
"query": "revenue",
"operator": "between",
"min_value": 1000,
"max_value": 10000,
"value_type": "number",
"filter_type": "having"
},
{
"name": "segment_filter",
"description": "Multiple segment filter",
"query": "segment",
"operator": "in",
"values": ["premium", "enterprise"],
"value_type": "string"
}
]
}
Quick Reference
- name: Unique identifier for the filter
- description: Human-readable explanation
- query: Column name or expression
- table: Source table name
- operator: Comparison operator (equals, between, in, etc.)
- value: Single comparison value
- value_type: Type of the filter value
- filter_type: Where to apply (where/having)
- is_active: Whether filter is currently active
- custom_expression: Custom SQL expression
- values: Array of values for IN/NOT_IN operators
- min_value/max_value: Range values for BETWEEN operator
- formatting: Filter value transformation rules
Detailed Configuration
For comprehensive information about configuring filters, including all parameters, examples, and best practices, see the Filters Configuration Guide.
Screenshot of the filter builder interface in the Cortex dashboard
parameters
Type: Optional[Dict[str, ParameterDefinition]]
Default: None
Required: No
Runtime parameters for dynamic query generation. Allows metrics to accept parameters at query time.
{
"parameters": {
"date_range": {
"name": "date_range",
"type": "date",
"description": "Date range for filtering",
"required": true,
"default_value": "2024-01-01"
},
"user_segment": {
"name": "user_segment",
"type": "string",
"description": "User segment to filter by",
"required": false,
"allowed_values": ["premium", "standard", "basic"],
"default_value": "standard"
},
"revenue_threshold": {
"name": "revenue_threshold",
"type": "float",
"description": "Minimum revenue threshold",
"min_value": 0.0,
"max_value": 1000000.0,
"default_value": 1000.0
}
}
}
Quick Reference
- name: Parameter identifier name
- type: Parameter data type (string, integer, float, boolean, date, datetime, list)
- description: Human-readable explanation
- default_value: Default value if not provided
- required: Whether the parameter is mandatory
- allowed_values: Array of valid values for enum-like parameters
- validation_regex: Regular expression for string validation
- min_value/max_value: Range constraints for numeric parameters
Detailed Configuration
For comprehensive information about configuring parameters, including all parameters, examples, and best practices, see the Parameters Configuration Guide.
Screenshot of the parameter configuration interface in the Cortex dashboard
cache
Type: Optional[CachePreference]
Default: None
Required: No
Result cache configuration for metrics and requests.
{
"cache": {
"enabled": true,
"ttl": 3600
}
}
Quick Reference
- enabled: Whether result caching is active
- ttl: Time-to-live in seconds
Detailed Configuration
For comprehensive information about configuring cache, including all parameters, examples, and best practices, see the Cache Configuration Guide.
Screenshot of the cache configuration interface in the Cortex dashboard
refresh
Type: Optional[RefreshPolicy]
Default: None
Required: No
Pre-aggregation refresh policy for materialized views and rollups.
{
"refresh": {
"type": "every",
"every": "1 hour"
}
}
Quick Reference
- type: Refresh strategy (every, sql, max)
- every: Time interval string for time-based refresh
- sql: Custom SQL query to determine if refresh is needed
- max: Column name to monitor for maximum value changes
Detailed Configuration
For comprehensive information about configuring refresh policies, including all parameters, examples, and best practices, see the Refresh Policy Configuration Guide.
Screenshot of the refresh policy configuration interface in the Cortex dashboard
RefreshPolicy Parameters (Legacy)
type
Type: RefreshType
Required: Yes
Refresh strategy. Available values:
every: Time-based refresh intervalssql: Custom SQL condition for refreshmax: Refresh based on maximum value changes
{
"type": "every"
}
every
Type: Optional[str]
Default: None
Required: No
Time interval string for time-based refresh.
{
"every": "1 hour"
}
sql
Type: Optional[str]
Default: None
Required: No
Custom SQL query to determine if refresh is needed.
{
"sql": "SELECT COUNT(*) FROM orders WHERE created_at > last_refresh"
}
max
Type: Optional[str]
Default: None
Required: No
Column name to monitor for maximum value changes.
{
"max": "updated_at"
}
## Complete Configuration Example
Here's a complete example showing how all the different components work together:
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"data_model_id": "550e8400-e29b-41d4-a716-446655440001",
"name": "user_revenue_analysis",
"alias": "revenue_by_user",
"description": "Comprehensive revenue analysis by user segments",
"title": "User Revenue Analysis",
"query": null,
"table_name": "users",
"data_source_id": "550e8400-e29b-41d4-a716-446655440002",
"limit": 1000,
"grouped": true,
"measures": [
{
"name": "total_revenue",
"description": "Sum of all user revenue",
"type": "sum",
"query": "revenue_amount",
"table": "orders",
"formatting": [
{
"name": "currency_format",
"type": "format",
"format_type": "currency",
"format_string": "$%.2f"
}
]
}
],
"dimensions": [
{
"name": "user_segment",
"description": "User segmentation category",
"query": "segment_type",
"table": "users"
}
],
"joins": [
{
"name": "user_orders",
"description": "Join users with orders",
"join_type": "left",
"left_table": "users",
"right_table": "orders",
"conditions": [
{
"left_table": "users",
"left_column": "id",
"right_table": "orders",
"right_column": "user_id",
"operator": "="
}
]
}
],
"filters": [
{
"name": "active_users",
"description": "Only active users",
"query": "status",
"table": "users",
"operator": "equals",
"value": "active",
"value_type": "string",
"filter_type": "where",
"is_active": true
}
],
"parameters": {
"date_range": {
"name": "date_range",
"type": "date",
"description": "Analysis date range",
"required": true
}
},
"version": 1,
"extends": null,
"public": true,
"refresh": {
"type": "every",
"every": "1 hour"
},
"cache": {
"enabled": true,
"ttl": 3600
},
"meta": {
"category": "user_analytics",
"owner": "data_team"
},
"is_valid": true,
"validation_errors": null,
"compiled_query": "SELECT segment_type, SUM(revenue_amount) as total_revenue FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.status = 'active' GROUP BY segment_type",
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-15T10:00:00Z"
}
This comprehensive configuration demonstrates how all the different components work together to create a powerful, flexible metric definition that can handle complex analytical requirements while maintaining performance through caching and refresh policies.
Configuration Guides
For detailed information about each configuration component, see the following guides:
- Measures Configuration - Quantitative metrics and calculations
- Dimensions Configuration - Categorical attributes for grouping
- Joins Configuration - Table relationships and data combination
- Aggregations Configuration - Advanced calculations and window functions
- Filters Configuration - Data filtering and segmentation
- Parameters Configuration - Dynamic query parameters
- Cache Configuration - Performance optimization through caching
- Refresh Policy Configuration - Data freshness and refresh strategies
Video Tutorials
Video: Complete walkthrough of configuring a metric from start to finish in the Cortex dashboard
Dashboard Examples
Screenshot of the complete metric configuration interface in the Cortex dashboard
Screenshot showing how configured metrics appear in the results dashboard
Related Topics
- Data Models Configuration - Learn about the data models that contain metrics
- Semantic Components - Explore all semantic configuration options
- API Reference - Learn about metric management APIs