Metric View Object Model
Note
The Semantic Bridge is in public preview. The 3.25.0 release supports Metric View v0.1 metadata, and the 3.26.2 release supports Metric View v1.1 metadata.
The Semantic Bridge includes an object model representing a Databricks Metric View. This allows you to work with Metric Views programmatically through C# scripts, similar to how you work with a Tabular model through the TOMWrapper.
Other than the import GUI, all access to and interaction with a Metric View is through C# scripts. All content in this document is referring to C# code that you would use in a C# script.
Loading and accessing the Metric View
You can load a Metric View with SemanticBridge.MetricView.Load or SemanticBridge.MetricView.Deserialize.
This stores the deserialized Metric View as SemanticBridge.MetricView.Model.
This property returns a View object, which is the root of the Metric View object graph.
// Load a Metric View from disk
SemanticBridge.MetricView.Load("C:/path/to/metricview.yaml");
// Access the loaded View
var view = SemanticBridge.MetricView.Model;
Output($"Metric View version: {view.Version}\r\nSource: {view.Source}");
Similar to a Tabular model and dissimilar to most other objects you may be used to in a C# script, the Metric View is persistent across multiple script executions.
This means that you can load a Metric View once, and reference it from subsequent script executions without re-loading it every time.
There is only ever a single Metric View loaded, and it is available in all scripts as SemanticBridge.MetricView.Model as mentioned above.
This behavior is similar to the Tabular model in C# scripts, which is always available simply as Model.
Load the sample Metric View for these code samples
Before starting, make sure you have Tabular Editor 3 open and have a Tabular model opened, or create a new model.
This how-to uses a sample e-commerce Metric View representing sales data with three dimension tables (product, customer, date) joined to a fact table (orders). Use either method below to load it (either "download and load" or "copy and deserialize"), then follow along with the rest of this how-to. You can run either command in the same C# script as the rest of this example, or you can run it first, in its own C# script, and the rest of the example in its own C# script.
Download sample-metricview.yaml
and load it by path:
SemanticBridge.MetricView.Load("C:/path/to/sample-metricview.yaml");
Domain objects
The object model consists of four main types that correspond to the structure of a Metric View YAML file. We do not repeat the entire specification here, so we encourage you to reference the Databricks Metric View documentation and our own API reference for the object model.
| API Reference | Description |
|---|---|
View |
The root object representing the entire Metric View |
Join |
A join definition connecting a dimension table to the fact |
Field |
A field definition (column) in the Metric View |
Measure |
An aggregation definition representing business logic |
Most properties and attributes of a Metric View have a structured representation in the object model, but we defer discussion of these in this document, as those are all direct representations of the Metric View spec and documented in our API reference, mentioned above.
Note
The object model was introduced in Tabular Editor 3.25.0 with support for Metric View v0.1.
Support for Metric View v1.1 was added in Tabular Editor 3.26.2;
this includes the Comment and Materialization properties on the View,
Cardinality and Rely on Join,
Comment, DisplayName, Synonyms, and Format on Field and Measure,
Window on Measure.
Note
In the object model, we follow C# naming conventions: PascalCase for all type and property names.
The Metric View YAML specification follows a naming convention of snake_case.
Serialization and deserialization convert between these, so C# scripts use PascalCase and the YAML we read and write stays spec-compliant snake_case.
View
The View object is the root of the Metric View and contains:
Version: The Metric View specification version (e.g., "1.1")Source: The source data for the fact table (e.g., "catalog.schema.table")Filter: Optional SQL boolean expression that applies to all queriesComment: Optional description of the Metric ViewJoins: Collection of join definitions; non-null empty collection if there are noJoinsFields: Collection of field definitions; non-null empty collection if there are noFieldsMeasures: Collection of measure definitions; non-null empty collection if there are noMeasuresMaterialization: Materialization configuration for query acceleration when hosted on Databricks; see theMaterializationAPI reference
var sb = new System.Text.StringBuilder();
var view = SemanticBridge.MetricView.Model;
sb.AppendLine($"Version: {view.Version}");
sb.AppendLine($"Source: {view.Source}");
sb.AppendLine($"Filter: {view.Filter ?? "(none)"}");
sb.AppendLine($"Joins: {view.Joins.Count}");
sb.AppendLine($"Fields: {view.Fields.Count}");
sb.AppendLine($"Measures: {view.Measures.Count}");
Output(sb.ToString());
Output
Version: 1.1
Source: sales.fact.orders
Filter: (none)
Joins: 3
Fields: 6
Measures: 6
Join
A Join represents a dimension table that is joined to the fact table:
Name: Name of the joined table (used as an alias)Source: Source table or query for the join (e.g., "catalog.schema.dimension_table")On: Optional SQL boolean expression for the join conditionUsing: Optional list of column names for the join (alternative toOn)Joins: Child joins (for snowflake schemas)ParentJoin: if this is a nested join, thenParentJoinis a pointer to the parent, otherwise nullCardinality: controls the relationship betweenView.SourceorParentJoinand thisJoin; see theJoinCardinalityAPI referenceRely: Optimizer hints about theJoin's relationship to its parent; see theRelyAPI reference
var sb = new System.Text.StringBuilder();
var view = SemanticBridge.MetricView.Model;
foreach (var join in view.Joins)
{
sb.AppendLine($"Join: {join.Name}");
sb.AppendLine($" Source: {join.Source}");
if (!string.IsNullOrEmpty(join.On))
sb.AppendLine($" On: {join.On}");
if (join.Using != null && join.Using.Count > 0)
sb.AppendLine($" Using: {string.Join(", ", join.Using)}");
}
Output(sb.ToString());
Output
Join: product
Source: sales.dim.product
On: source.product_id = product.product_id
Join: customer
Source: sales.dim.customer
On: source.customer_id = customer.customer_id
Join: date
Source: sales.dim.date
On: source.order_date = date.date_key
Field
A Field represents a field (column) in the Metric View:
Name: The name of the field, referenced in Metric View expressionsExpr: The SQL expression defining the field (either a column reference or a SQL expression)Comment: Optional description of the fieldDisplayName: Optional human-readable display name for the fieldSynonyms: Optional alternative names for the field, used by AI and BI toolsFormat: Optional display format specification for the field's values; see theFormatAPI reference
var sb = new System.Text.StringBuilder();
var view = SemanticBridge.MetricView.Model;
foreach (var field in view.Fields)
{
sb.AppendLine($"Field: {field.Name}");
sb.AppendLine($" Expression: {field.Expr}");
}
Output(sb.ToString());
Output
Field: product_name
Expression: product.product_name
Field: product_category
Expression: product.category
Field: customer_segment
Expression: customer.segment
Field: order_date
Expression: date.full_date
Field: order_year
Expression: date.year
Field: order_month
Expression: date.month_name
Measure
A Measure represents a named aggregation with business logic:
Name: The name of the measure, referenced in Metric View expressions asMEASURE(<name>)Expr: The SQL aggregate expression defining the measureComment: Optional description of the measureDisplayName: Optional human-readable display name for the measureSynonyms: Optional alternative names for the measure, used by AI and BI toolsFormat: Optional display format specification for the measure's values; see theFormatAPI referenceWindow: Optional list of window specifications for windowed or semi-additive aggregation; see theWindowAPI reference
var sb = new System.Text.StringBuilder();
var view = SemanticBridge.MetricView.Model;
foreach (var measure in view.Measures)
{
sb.AppendLine($"Measure: {measure.Name}");
sb.AppendLine($" Expression: {measure.Expr}");
}
Output(sb.ToString());
Output
Measure: total_revenue
Expression: SUM(revenue)
Measure: gross_margin
Expression: SUM(revenue) - SUM(cost)
Measure: order_count
Expression: COUNT(*)
Measure: avg_order_value
Expression: AVG(revenue)
Measure: revenue_to_budget
Expression: (SUM(revenue) - SUM(budget)) / SUM(budget)
Measure: unique_customers
Expression: COUNT(DISTINCT customer_id)
Using directives
When working with the Metric View object model in C# scripts, you may need to add a using directive to avoid naming conflicts with similarly-named types in the Tabular Object Model. We recommend aliasing the namespace:
// Alias to avoid conflicts with TOM types like Measure
using MetricView = TabularEditor.SemanticBridge.Platforms.Databricks.MetricView;
SemanticBridge.MetricView.Load("C:/path/to/metricview.yaml");
var view = SemanticBridge.MetricView.Model;
// Now you can reference types explicitly
foreach (MetricView.Field field in view.Fields)
{
// ...
}
Interacting with the object model
This document describes the patterns of using the object model. See the Semantic Bridge how-tos for detailed copy and paste-able examples.
View parent pointer
All core Metric View objects described in this document inherit from MetricViewObjectBase for their core functionality.
Among other things, this means that each holds a View pointer back up to the Metric View they are defined in.
This allows you to inspect the whole Metric View when holding any of these objects.
SemanticBridge.MetricView.Load("C:/path/to/metricview.yaml");
var v = SemanticBridge.MetricView.Model; // alias the Metric View as v just for concision
var f = v.Fields.FirstOrDefault(); // f is the first field defined in the Metric View
Output(f.View == v); // the field, f, lets you navigate up to the containing view
Adding objects
You never instantiate a View, Join, Field, or Measure directly.
Instead, deserialize or load a base View, or use the various Add methods:
- New Metric View:
DeserializeYAML in a stringLoada YAML file from disk
- Add objects
Deserialize and Load both set the global SemanticBridge.MetricView.Model so you can interact with it in scripts.
The Add methods all return the new object just added so that you can interact with it and set additional properties;
this mirrors the interaction with TOM objects you are already familiar with in C# scripts.
Modify properties
The Metric View object model is mutable throughout, so you can simply set properties directly. C# autocompletion in Tabular Editor 3 will help with finding the right properties and types to use. All properties and their types are in the API documentation.
Accessing objects by name
The root View contains collections for Joins, Fields, and Measures.
Each Join contains a child Joins collection.
Each of these can be indexed by name;
this looks up the child object by its Name property.
This lookup is case insensitive, matching the default in Databricks SQL.
Metric View versions
We track the Databricks Metric View documentation to stay up to date with the specification.
All properties are annotated with the version that they were introduced.
Thanks to this, the object model will raise exceptions and surface diagnostics if you attempt to set a property that is not allowed for a given version of the spec.
We recommend always running SemanticBridge.MetricView.Validate(); after modifying a Metric View in a C# script;
this will check all default validation rules for correctness.