Explores (Looker to Holistics)
High-level Overview
Looker Explore vs Holistics Dataset
In principle, an explore in Looker corresponds to a dataset in Holistics.
Dynamic Root Models vs. Root Models
Looker's explore feature is a SQL generation interface that creates a series of JOINs based on the fields you select. The first table in the FROM clause of the generated query represents the initial view in Looker's explore (or in Holistics, we call it root model).
This means that, even when you only select fields in users
view (via Field Picker UI), Looker will always generate the SQL starting from the root model events
to users
via your specified joins.
In Holistics, the table in the from clause is dynamic based on which fields are selected in the our Explore UI
Relationships over Joins
A key distinction between Looker and Holistics lies in how they handle joins. Holistics uses relationships to automatically generate appropriate joins, whereas Looker requires users to pre-define the joins in advance within their explores.
Step-by-Step Migration Tutorial
Step 1: Set Up Your Environment
- Open your Looker explore file
- Create a new Holistics dataset
- Identify all views and their relationships
Step 2: Define Models
- List all models used in the explore:
// Looker
explore: ecommerce {
view_name: order_items
join: products { ... }
join: orders { ... }
}
// Holistics
Dataset ecommerce {
models: [
order_items,
products,
orders
]
}
Step 3: Convert Joins to Relationships
From the Looker explore below, we can identify:
- 5 views that will become models in Holistics:
order_items
,products
,orders
,merchants
, andusers
- The relationships between these models:
order_items
many-to-oneproducts
(via product_id)order_items
many-to-oneorders
(via order_id)products
many-to-onemerchants
(via merchant_id)orders
many-to-oneusers
(via user_id)
// Looker
explore: order_items {
join: products {
type: left_outer
sql_on: ${order_items.product_id} = ${products.id} ;;
relationship: many_to_one
}
join: orders {
type: left_outer
sql_on: ${order_items.order_id} = ${orders.id} ;;
relationship: many_to_one
}
join: merchants {
type: left_outer
sql_on: ${products.merchant_id} = ${merchants.id} ;;
relationship: many_to_one
}
join: users {
type: left_outer
sql_on: ${orders.user_id} = ${users.id} ;;
relationship: many_to_one
}
}
In Holistics, we express these relationships using the relationship
syntax. The arrow direction (>
) indicates the many-to-one relationship:
// Holistics
Dataset ecommerce {
models: [
order_items,
products,
orders,
merchants,
users
]
relationships: [
// orders -> users (n-1)
relationship(orders.user_id > users.id, true),
// order_items -> orders (n-1)
relationship(order_items.order_id > orders.id, true),
// order_items -> products (n-1)
relationship(order_items.product_id > products.id, true),
// products -> merchants (n-1)
relationship(products.merchant_id > merchants.id, true),
]
}
Step 4: Handle Access Control
In Looker
// Looker
access_filter: {
field: orders.merchant_id
user_attribute: merchant_id
}
In Holistics
Use Holistics Row-level Permission instead
Step 5: Test and Validate
- Test common field combinations
- Verify join paths are correct
- Compare query results with Looker
- Test access controls
Reference Manual
Property Mapping
Looker Property | Holistics Property | Notes |
---|---|---|
view_name | N/A | Holistics uses dynamic root model |
join | relationships | Define relationships between models |
sql_on | relationship() | Use relationship syntax |
fields | Dataset View | Use Dataset Custom View |
access_filter | Row-level Permission | Use Row-level Permission |
Common Patterns
Dataset Organization
// Looker - using view_name and joins
explore: ecommerce {
view_name: order_items
join: products { ... }
join: orders { ... }
}
// Holistics - list all models and their relationships
Dataset ecommerce {
models: [
order_items,
products,
orders
]
relationships: [
relationship(order_items.product_id > products.id, true),
relationship(order_items.order_id > orders.id, true)
]
}Field Selection
// Looker - using fields parameter
explore: ecommerce {
fields: [
orders.id,
orders.status,
users.email
]
}
// Holistics - using Dataset View
Dataset ecommerce {
// ... other configurations
view main {
fields: [
orders.id,
orders.status,
users.email
]
}
}
Detailed Feature Comparison
LookML Parameter | Purpose | Support | Holistics Equivalent & Implementation |
---|---|---|---|
Structural Parameters | |||
extends | The extends parameter lets you build upon the content and settings from another Explore | ✅ | Holistics AML Extend |
extension: required | flags an Explore as requiring extension | ✔️ (partial) | Holistics doesn't support this exact concept but we can rebuild this via Function |
fields: [field-ref] | specify which fields from an Explore are exposed in the Explore UI | ✅ | Holistics Dataset Custom View |
tags: ["string"] | Specifies text that can be passed to other applications | 🕑 Coming Soon | |
Display Parameters | |||
description | add information about the Explore to the UI | ✅ | Dataset description: description: "your_description" |
group_label | change the default organization of the Explore menu | ✔️ (partially) | Holistics doesn't have the exact concept, but users can manually organize the Dataset to appropriate folders in Reporting layer |
hidden: yes or no | Hides an Explore from the Explore menu | ❌ | |
label | Changes the way an Explore appears in the Explore menu | ✅ | Holistics Dataset Label: label: "Your Dataset" |
query | Creates a predefined query for users to select in an Explore's Quick Start menu | ❌ | |
view_label | Specifies how a group of fields from the Explore's base view will be labeled in the field picker | ❌ | |
Filter Parameters | |||
access_filter | Adds user-specific filters to an Explore | ✅ | Holistics Row-level Permission |
always_filter | Adds filters a user can change, but not remove, to an Explore | ❌ | |
case_sensitive | Specifies whether filters are case-sensitive for an Explore | ❌ | |
sql_always_where: sql-block ;; | Inserts conditions into the query's WHERE clause that a user cannot change or remove | ❌ | |
sql_always_having: sql-block ;; | Inserts conditions into the query's HAVING clause that a user cannot change or remove | ❌ | |
Join Parameters | |||
always_join: [field-ref] | forces one or more joins to be included in the SQL that Looker generates | ❌ | |
join: identifier | define the join relationship between an Explore and a view | ❌ | Holistics uses relationship instead of pre-defined joins |
Query Parameters | |||
cancel_grouping_fields: [field-ref] | stop Looker from adding a GROUP BY clause to the SQL | ❌ | |
from: view-ref | Determines the view that will define the fields of an Explore | ❌ | Holistics doesn't have root model concept |
persist_for | modify the amount of time that cached query results are used | ❌ | |
persist_with | specify a datagroup caching policy to use for that specific Explore | ❌ | |
required_access_grants: [access-grant-ref] | Limits access to the Explore to only users whose user attribute values match the access grants | ✔️ (partially) | Share Dataset with Explorers and Viewers to explore. Check our "Dataset Sharing" document |
sql_table_name: sql-block ;; | Specifies the database table on which an Explore will be based | ❌ | |
view_name: view-ref | Specifies the view on which an Explore will be based | ❌ | Holistics doesn't have root model concept |
Aggregate Table Parameters | |||
aggregate_table | create aggregate tables that will minimize the number of queries required | ✅ | Aggregated Awareness (Pre-aggregate) |
Refinement Parameters | |||
final: yes or no | Indicates that the current refinement is the final refinement allowed for the Explore | ❌ |
(*) Looker Parameters that are not mentioned in this table are generally not supported