Creating Business Context
A user in Finance or Marketing on a semantic layer does not want or may not be allowed access to everything.
They want to see semantics relevant to them, with their context applied.
That concept is called in Honeydew a “Domain”.
A Domain is a lightweight governance object that allows to build context for users, as well as maintain access control on data and on metadata.
That context includes:
- Selection of entities and sub-selection of fields, that are accessible when using the domain
- Selection of filters that must be applied on every query on the domain
- Selection of parameter overrides that apply in the domain context
Selecting entities and fields
Domain allows to select entities that participate. For example, a domain that selects a subset
of entities from TPCH:
type: domain
name: orders_domain
description: Orders Tracing Domain
# Entities and fields that participate
entities:
- name: lineitem
- name: orders
- name: partsupp
- name: part
Selecting entity fields
By default, all fields from an entity are included in the domain. You can control which fields
are included using field selectors - string patterns evaluated in the order they are listed.
Field selector syntax:
* - Include all fields
field_name - Include a specific field
-field_name - Exclude a specific field
pattern*, *pattern, *mid* - Include fields matching a wildcard pattern
-pattern*, -*pattern, -*mid* - Exclude fields matching a wildcard pattern
Evaluation rules:
- Selectors are evaluated in the order they are listed
- The last matching selector determines whether a field is included or excluded
- If no selectors are specified, all fields are included (equivalent to
["*"])
Examples:
entities:
# Include all fields (default behavior)
- name: customers
# Include only specific fields
- name: orders
fields:
- order_id
- order_date
- order_total
# Include all fields except specific ones
- name: employees
fields:
- "*"
- "-salary"
- "-ssn"
# Include fields matching a pattern
- name: products
fields:
- product_*
# Complex selection: all fields, exclude internal, re-include one
- name: transactions
fields:
- "*"
- "-internal_*"
- internal_status
Field selectors are evaluated in order. For example, ["*", "-field_a", "field_a"] will include
field_a because the last matching selector (field_a) is an inclusion.
Filters
Domain may control how data is filtered.
There are two types of filters: Semantic and Source.
| Aspect | Semantic Filters | Source Filters |
|---|
| Scope | Apply to all queries in a domain | Apply only when source entity is queried |
| Timing | Enforced after semantic resolution, may add JOINs | Applied early, directly on source tables |
| Purpose | Governance & access control | Performance optimization (e.g., partitions) and removing duplicate data (with conditional filtering) |
| Caveats | Can slow queries by introducing extra joins | May alter computed values due to order of filtering |
| Best Use | Consistent rules (e.g., tenant, access filters) | Performance with large/partitioned data |
Semantic Filters
Filters within a domain apply to every query on the domain. Think of them as filters every user must add to every query.
For example,
type: domain
name: orders_domain
description: Domestic Orders Tracing Domain
# Entities and fields that participate
entities:
- name: lineitem
- name: orders
- name: partsupp
- name: part
# Semantic Filters that always apply to every query on the domain
filters:
- name: ground_shipping
sql: lineitem.l_shipmode in ('MAIL', 'RAIL', 'TRUCK')
display_name: Ground Shipping Only
description: Only include shipments via ground transportation
Semantic filter’s sql field can contain ad-hoc expressions (as in the example above) or
reference named boolean attributes.
The display_name and description fields are optional.
A semantic filter will be always added to a query in a domain context. That means that semantic filters may have a performance impact when they introduce more JOINs.For example, this SQL query on the domain above that asks for part count:SELECT AGG("part.count") FROM domains.orders_domain
will include a JOIN to lineitems even though it was not directly referenced in the query to make sure only parts that where shipped over ground are included.
Semantic Filters using Parameters
A common use case is filtering data based on a parameter that sets user context.
For example, if:
- Every user operates within a tenant context
- Data in Snowflake is partitioned by a tenant column (in the example below in a tenant dimension
dim_tenant, though can be a column in every table)
- Users are only allowed to see data within their own tenant
Set $TENANT user parameter, and use it as a domain filter:
type: domain
# Entities that participate ..
filters:
- name: tenant_filter
sql: dim_tenant.tenant_id = $TENANT
Apply the parameter in the manner appropriate for the user queries (whether it is through BI connection settings or Snowflake SET statements).
If filtering data through a filtering dimension, make sure it is cross filtering the data with a one-to-many filtering direction.
Source Filters
Source filters are filters that are applied at the source level (unlike semantic filters that apply to the semantic layer as a whole).
The use cases for source filters are:
- Improving performance with logically partitioned data by always pushing filters below calculated attributes.
- Removing duplicated data using conditional filtering, which is common when
dealing with either Multi-Grain Data or
Slowly Changing Dimensions with Multiple Versions
Source filters are only supported on attributes that come from an entity source table.
A source filter is only applied if the source is part of the query.
type: domain
name: orders_domain
description: Domestic Orders Tracing Domain
# Entities and fields that participate
entities:
- name: lineitem
- name: orders
- name: partsupp
- name: part
source_filters:
- name: shipping_date_in_1994
sql: lineitem.l_shipdate >= '1994-01-01' and lineitem.l_shipdate < '1995-01-01'
Caution: Source filters apply before any other computation is done, which can change the values of calculated attributed.
See filtering order for more details.When in doubt, use a semantic filter, not a source filter.
Conditional Filtering
In some case, a domain filter is desired unless the user filtered otherwise.
The main use cases are:
- Performance on large datasets - reduce the data by default unless the user has explicitly asked for more data.
- Correctness with Slowly Changing Dimensions.
- Correctness with Multi-Grain tables.
See Conditional Filters for more details.
Conditional Filters are usually used to reduce data at the source, thus they are typically used within source filters.
Domain Hierarchy
Domain hierarchy functionality is currently in Beta.
Contact support@honeydew.ai to activate it for your account.
Domains can extend one or more parent domains, inheriting
and building upon their configuration.
This enables reusable base domains that compose
into specialized domains.
Extending Domains
Use the extends field to inherit from parent domains:
type: domain
name: child_domain
extends:
- parent_domain
What Gets Inherited
A child domain inherits from its parents:
- All entities and their field selections
- All filters (semantic and source)
- All parameters
- All labels (additive)
- All metadata sections
How Items Merge
Items in lists are matched by name. When a child defines
an item with the same name as a parent:
- Scalar fields (like
sql in filters) are replaced
- Collection fields (like
fields in entities)
are extended
- Use
merge: remove to remove an inherited item
# Parent domain
type: domain
name: parent
entities:
- name: customers
- name: orders
- name: products
filters:
- name: active
sql: status = 'active'
---
# Child domain
type: domain
name: child
extends:
- parent
entities:
- name: invoices # Add new entity
- name: orders # Extend orders
fields: [order_id, order_date]
- name: products # Remove inherited
merge: remove
filters:
- name: active # Replace parent filter
sql: status = 'active' AND deleted_at IS NULL
# Result entities: [customers, orders (extended), invoices]
Field Inheritance
When a child extends a parent entity, field operations
apply on top of the inherited field list:
# Parent
entities:
- name: customers
fields: [*]
- name: orders
fields: [order_id, order_date, order_status]
# Child
entities:
- name: customers
fields: [-ssn, -salary] # Remove from inherited
- name: orders
fields: [order_total] # Add to inherited
# Result:
# - customers: All fields except ssn, salary
# - orders: [order_id, order_date, order_status, order_total]
If the parent has fields: [*], the child already inherits
all fields. To restrict to specific fields, use -* first:
# Parent has all fields
entities:
- name: customers
fields: [*]
# Child wants only specific fields
entities:
- name: customers
fields: [-*, id, name, email]
Filter Inheritance
Filters with the same name replace parent filters:
# Parent
filters:
- name: region_filter
sql: region = 'US'
# Child
filters:
- name: region_filter
sql: region IN ('US', 'CA') # Replaces parent
- name: active_only
sql: status = 'active' # New filter
This applies to both semantic and source filters.
Label Inheritance
Labels use additive inheritance — child labels are added
to parent labels:
# Parent
labels: [production, sales]
# Child
labels: [analytics]
# Result: [production, sales, analytics]
Metadata sections are matched by name. Within each
section, items are matched by key:
# Parent
metadata:
- name: snowflake
metadata:
- name: role
value: default_role
- name: warehouse
value: default_wh
# Child
metadata:
- name: snowflake
metadata:
- name: warehouse
value: prod_wh # Overrides parent
- name: short_term_cache_ttl_in_seconds
value: 3600 # New item
# Result: role=default_role (inherited),
# warehouse=prod_wh (overridden),
# short_term_cache_ttl_in_seconds=3600 (new)
Removing Inherited Items
Use merge: remove to exclude items inherited
from parents:
entities:
- name: sensitive_entity
merge: remove
filters:
- name: legacy_filter
merge: remove
parameters:
- name: OLD_PARAM
merge: remove
This works for entities, filters, source_filters,
and parameters.
Multiple Inheritance
Extend multiple parent domains for composition:
# Base data model
type: domain
name: base_sales
entities:
- name: fact_sales
fields: [*]
- name: dim_customer
fields: [*]
---
# Security configuration
type: domain
name: security_mixin
filters:
- name: exclude_test
sql: is_test = false
---
# Performance configuration
type: domain
name: performance_mixin
source_filters:
- name: partition_recent
sql: date >= '2024-01-01'
---
# Combined domain
type: domain
name: sales_secure
extends:
- base_sales
- security_mixin
- performance_mixin
entities:
- name: dim_customer
fields: [-*, customer_id] # Only ID (no PII)
filters:
- name: public_only
sql: visibility = 'PUBLIC'
Parents are evaluated left-to-right. If multiple parents
define the same item, the rightmost parent wins.
The child overrides all parents.
Example: Regional Sales
# Base sales domain
type: domain
name: base_sales
entities:
- name: customers
fields: [*]
- name: orders
fields: [*]
- name: products
fields: [*]
filters:
- name: exclude_test
sql: orders.is_test = false
metadata:
- name: snowflake
metadata:
- name: role
value: analyst_role
---
# US sales domain
type: domain
name: sales_us
extends:
- base_sales
entities:
- name: customers
fields: [-ssn]
filters:
- name: us_region
sql: customers.country = 'US'
source_filters:
- name: recent_data
sql: orders.order_date >= '2024-01-01'
parameters:
- name: REGION
value: 'US'
labels:
- us_market
metadata:
- name: snowflake
metadata:
- name: warehouse
value: us_warehouse
The sales_us domain includes:
- All three entities (customers without SSN)
- Both filters (
exclude_test inherited, us_region added)
- Source filter for recent data
- US region parameter
- Snowflake metadata:
analyst_role inherited,
us_warehouse added
Interfaces
Domains on SQL interface
Domains are present as a flat table in the domains schema.
- Attributes that are part of the domain are accessible as SQL columns.
- Metrics that are part of the domain are accessible as SQL columns that can be aggregated on.
- All filters of the domain apply (in addition to any filters in the SQL query).
See SQL interface for more details.
Domains as a context for dynamic datasets
A dynamic dataset can be associated with a domain. In that case, all domain configuration applies to the dynamic dataset query.
Data Warehouse-specific domain configuration
Data warehouse access control
Domains can be configured to manage data warehouse session settings,
such as assigning a specific role or linking a designated compute
resource to each domain.
Domain-level configuration allows you to link user access
(e.g., via a BI tool, SQL interface, or the Honeydew native
application) to specific data and cost governance policies.This can also be used to enforce
row-level security
by scoping native data warehouse RLS policies to a domain-specific role.
This configuration is applied in the following scenarios:
- Queries executed through the Honeydew SQL interface, such as those from a BI tool
- Queries executed via the Honeydew Native Application
- Queries run from the Honeydew web user interface
If a third-party tool uses Honeydew only to compile a SQL query and executes the query independently,
the domain’s data warehouse configuration will not apply to that query.
Domain-level settings take precedence over the global data warehouse configuration.
Domains without specific settings default to the global configuration for your Honeydew account.
Snowflake
Databricks
BigQuery
Configure the Snowflake role and warehouse in the domain’s
snowflake metadata section. Both fields are optional.metadata:
- name: snowflake
metadata:
- name: role
value: <role name>
- name: warehouse
value: <warehouse name>
Domain-level Snowflake role and warehouse configuration
does not apply to deployment actions of Dynamic Datasets
as views or tables in Snowflake. They are used only for data
queries executed on the domain or on dynamic datasets
associated with the domain.
Configure the Databricks catalog and warehouse in the domain’s
databricks metadata section. Both fields are optional.metadata:
- name: databricks
metadata:
- name: catalog
value: <catalog name>
- name: warehouse
value: <warehouse name>
Define
row filters
in Unity Catalog scoped to the service principal’s permissions on that catalog.Domain-level Databricks catalog and warehouse configuration
does not apply to deployment actions of Dynamic Datasets.
They are used only for data queries executed on the domain
or on dynamic datasets associated with the domain.
Configure the BigQuery dataset in the domain’s bigquery
metadata section.metadata:
- name: bigquery
metadata:
- name: dataset
value: <dataset name>
Define
BigQuery RLS policies
scoped to the service account’s IAM access groups on that
dataset.Domain-level BigQuery dataset configuration does not apply
to deployment actions of Dynamic Datasets. It is used only for
data queries executed on the domain or on dynamic datasets
associated with the domain.
Snowflake short-term aggregate caching
Domains can be configured to enable short-term aggregate caching in Snowflake.
For more information, see
Snowflake Short-Term Aggregate Caching.
YAML Schema
Each domain is defined by a YAML file in Git, which also tracks and preserves the full history of every change.
The schema for a domain is:
type: domain
name: <name>
extends:
- <parent domain name>
- ...
display_name: <display name>
owner: <owner>
description: |-
<description>
labels: [label1, label2, ...]
tags:
- key: <key>
value: <value>
source: <snowflake/databricks/bigquery/honeydew/other>
- ...
folder: <folder>
hidden: <True/False/Yes/No>
entities:
- name: <entity name>
fields:
- <field selector>
- ...
merge: remove # Optional: remove inherited entity
- ...
filters:
- name: <filter name>
sql: <filter expression>
display_name: <display name> # optional
description: <description> # optional
merge: remove # Optional: remove inherited filter
- ...
source_filters:
- name: <filter name>
sql: <source filter expression>
display_name: <display name> # optional
description: <description> # optional
merge: remove # Optional: remove inherited source filter
- ...
parameters:
- name: <parameter name>
value: <parameter value>
merge: remove # Optional: remove inherited parameter
- ...
metadata:
- name: <section name>
metadata:
- name: <key>
value: <value>
- ...
- ...
Fields:
name: Name of domain
extends: Optional list of parent domains to inherit from
display_name, owner, description, labels, tags, folder, hidden: Metadata
entities: List of entities that participate in the domain
name: Name of entity
fields: List of field selectors (if omitted, all fields are included)
- Each selector is a string:
*, field_name, -field_name, or a wildcard pattern
- Selectors are evaluated in the order listed; last match determines inclusion
alias: Optional alias for entity
merge: Optional remove to remove inherited entity
filters: List of semantic filters
name: Unique identifier for the filter
sql: Filter expression
display_name: Optional human-readable name
description: Optional description
merge: Optional remove to remove inherited filter
source_filters: List of source filters
name: Unique identifier for the filter
sql: Filter expression
display_name: Optional human-readable name
description: Optional description
merge: Optional remove to remove inherited source filter
parameters: List of parameters and values (override workspace
or parent domain values)
name: Parameter name
value: Parameter value
merge: Optional remove to remove inherited parameter
metadata: Additional metadata sections for the domain
name: Section name (e.g., honeydew, snowflake)
metadata: Key-value pairs within the section
(see examples for AI,
Tableau and
Power BI)