From fc17dd1742b9be4f1637e1b4742db2a2e88b9eb2 Mon Sep 17 00:00:00 2001 From: Jordan Stein Date: Mon, 8 Jan 2024 12:35:08 -0800 Subject: [PATCH 01/60] add conversion-metrics-docs --- website/docs/docs/build/conversion-metrics.md | 307 ++++++++++++++++++ .../conversion-metrics-fill-null.png | Bin 0 -> 99522 bytes 2 files changed, 307 insertions(+) create mode 100644 website/docs/docs/build/conversion-metrics.md create mode 100644 website/static/img/docs/dbt-cloud/semantic-layer/conversion-metrics-fill-null.png diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md new file mode 100644 index 00000000000..0a30b75aae5 --- /dev/null +++ b/website/docs/docs/build/conversion-metrics.md @@ -0,0 +1,307 @@ +--- +title: "Conversion metrics" +id: conversion +description: "Use Conversion metrics to measure conversion events." +sidebar_label: Conversion +tags: [Metrics, Semantic Layer] +--- + +Conversion metrics allow us to define when a base event happens and then a conversion event happens for a specific entity within some time range. For example, we might want to measure how often a user(entity) completes a visit(base event) and then purchases (conversion event) within 7 days(time window). This requires a time range and an entity to join on. This is different from a ratio metric because we include an entity in the pre-aggregated join. + +The specification for conversion metrics is as follows: + +| Parameter | Description | Type | Required/Optional | +| --- | --- | --- | --- | +| name | The name of the metric. | String | Required | +| description | The description of the metric. | String | Optional | +| type | The type of the metric. In this case conversion. | String | Required | +| label | The value that will be displayed in downstream tools. | String | Required | +| type_parameters | Configurations that are specific to each metric type | List | Required | +| conversion_type_params | Additional configuration specific to conversion metrics | List | Required | +| entity | The entity for each conversion event | Entity | Required | +| calculation | How we perform the calculation. Either conversion_rate or conversions. Default is conversion_rate | String | Required | +| base_measure | The base conversion event measure | Measure | Required | +| conversion_measure | The conversion event measure | Measure | Required | +| window | The time window for the conversion event to occur i.e 7 days, 1 week, 3 months. Defaults to infinity. | String | Required | +| constant_properties | List of constant properties. Defaults to None. | List | Optional | +| base_property | The property from the base semantic model that you want to hold constant. | Entity or Dimension | Optional | +| conversion_property | The property from the conversion semantic model that you want to hold constant. | Entity or Dimension | Optional | + +The following displays the complete specification for ratio metrics, along with an example: + +```bash +metric: + - name: The metric name # Required + description: the metric description # Required + type: conversion + type_params: + conversion_type_params: + entity: _entity_ # required + calculation: _calculation_type_ # optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits) + more to come + base_measure: _measure_ # required + conversion_measure: _measure_ # required + window: _time_window_ # optional. default: inf. window to join the two events on. Follows similar format as time windows elsewhere (i.e. 7 days) + constant_properties: # optional. List of constant properties default: None + - base_property: _dimension_or_entity_ # required. A reference to a dimension/entity of the semantic model linked to the base_measure + conversion_property: _dimension_or_entity_ # same as base above, but to the semantic model of the conversion_measure +``` + +**Conversion Metric Example** + +The following example walks through how we calculate a conversion metric step by step. Suppose we have two semantic models, Visits and Buys. The Visits table represents visits to an e-commerce site, and the buys table represents someone completing an order on that site. The underlying tables look like the following: + +**VISITS** + +| DS | USER_ID | REFERRER_ID | +| --- | --- | --- | +| 2020-01-01 | bob | facebook | +| 2020-01-04 | bob | google | +| 2020-01-07 | bob | amazon | + +**BUYS** + +| DS | USER_ID | REFERRER_ID | +| --- | --- | --- | +| 2020-01-02 | bob | facebook | +| 2020-01-07 | bob | amazon | + +Next, we define a conversion metric as follows: + +```yaml +- name: visit_to_buy_conversion_rate_7d + description: "Conversion rate from visiting the website to completing a transaction in 7 days" + type: conversion + label: Visit to Buy Conversion Rate (7 day window) + type_params: + conversion_type_params: + base_measure: visits + conversion_measure: sellers + entity: user + window: 7 days +``` + +To calculate the conversion, we need to be able to link the BUYS event to a VISITS event. Our approach is that a conversion will be linked to its closest base event. We walk through how the conversion is calculated in the following steps: + +### Step 1: + +This step joins the `buys` table to the `visits` table and gets all combinations of visits-buys events that match the join condition (any rows that have the same user and the buy happened at most 7 days after the visit). + +The SQL generated in these steps looks like the following: + +```sql +SELECT + v.ds + , v.user_id + , v.referrer_id + , b.ds + , b.uuid + , 1 AS buys +FROM VISITS v +INNER JOIN ( + SELECT *, UUID_STRING() AS uuid FROM BUYS -- Adds a UUID column to uniquely identify the different rows +) b +ON +v.user_id = b.user_id AND v.ds <= b.ds AND v.ds > b.ds - INTERVAL '7 day'; +``` + +The data set returns look like this. Note that there are two potential conversion events for the first visit. + +| V.DS | V.USER_ID | V.REFERRER_ID | B.DS | UUID | BUYS | +| --- | --- | --- | --- | --- | --- | +| 2020-01-01 | bob | facebook | 2020-01-02 | uuid1 | 1 | +| 2020-01-01 | bob | facebook | 2020-01-07 | uuid2 | 1 | +| 2020-01-04 | bob | google | 2020-01-07 | uuid2 | 1 | +| 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | + +### Step 2: + +Now in step 1, instead of returning the raw visit values, we can instead use a window function, we can partition by the conversion source and get the first_value ordered by visit ds descending to get the closest base event from the conversion event. + +```sql +SELECT + first_value(v.ds) OVER (PARTITION BY b.ds, b.user_id, b.uuid ORDER BY v.ds DESC NULLS FIRST) AS v.ds + , first_value(v.user_id) OVER (PARTITION BY b.ds, b.user_id, b.uuid ORDER BY v.ds DESC NULLS FIRST) AS user_id + , first_value(v.referrer_id) OVER (PARTITION BY b.ds, b.user_id, b.uuid ORDER BY v.ds DESC NULLS FIRST) AS referrer_id + , b.ds + , b.uuid + , 1 AS buys +FROM VISITS v +INNER JOIN ( + SELECT *, UUID_STRING() AS uuid FROM BUYS +) b +ON +v.user_id = b.user_id AND v.ds <= b.ds AND v.ds > b.ds - INTERVAL '7 day'; +``` + +**Returns** + +| V.DS | V.USER_ID | V.REFERRER_ID | B.DS | UUID | BUYS | +| --- | --- | --- | --- | --- | --- | +| 2020-01-01 | bob | facebook | 2020-01-02 | uuid1 | 1 | +| 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | +| 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | +| 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | + +As you can see we successfully linked the 2 conversions to the correct visit events. Now because of the join, we got every combination so there is a fanout result and after the window function, we get duplicates. To resolve this, we can use a distinct select to remove the duplicates and the UUID here helps identify which conversion is unique. + +### Step 3: + +Instead of regular select in the step 2, we use a distinct select to remove the duplicates. + +```sql +SELECT DISTINCT + first_value(v.ds) OVER (PARTITION BY b.ds, b.user_id, b.uuid ORDER BY v.ds DESC NULLS FIRST) AS v.ds + , first_value(v.user_id) OVER (PARTITION BY b.ds, b.user_id, b.uuid ORDER BY v.ds DESC NULLS FIRST) AS user_id + , first_value(v.referrer_id) OVER (PARTITION BY b.ds, b.user_id, b.uuid ORDER BY v.ds DESC NULLS FIRST) AS referrer_id + , b.ds + , b.uuid + , 1 AS buys +FROM VISITS v +INNER JOIN ( + SELECT *, UUID_STRING() AS uuid FROM BUYS +) b +ON +v.user_id = b.user_id AND v.ds <= b.ds AND v.ds > b.ds - INTERVAL '7 day'; +``` + +| V.DS | V.USER_ID | V.REFERRER_ID | B.DS | UUID | BUYS | +| --- | --- | --- | --- | --- | --- | +| 2020-01-01 | bob | facebook | 2020-01-02 | uuid1 | 1 | +| 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | + +Now we have a data set that contains each conversion linked to a visit event. + +1. aggregate the "conversions" table to get the total number of conversions +2. join the aggregated base measure table "opportunties" to the "conversions" table using the group by keys +3. calculate the conversion + +### **Step 4:** + +Now that we’ve tied each conversion event to a visit we can calculate the aggregated conversions and opportunities measures, and join them to calculate the actual conversion rate. The SQL to calculate the conversion rate is as follows: + +```sql +SELECT + COALESCE(subq_3.metric_time__day, subq_13.metric_time__day) AS metric_time__day +, CAST(MAX(subq_13.buys) AS DOUBLE) / CAST(NULLIF(MAX(subq_3.visits), 0) AS DOUBLE) AS visit_to_buy_conversion_rate_7d +FROM ( -- Base Measure + SELECT + metric_time__day + , SUM(visits) AS mqls + FROM ( + SELECT + DATE_TRUNC('day', first_contact_date) AS metric_time__day + , 1 as visits + FROM visits + ) subq_2 + GROUP BY + metric_time__day +) subq_3 +FULL OUTER JOIN ( -- Conversion Measure + SELECT + metric_time__day + , SUM(buys) AS sellers + FROM ( + ..... +#The output of this subquery is the table produced in Step 3. The SQL is hidden for legibility. +#To see the full SQL output and --explain to your conversion metric query. + ) subq_10 + GROUP BY + metric_time__day +) subq_13 +ON + subq_3.metric_time__day = subq_13.metric_time__day +GROUP BY +``` + +**Set the value of null conversion events** + +You may want to set the value of a null conversion event to zero instead of null, so the final data set returns zero. You can add the `fill_nulls_with` parameter to your conversion metric definition like this: + +```yaml +- name: vist_to_buy_conversion_rate_7_day_window + description: "Conversion rate from MQL to seller" + type: conversion + label: MQL to Seller Conversion Rate (1 week day window) + type_params: + conversion_type_params: + # calculation: CONVERSIONS + base_measure: mqls + conversion_measure: + name: sellers + fill_nulls_with: 0 + entity: mql + window: 1 week +``` + +This will return the following result set: + +![Screenshot 2024-01-04 at 2.31.11 PM.png](../website/static/img/docs/dbt-cloud/semantic-layer/conversion-metrics-fill-null.png) + +**Setting the calculation type:** + +The conversion calculation parameter can be used to either show the raw number of conversions or the conversion rate. The default value is the conversion rate. I can change the default to show the number of conversions by setting the `calculation: conversion` parameter: + +```yaml +- name: vist_to_buy_conversions_1_week_window + description: "Visit to Buy Conversions" + type: conversion + label: Visit to Buy Conversions (1 week window) + type_params: + conversion_type_params: + calculation: conversions + base_measure: visits + conversion_measure: + name: buys + fill_nulls_with: 0 + entity: user + window: 1 week +``` + +**Setting a constant property for a conversion metric** + +*If you’re not sure what a constant property is [Amplitude has a great blog post on constant properties. I recommend](https://amplitude.com/blog/holding-constant) reading this to get up to speed on the concept.* + +It's possible to add a constant property to a conversion metric to only count a conversions if this dimension or entity is the same for both the base and conversion event. For example, say you work at an e-commerce company and want to answer the following questions: + +*How often did visitors convert from View Item Details to Complete Purchase with the same product in each step?* + +What makes this question tricky to answer is users could have completed these two conversion milestones across many products. For example, viewed a pair of shoes, then a T-shirt, and eventually checked out with a bow tie. This would still count as a conversion, even tho the conversion event only happened for the bow tie. + +Back to our initial questions, we want to see how many customers viewed an item detail page and then completed *a purchase for the same product.* In this case, we would want to set product_id as the constant property. We would specify this in the configs as follows: + +```yaml +- name: view_item_detail_to_purchase_with_same_item + description: "Conversion rate for users who viewed the item detail page and purchased the item" + type: Conversion + label: View Item Detail > Purchase + type_params: + conversion_type_params: + calculation: conversions + base_measure: view_item_detail + conversion_measure: purchase + entity: user + window: 1 week + constant_properties: + - base_property: product + conversion_property: product +``` + +We will add an additional condition to the join to make sure the constant property is the same across conversion. + +```sql +SELECT DISTINCT + first_value(v.ds) OVER (PARTITION BY buy_source.ds, buy_source.user_id, buy_source.session_id ORDER BY v.ds DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS ds + , first_value(v.user_id) OVER (PARTITION BY buy_source.ds, buy_source.user_id, buy_source.session_id ORDER BY v.ds DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS user_id + , first_value(v.referrer_id) OVER (PARTITION BY buy_source.ds, buy_source.user_id, buy_source.session_id ORDER BY v.ds DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS referrer_id + , buy_source.uuid + , 1 AS buys + FROM {{ source_schema }}.fct_view_item_details v + INNER JOIN + ( + SELECT *, {{ generate_random_uuid() }} AS uuid FROM {{ source_schema }}.fct_purchases + ) buy_source + ON + v.user_id = buy_source.user_id + v.user_id = b.user_id AND v.ds <= b.ds AND v.ds > b.ds - INTERVAL '7 day'; + AND buy_source.product_id = v.product_id #Joining on the constant property product ID +``` \ No newline at end of file diff --git a/website/static/img/docs/dbt-cloud/semantic-layer/conversion-metrics-fill-null.png b/website/static/img/docs/dbt-cloud/semantic-layer/conversion-metrics-fill-null.png new file mode 100644 index 0000000000000000000000000000000000000000..0fd5e206ba7e3d9b2b5ba9b92246f4594f9a2c40 GIT binary patch literal 99522 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 sl;e79yV;kyOy-?8 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 Date: Tue, 9 Jan 2024 13:02:46 +0000 Subject: [PATCH 02/60] edits to conversion metrics v1 --- website/docs/docs/build/conversion-metrics.md | 77 +++++++++++-------- website/sidebars.js | 1 + 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 0a30b75aae5..e7768e91972 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -6,7 +6,13 @@ sidebar_label: Conversion tags: [Metrics, Semantic Layer] --- -Conversion metrics allow us to define when a base event happens and then a conversion event happens for a specific entity within some time range. For example, we might want to measure how often a user(entity) completes a visit(base event) and then purchases (conversion event) within 7 days(time window). This requires a time range and an entity to join on. This is different from a ratio metric because we include an entity in the pre-aggregated join. +Conversion metrics allow us to define when a base event happens and a subsequent conversion event happens for a specific entity within some time range. + +- **Example**: Track how often a user (entity) completes a visit (base event) and then makes a purchase (conversion event) within 7 days (time window). +- **Requirements**: A time range and an entity to join on. +- **How it differs from [Ratio metrics](/docs/build/ratio)**: Includes an entity in the pre-aggregated join. + +## Parameters The specification for conversion metrics is as follows: @@ -14,41 +20,48 @@ The specification for conversion metrics is as follows: | --- | --- | --- | --- | | name | The name of the metric. | String | Required | | description | The description of the metric. | String | Optional | -| type | The type of the metric. In this case conversion. | String | Required | -| label | The value that will be displayed in downstream tools. | String | Required | -| type_parameters | Configurations that are specific to each metric type | List | Required | -| conversion_type_params | Additional configuration specific to conversion metrics | List | Required | -| entity | The entity for each conversion event | Entity | Required | -| calculation | How we perform the calculation. Either conversion_rate or conversions. Default is conversion_rate | String | Required | -| base_measure | The base conversion event measure | Measure | Required | -| conversion_measure | The conversion event measure | Measure | Required | -| window | The time window for the conversion event to occur i.e 7 days, 1 week, 3 months. Defaults to infinity. | String | Required | +| type | The type of the metric (such as derived, ratio, and so on). In this case, set as 'conversion' | String | Required | +| label | Displayed value in downstream tools. | String | Required | +| type_parameters | Specific configurations for each metric type. | List | Required | +| conversion_type_params | Additional configuration specific to conversion metrics. | List | Required | +| entity | The entity for each conversion event. | Entity | Required | +| calculation | Method of calculation. Either `conversion_rate` or `conversions`. Default is `conversion_rate`. | String | Required | +| base_measure | The base conversion event measure. | Measure | Required | +| conversion_measure | The conversion event measure. | Measure | Required | +| window | The time window for the conversion event, such as 7 days, 1 week, 3 months. Defaults to infinity. | String | Required | | constant_properties | List of constant properties. Defaults to None. | List | Optional | | base_property | The property from the base semantic model that you want to hold constant. | Entity or Dimension | Optional | | conversion_property | The property from the conversion semantic model that you want to hold constant. | Entity or Dimension | Optional | -The following displays the complete specification for ratio metrics, along with an example: - -```bash -metric: - - name: The metric name # Required - description: the metric description # Required - type: conversion - type_params: - conversion_type_params: - entity: _entity_ # required - calculation: _calculation_type_ # optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits) + more to come - base_measure: _measure_ # required - conversion_measure: _measure_ # required - window: _time_window_ # optional. default: inf. window to join the two events on. Follows similar format as time windows elsewhere (i.e. 7 days) - constant_properties: # optional. List of constant properties default: None - - base_property: _dimension_or_entity_ # required. A reference to a dimension/entity of the semantic model linked to the base_measure - conversion_property: _dimension_or_entity_ # same as base above, but to the semantic model of the conversion_measure +The following code example displays the complete specification for conversion metrics and details how they're applied: + +```yaml +metrics: + - name: The metric name # Required + description: the metric description # Required + type: conversion + type_params: + conversion_type_params: + entity: _entity_ # Required + calculation: _calculation_type_ # Optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits) and more to come. + base_measure: _measure_ # Required + conversion_measure: _measure_ # Required + window: _time_window_ # Optional. default: inf. window to join the two events on. Follows similar format as time windows elsewhere (such as, 7 days) + constant_properties: # Optional. List of constant properties default: None + - base_property: _dimension_or_entity_ # Required. A reference to a dimension/entity of the semantic model linked to the base_measure + conversion_property: _dimension_or_entity_ # Same as base above, but to the semantic model of the conversion_measure ``` -**Conversion Metric Example** +### Conversion metric example + +The following example will measure conversions from website visits (_Visits_ table) to order completions (_Buys_ table).Let's go through how to calculate a conversion metric step by step. + +1. Suppose we have two semantic models, _Visits_ and _Buys_: -The following example walks through how we calculate a conversion metric step by step. Suppose we have two semantic models, Visits and Buys. The Visits table represents visits to an e-commerce site, and the buys table represents someone completing an order on that site. The underlying tables look like the following: +- The _Visits_ table represents visits to an e-commerce site +- The _Buys_ table represents someone completing an order on that site. + +The underlying tables look like the following: **VISITS** @@ -172,7 +185,7 @@ v.user_id = b.user_id AND v.ds <= b.ds AND v.ds > b.ds - INTERVAL '7 day'; Now we have a data set that contains each conversion linked to a visit event. 1. aggregate the "conversions" table to get the total number of conversions -2. join the aggregated base measure table "opportunties" to the "conversions" table using the group by keys +2. join the aggregated base measure table "opportunities" to the "conversions" table using the group by keys 3. calculate the conversion ### **Step 4:** @@ -235,7 +248,7 @@ You may want to set the value of a null conversion event to zero instead of null This will return the following result set: -![Screenshot 2024-01-04 at 2.31.11 PM.png](../website/static/img/docs/dbt-cloud/semantic-layer/conversion-metrics-fill-null.png) + **Setting the calculation type:** @@ -304,4 +317,4 @@ SELECT DISTINCT v.user_id = buy_source.user_id v.user_id = b.user_id AND v.ds <= b.ds AND v.ds > b.ds - INTERVAL '7 day'; AND buy_source.product_id = v.product_id #Joining on the constant property product ID -``` \ No newline at end of file +``` diff --git a/website/sidebars.js b/website/sidebars.js index 27bcd1147a3..8cdeabd804c 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -323,6 +323,7 @@ const sidebarSettings = { link: { type: "doc", id: "docs/build/metrics-overview" }, items: [ "docs/build/metrics-overview", + "docs/build/conversion", "docs/build/cumulative", "docs/build/derived", "docs/build/ratio", From fe44dbc8a9650eca284cdd373a568debb29eeb3c Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Tue, 9 Jan 2024 13:37:45 +0000 Subject: [PATCH 03/60] more changes v2 --- website/docs/docs/build/conversion-metrics.md | 108 +++++++++--------- 1 file changed, 57 insertions(+), 51 deletions(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index e7768e91972..b6ff177fed7 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -52,18 +52,19 @@ metrics: conversion_property: _dimension_or_entity_ # Same as base above, but to the semantic model of the conversion_measure ``` -### Conversion metric example +## Conversion metric example -The following example will measure conversions from website visits (_Visits_ table) to order completions (_Buys_ table).Let's go through how to calculate a conversion metric step by step. +The following example will measure conversions from website visits (`VISITS` table) to order completions (`BUYS` table). Let's calculate a conversion metric step by step. -1. Suppose we have two semantic models, _Visits_ and _Buys_: +Suppose we have two semantic models, `VISITS` and `BUYS`: -- The _Visits_ table represents visits to an e-commerce site -- The _Buys_ table represents someone completing an order on that site. +- The `VISITS` table represents visits to an e-commerce site +- The `BUYS` table represents someone completing an order on that site. -The underlying tables look like the following: +The underlying tables look like the following: -**VISITS** +`VISITS`
+Contains user visits with `USER_ID` and `REFERRER_ID`. | DS | USER_ID | REFERRER_ID | | --- | --- | --- | @@ -71,7 +72,8 @@ The underlying tables look like the following: | 2020-01-04 | bob | google | | 2020-01-07 | bob | amazon | -**BUYS** +`BUYS`
+Records completed orders with `USER_ID` and `REFERRER_ID`. | DS | USER_ID | REFERRER_ID | | --- | --- | --- | @@ -82,42 +84,43 @@ Next, we define a conversion metric as follows: ```yaml - name: visit_to_buy_conversion_rate_7d - description: "Conversion rate from visiting the website to completing a transaction in 7 days" - type: conversion - label: Visit to Buy Conversion Rate (7 day window) - type_params: - conversion_type_params: - base_measure: visits - conversion_measure: sellers - entity: user - window: 7 days + description: "Conversion rate from visiting to transaction in 7 days" + type: conversion + label: Visit to Buy Conversion Rate (7 day window) + type_params: + conversion_type_params: + base_measure: visits + conversion_measure: sellers + entity: user + window: 7 days ``` -To calculate the conversion, we need to be able to link the BUYS event to a VISITS event. Our approach is that a conversion will be linked to its closest base event. We walk through how the conversion is calculated in the following steps: +To calculate the conversion, link the `BUYS` event to the nearest `VISITS` event (or closest base event). The following steps explain this process in more detail: -### Step 1: +### Step 1: Join `VISITS` and `BUYS` -This step joins the `buys` table to the `visits` table and gets all combinations of visits-buys events that match the join condition (any rows that have the same user and the buy happened at most 7 days after the visit). +This step joins the `BUYS` table to the `VISITS` table and gets all combinations of visits-buys events that match the join condition where buys occur within 7 days of the visit (any rows that have the same user and a buy happened at most 7 days after the visit). The SQL generated in these steps looks like the following: ```sql -SELECT - v.ds - , v.user_id - , v.referrer_id - , b.ds - , b.uuid - , 1 AS buys -FROM VISITS v -INNER JOIN ( - SELECT *, UUID_STRING() AS uuid FROM BUYS -- Adds a UUID column to uniquely identify the different rows +select + v.ds, + v.user_id, + v.referrer_id, + b.ds, + b.uuid, + 1 as buys +from visits v +inner join ( + select *, uuid_string() as uuid from buys -- Adds a uuid column to uniquely identify the different rows ) b -ON -v.user_id = b.user_id AND v.ds <= b.ds AND v.ds > b.ds - INTERVAL '7 day'; +on +v.user_id = b.user_id and v.ds <= b.ds and v.ds > b.ds - interval '7 day' ``` -The data set returns look like this. Note that there are two potential conversion events for the first visit. +The dataset returns the following: +Note that there are two potential conversion events for the first visit. | V.DS | V.USER_ID | V.REFERRER_ID | B.DS | UUID | BUYS | | --- | --- | --- | --- | --- | --- | @@ -126,27 +129,28 @@ The data set returns look like this. Note that there are two potential conversio | 2020-01-04 | bob | google | 2020-01-07 | uuid2 | 1 | | 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | -### Step 2: +### Step 2: Refine with Window Function -Now in step 1, instead of returning the raw visit values, we can instead use a window function, we can partition by the conversion source and get the first_value ordered by visit ds descending to get the closest base event from the conversion event. +Instead of returning the raw visit values, use window functions to link conversions to the closest base event. You can partition by the conversion source and get the `first_value` ordered by `visit ds`, descending to get the closest base event from the conversion event: ```sql -SELECT - first_value(v.ds) OVER (PARTITION BY b.ds, b.user_id, b.uuid ORDER BY v.ds DESC NULLS FIRST) AS v.ds - , first_value(v.user_id) OVER (PARTITION BY b.ds, b.user_id, b.uuid ORDER BY v.ds DESC NULLS FIRST) AS user_id - , first_value(v.referrer_id) OVER (PARTITION BY b.ds, b.user_id, b.uuid ORDER BY v.ds DESC NULLS FIRST) AS referrer_id - , b.ds - , b.uuid - , 1 AS buys -FROM VISITS v -INNER JOIN ( - SELECT *, UUID_STRING() AS uuid FROM BUYS +select + first_value(v.ds) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc nulls first) as v_ds, + first_value(v.user_id) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc nulls first) as user_id, + first_value(v.referrer_id) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc nulls first) as referrer_id, + b.ds, + b.uuid, + 1 as buys +from visits v +inner join ( + select *, uuid_string() as uuid from buys ) b -ON -v.user_id = b.user_id AND v.ds <= b.ds AND v.ds > b.ds - INTERVAL '7 day'; +on +v.user_id = b.user_id and v.ds <= b.ds and v.ds > b.ds - interval '7 day' + ``` -**Returns** +The dataset returns the following: | V.DS | V.USER_ID | V.REFERRER_ID | B.DS | UUID | BUYS | | --- | --- | --- | --- | --- | --- | @@ -155,11 +159,13 @@ v.user_id = b.user_id AND v.ds <= b.ds AND v.ds > b.ds - INTERVAL '7 day'; | 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | | 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | -As you can see we successfully linked the 2 conversions to the correct visit events. Now because of the join, we got every combination so there is a fanout result and after the window function, we get duplicates. To resolve this, we can use a distinct select to remove the duplicates and the UUID here helps identify which conversion is unique. +This workflow links the two conversions to the correct visit events. Due to the join, we end up with multiple combinations, leading to fanout results. After applying the window function, duplicates appear. + +To resolve this and eliminate duplicates, use a distinct select, and the UUID helps identify which conversion is unique. -### Step 3: +### Step 3: Remove duplicates -Instead of regular select in the step 2, we use a distinct select to remove the duplicates. +Instead of regular select in the [Step 2](#step-2-refine-with-window-function), use a distinct select to remove the duplicates. ```sql SELECT DISTINCT From f62e3c6628ab1684f6d548f8ea533fd720fdbbf0 Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Tue, 9 Jan 2024 14:00:28 +0000 Subject: [PATCH 04/60] edits v3 --- website/docs/docs/build/conversion-metrics.md | 171 ++++++++++-------- 1 file changed, 96 insertions(+), 75 deletions(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index b6ff177fed7..f7592d80d58 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -43,7 +43,7 @@ metrics: type_params: conversion_type_params: entity: _entity_ # Required - calculation: _calculation_type_ # Optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits) and more to come. + calculation: _calculation_type_ # Optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits), and more to come. base_measure: _measure_ # Required conversion_measure: _measure_ # Required window: _time_window_ # Optional. default: inf. window to join the two events on. Follows similar format as time windows elsewhere (such as, 7 days) @@ -129,7 +129,7 @@ Note that there are two potential conversion events for the first visit. | 2020-01-04 | bob | google | 2020-01-07 | uuid2 | 1 | | 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | -### Step 2: Refine with Window Function +### Step 2: Refine with window function Instead of returning the raw visit values, use window functions to link conversions to the closest base event. You can partition by the conversion source and get the `first_value` ordered by `visit ds`, descending to get the closest base event from the conversion event: @@ -161,104 +161,121 @@ The dataset returns the following: This workflow links the two conversions to the correct visit events. Due to the join, we end up with multiple combinations, leading to fanout results. After applying the window function, duplicates appear. -To resolve this and eliminate duplicates, use a distinct select, and the UUID helps identify which conversion is unique. +To resolve this and eliminate duplicates, use a distinct select. The UUID also helps identify which conversion is unique. The next step go in to more detail on how to do this. ### Step 3: Remove duplicates -Instead of regular select in the [Step 2](#step-2-refine-with-window-function), use a distinct select to remove the duplicates. +Instead of regular select used in the [Step 2](#step-2-refine-with-window-function), use a distinct select to remove the duplicates: ```sql -SELECT DISTINCT - first_value(v.ds) OVER (PARTITION BY b.ds, b.user_id, b.uuid ORDER BY v.ds DESC NULLS FIRST) AS v.ds - , first_value(v.user_id) OVER (PARTITION BY b.ds, b.user_id, b.uuid ORDER BY v.ds DESC NULLS FIRST) AS user_id - , first_value(v.referrer_id) OVER (PARTITION BY b.ds, b.user_id, b.uuid ORDER BY v.ds DESC NULLS FIRST) AS referrer_id - , b.ds - , b.uuid - , 1 AS buys -FROM VISITS v -INNER JOIN ( - SELECT *, UUID_STRING() AS uuid FROM BUYS +select distinct + first_value(v.ds) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc nulls first) as v_ds, + first_value(v.user_id) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc nulls first) as user_id, + first_value(v.referrer_id) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc nulls first) as referrer_id, + b.ds, + b.uuid, + 1 as buys +from visits v +inner join ( + select *, uuid_string() as uuid from buys ) b -ON -v.user_id = b.user_id AND v.ds <= b.ds AND v.ds > b.ds - INTERVAL '7 day'; +on +v.user_id = b.user_id and v.ds <= b.ds and v.ds > b.ds - interval '7 day'; ``` +The dataset returns the following: + | V.DS | V.USER_ID | V.REFERRER_ID | B.DS | UUID | BUYS | | --- | --- | --- | --- | --- | --- | | 2020-01-01 | bob | facebook | 2020-01-02 | uuid1 | 1 | | 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | -Now we have a data set that contains each conversion linked to a visit event. +We now have a dataset where every conversion is connected to a visit event. To proceed: -1. aggregate the "conversions" table to get the total number of conversions -2. join the aggregated base measure table "opportunities" to the "conversions" table using the group by keys -3. calculate the conversion +1. Sum up the total conversions in the "conversions" table. +2. Combine this table with the "opportunities" table, matching them based on group keys. +3. Calculate the conversion rate. -### **Step 4:** +### Step 4: Aggregate and calculate -Now that we’ve tied each conversion event to a visit we can calculate the aggregated conversions and opportunities measures, and join them to calculate the actual conversion rate. The SQL to calculate the conversion rate is as follows: +Now that we’ve tied each conversion event to a visit, we can calculate the aggregated conversions and opportunities measures, and join them to calculate the actual conversion rate. The SQL to calculate the conversion rate is as follows: ```sql -SELECT - COALESCE(subq_3.metric_time__day, subq_13.metric_time__day) AS metric_time__day -, CAST(MAX(subq_13.buys) AS DOUBLE) / CAST(NULLIF(MAX(subq_3.visits), 0) AS DOUBLE) AS visit_to_buy_conversion_rate_7d -FROM ( -- Base Measure - SELECT - metric_time__day - , SUM(visits) AS mqls - FROM ( - SELECT - DATE_TRUNC('day', first_contact_date) AS metric_time__day - , 1 as visits - FROM visits +select + coalesce(subq_3.metric_time__day, subq_13.metric_time__day) as metric_time__day, + cast(max(subq_13.buys) as double) / cast(nullif(max(subq_3.visits), 0) as double) as visit_to_buy_conversion_rate_7d +from ( -- base measure + select + metric_time__day, + sum(visits) as mqls + from ( + select + date_trunc('day', first_contact_date) as metric_time__day, + 1 as visits + from visits ) subq_2 - GROUP BY + group by metric_time__day ) subq_3 -FULL OUTER JOIN ( -- Conversion Measure - SELECT - metric_time__day - , SUM(buys) AS sellers - FROM ( - ..... -#The output of this subquery is the table produced in Step 3. The SQL is hidden for legibility. -#To see the full SQL output and --explain to your conversion metric query. +full outer join ( -- conversion measure + select + metric_time__day, + sum(buys) as sellers + from ( + -- ... + -- The output of this subquery is the table produced in Step 3. The SQL is hidden for legibility. + -- To see the full SQL output and --explain to your conversion metric query. ) subq_10 - GROUP BY + group by metric_time__day ) subq_13 -ON +on subq_3.metric_time__day = subq_13.metric_time__day -GROUP BY +group by + metric_time__day ``` -**Set the value of null conversion events** +### Additional settings + +Use the following additional settings to customize your conversion metrics: + +- Null conversion values: Set null conversions to zero using `fill_nulls_with`. +- Calculation type: Choose between showing raw conversions or conversion rate. +- Constant property: Add conditions to join conversions on constant properties for specific scenarios. -You may want to set the value of a null conversion event to zero instead of null, so the final data set returns zero. You can add the `fill_nulls_with` parameter to your conversion metric definition like this: + + + +To return zero in the final data set, you may want to set the value of a null conversion event to zero instead of null. You can add the `fill_nulls_with` parameter to your conversion metric definition like this: ```yaml - name: vist_to_buy_conversion_rate_7_day_window - description: "Conversion rate from MQL to seller" - type: conversion - label: MQL to Seller Conversion Rate (1 week day window) - type_params: - conversion_type_params: - # calculation: CONVERSIONS - base_measure: mqls - conversion_measure: - name: sellers - fill_nulls_with: 0 - entity: mql - window: 1 week + description: "Conversion rate from MQL to seller" + type: conversion + label: MQL to Seller Conversion Rate (1 week day window) + type_params: + conversion_type_params: + calculation: conversions + base_measure: mqls + conversion_measure: + name: sellers + fill_nulls_with: 0 + entity: mql + window: 1 week + ``` This will return the following result set: - + + + -**Setting the calculation type:** + -The conversion calculation parameter can be used to either show the raw number of conversions or the conversion rate. The default value is the conversion rate. I can change the default to show the number of conversions by setting the `calculation: conversion` parameter: +Use the conversion calculation parameter to either show the raw number of conversions or the conversion rate. The default value is the conversion rate. + +You can change the default to display the number of conversions by setting the `calculation: conversion` parameter: ```yaml - name: vist_to_buy_conversions_1_week_window @@ -276,7 +293,9 @@ The conversion calculation parameter can be used to either show the raw number o window: 1 week ``` -**Setting a constant property for a conversion metric** + + + *If you’re not sure what a constant property is [Amplitude has a great blog post on constant properties. I recommend](https://amplitude.com/blog/holding-constant) reading this to get up to speed on the concept.* @@ -290,17 +309,17 @@ Back to our initial questions, we want to see how many customers viewed an item ```yaml - name: view_item_detail_to_purchase_with_same_item - description: "Conversion rate for users who viewed the item detail page and purchased the item" - type: Conversion - label: View Item Detail > Purchase - type_params: - conversion_type_params: - calculation: conversions - base_measure: view_item_detail - conversion_measure: purchase - entity: user - window: 1 week - constant_properties: + description: "Conversion rate for users who viewed the item detail page and purchased the item" + type: Conversion + label: View Item Detail > Purchase + type_params: + conversion_type_params: + calculation: conversions + base_measure: view_item_detail + conversion_measure: purchase + entity: user + window: 1 week + constant_properties: - base_property: product conversion_property: product ``` @@ -324,3 +343,5 @@ SELECT DISTINCT v.user_id = b.user_id AND v.ds <= b.ds AND v.ds > b.ds - INTERVAL '7 day'; AND buy_source.product_id = v.product_id #Joining on the constant property product ID ``` + + From 7714cd31594b6e4ec3db42801487f6337f6b1493 Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Tue, 9 Jan 2024 15:46:36 +0000 Subject: [PATCH 05/60] v4 --- website/docs/docs/build/conversion-metrics.md | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index f7592d80d58..197603cb76b 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -297,15 +297,14 @@ You can change the default to display the number of conversions by setting the ` -*If you’re not sure what a constant property is [Amplitude has a great blog post on constant properties. I recommend](https://amplitude.com/blog/holding-constant) reading this to get up to speed on the concept.* +*Refer to [Amplitude's blog posts on constant properties](https://amplitude.com/blog/holding-constant) to learn about this concept.* -It's possible to add a constant property to a conversion metric to only count a conversions if this dimension or entity is the same for both the base and conversion event. For example, say you work at an e-commerce company and want to answer the following questions: +You can add a constant property to a conversion metric to count only those conversions where a specific dimension or entity matches in both the base and conversion events. For example, if you're at an e-commerce company and want to answer the following questions: -*How often did visitors convert from View Item Details to Complete Purchase with the same product in each step?* +- How often did visitors convert from _View Item Details_ to _Complete Purchase_ with the same product in each step? + What makes this question tricky to answer is users could have completed these two conversion milestones across many products. For example, viewed a pair of shoes, then a T-shirt, and eventually checked out with a bow tie. This would still count as a conversion, even though the conversion event only happened for the bow tie. -What makes this question tricky to answer is users could have completed these two conversion milestones across many products. For example, viewed a pair of shoes, then a T-shirt, and eventually checked out with a bow tie. This would still count as a conversion, even tho the conversion event only happened for the bow tie. - -Back to our initial questions, we want to see how many customers viewed an item detail page and then completed *a purchase for the same product.* In this case, we would want to set product_id as the constant property. We would specify this in the configs as follows: +Back to our initial questions, we want to see how many customers viewed an item detail page and then completed a purchase for the _same_ product. In this case, we would want to set `product_id` as the constant property. We would specify this in the configs as follows: ```yaml - name: view_item_detail_to_purchase_with_same_item @@ -324,24 +323,27 @@ Back to our initial questions, we want to see how many customers viewed an item conversion_property: product ``` -We will add an additional condition to the join to make sure the constant property is the same across conversion. +We will add an additional condition to the join to make sure the constant property is the same across conversion. ```sql -SELECT DISTINCT - first_value(v.ds) OVER (PARTITION BY buy_source.ds, buy_source.user_id, buy_source.session_id ORDER BY v.ds DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS ds - , first_value(v.user_id) OVER (PARTITION BY buy_source.ds, buy_source.user_id, buy_source.session_id ORDER BY v.ds DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS user_id - , first_value(v.referrer_id) OVER (PARTITION BY buy_source.ds, buy_source.user_id, buy_source.session_id ORDER BY v.ds DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS referrer_id - , buy_source.uuid - , 1 AS buys - FROM {{ source_schema }}.fct_view_item_details v - INNER JOIN - ( - SELECT *, {{ generate_random_uuid() }} AS uuid FROM {{ source_schema }}.fct_purchases - ) buy_source - ON - v.user_id = buy_source.user_id - v.user_id = b.user_id AND v.ds <= b.ds AND v.ds > b.ds - INTERVAL '7 day'; - AND buy_source.product_id = v.product_id #Joining on the constant property product ID +select distinct + first_value(v.ds) over (partition by buy_source.ds, buy_source.user_id, buy_source.session_id order by v.ds desc rows between unbounded preceding and unbounded following) as ds, + first_value(v.user_id) over (partition by buy_source.ds, buy_source.user_id, buy_source.session_id order by v.ds desc rows between unbounded preceding and unbounded following) as user_id, + first_value(v.referrer_id) over (partition by buy_source.ds, buy_source.user_id, buy_source.session_id order by v.ds desc rows between unbounded preceding and unbounded following) as referrer_id, + buy_source.uuid, + 1 as buys +from {{ source_schema }}.fct_view_item_details v +inner join + ( + select *, {{ generate_random_uuid() }} as uuid from {{ source_schema }}.fct_purchases + ) buy_source +on + v.user_id = buy_source.user_id + and v.ds <= buy_source.ds + and v.ds > buy_source.ds - interval '7 day' + and buy_source.product_id = v.product_id --Joining on the constant property product_id + ``` + From c9cfe842149004f530aab2cde9805560fc0d193c Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Tue, 9 Jan 2024 16:01:32 +0000 Subject: [PATCH 06/60] add in metrics overview page --- website/docs/docs/build/metrics-overview.md | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/website/docs/docs/build/metrics-overview.md b/website/docs/docs/build/metrics-overview.md index b6ccc1c3b9c..47d8b698c71 100644 --- a/website/docs/docs/build/metrics-overview.md +++ b/website/docs/docs/build/metrics-overview.md @@ -48,6 +48,27 @@ This page explains the different supported metric types you can add to your dbt - [Ratio](#ratio-metrics) — Create a ratio out of two measures. --> +### Conversion metrics + +[Conversion metrics](/docs/build/conversion) help you track when a base event and a subsequent conversion event occurs for an entity within a set time period. + +```yaml +metrics: + - name: The metric name # Required + description: the metric description # Required + type: conversion + type_params: + conversion_type_params: + entity: _entity_ # Required + calculation: _calculation_type_ # Optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits), and more to come. + base_measure: _measure_ # Required + conversion_measure: _measure_ # Required + window: _time_window_ # Optional. default: inf. window to join the two events on. Follows similar format as time windows elsewhere (such as, 7 days) + constant_properties: # Optional. List of constant properties default: None + - base_property: _dimension_or_entity_ # Required. A reference to a dimension/entity of the semantic model linked to the base_measure + conversion_property: _dimension_or_entity_ # Same as base above, but to the semantic model of the conversion_measure +``` + ### Cumulative metrics [Cumulative metrics](/docs/build/cumulative) aggregate a measure over a given window. If no window is specified, the window would accumulate the measure over all time. **Note**, you will need to create the [time spine model](/docs/build/metricflow-time-spine) before you add cumulative metrics. @@ -66,6 +87,7 @@ metrics: window: 7 days ``` + ### Derived metrics [Derived metrics](/docs/build/derived) are defined as an expression of other metrics. Derived metrics allow you to do calculations on top of metrics. From 516f1690613ec88e7861ee8c979f897be7c7e4ab Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Tue, 9 Jan 2024 16:14:20 +0000 Subject: [PATCH 07/60] tweak for clarity --- website/docs/docs/build/conversion-metrics.md | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 197603cb76b..4cf4290acdb 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -54,7 +54,7 @@ metrics: ## Conversion metric example -The following example will measure conversions from website visits (`VISITS` table) to order completions (`BUYS` table). Let's calculate a conversion metric step by step. +The following example will measure conversions from website visits (`VISITS` table) to order completions (`BUYS` table). Let's calculate a conversion metric for this scenario step by step. Suppose we have two semantic models, `VISITS` and `BUYS`: @@ -161,7 +161,7 @@ The dataset returns the following: This workflow links the two conversions to the correct visit events. Due to the join, we end up with multiple combinations, leading to fanout results. After applying the window function, duplicates appear. -To resolve this and eliminate duplicates, use a distinct select. The UUID also helps identify which conversion is unique. The next step go in to more detail on how to do this. +To resolve this and eliminate duplicates, use a distinct select. The UUID also helps identify which conversion is unique. The next steps provide more detail on how to do this. ### Step 3: Remove duplicates @@ -198,7 +198,7 @@ We now have a dataset where every conversion is connected to a visit event. To p ### Step 4: Aggregate and calculate -Now that we’ve tied each conversion event to a visit, we can calculate the aggregated conversions and opportunities measures, and join them to calculate the actual conversion rate. The SQL to calculate the conversion rate is as follows: +Now that we’ve tied each conversion event to a visit, we can calculate the aggregated conversions and opportunities measures. Then we can join them to calculate the actual conversion rate. The SQL to calculate the conversion rate is as follows: ```sql select @@ -224,7 +224,7 @@ full outer join ( -- conversion measure from ( -- ... -- The output of this subquery is the table produced in Step 3. The SQL is hidden for legibility. - -- To see the full SQL output and --explain to your conversion metric query. + -- To see the full SQL output, add --explain to your conversion metric query. ) subq_10 group by metric_time__day @@ -244,7 +244,7 @@ Use the following additional settings to customize your conversion metrics: - Constant property: Add conditions to join conversions on constant properties for specific scenarios. - + To return zero in the final data set, you may want to set the value of a null conversion event to zero instead of null. You can add the `fill_nulls_with` parameter to your conversion metric definition like this: @@ -271,7 +271,7 @@ This will return the following result set: - + Use the conversion calculation parameter to either show the raw number of conversions or the conversion rate. The default value is the conversion rate. @@ -295,16 +295,19 @@ You can change the default to display the number of conversions by setting the ` - + *Refer to [Amplitude's blog posts on constant properties](https://amplitude.com/blog/holding-constant) to learn about this concept.* -You can add a constant property to a conversion metric to count only those conversions where a specific dimension or entity matches in both the base and conversion events. For example, if you're at an e-commerce company and want to answer the following questions: +You can add a constant property to a conversion metric to count only those conversions where a specific dimension or entity matches in both the base and conversion events. -- How often did visitors convert from _View Item Details_ to _Complete Purchase_ with the same product in each step? - What makes this question tricky to answer is users could have completed these two conversion milestones across many products. For example, viewed a pair of shoes, then a T-shirt, and eventually checked out with a bow tie. This would still count as a conversion, even though the conversion event only happened for the bow tie. +For example, if you're at an e-commerce company and want to answer the following questions: +- _How often did visitors convert from `View Item Details` to `Complete Purchase` with the same product in each step?_
+ - What makes this question tricky to answer is users could have completed these two conversion milestones across many products. For example, viewed a pair of shoes, then a T-shirt, and eventually checked out with a bow tie. This would still count as a conversion, even though the conversion event only happened for the bow tie. -Back to our initial questions, we want to see how many customers viewed an item detail page and then completed a purchase for the _same_ product. In this case, we would want to set `product_id` as the constant property. We would specify this in the configs as follows: +Back to our initial questions, we want to see how many customers viewed an item detail page and then completed a purchase for the _same_ product. + +In this case, we would want to set `product_id` as the constant property. We would specify this in the configs as follows: ```yaml - name: view_item_detail_to_purchase_with_same_item From 2e487c4fd07d82f30a76786400870a49d84b7c0f Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Tue, 9 Jan 2024 16:23:47 +0000 Subject: [PATCH 08/60] turn to code --- website/docs/docs/build/conversion-metrics.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 4cf4290acdb..e9dce986641 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -18,20 +18,20 @@ The specification for conversion metrics is as follows: | Parameter | Description | Type | Required/Optional | | --- | --- | --- | --- | -| name | The name of the metric. | String | Required | -| description | The description of the metric. | String | Optional | -| type | The type of the metric (such as derived, ratio, and so on). In this case, set as 'conversion' | String | Required | -| label | Displayed value in downstream tools. | String | Required | -| type_parameters | Specific configurations for each metric type. | List | Required | -| conversion_type_params | Additional configuration specific to conversion metrics. | List | Required | -| entity | The entity for each conversion event. | Entity | Required | -| calculation | Method of calculation. Either `conversion_rate` or `conversions`. Default is `conversion_rate`. | String | Required | -| base_measure | The base conversion event measure. | Measure | Required | -| conversion_measure | The conversion event measure. | Measure | Required | -| window | The time window for the conversion event, such as 7 days, 1 week, 3 months. Defaults to infinity. | String | Required | -| constant_properties | List of constant properties. Defaults to None. | List | Optional | -| base_property | The property from the base semantic model that you want to hold constant. | Entity or Dimension | Optional | -| conversion_property | The property from the conversion semantic model that you want to hold constant. | Entity or Dimension | Optional | +| `name` | The name of the metric. | String | Required | +| `description` | The description of the metric. | String | Optional | +| `type` | The type of the metric (such as derived, ratio, and so on). In this case, set as 'conversion' | String | Required | +| `label` | Displayed value in downstream tools. | String | Required | +| `type_parameters` | Specific configurations for each metric type. | List | Required | +| `conversion_type_params` | Additional configuration specific to conversion metrics. | List | Required | +| `entity` | The entity for each conversion event. | Entity | Required | +| `calculation` | Method of calculation. Either `conversion_rate` or `conversions`. Default is `conversion_rate`. | String | Required | +| `base_measure` | The base conversion event measure. | Measure | Required | +| `conversion_measure` | The conversion event measure. | Measure | Required | +| `window` | The time window for the conversion event, such as 7 days, 1 week, 3 months. Defaults to infinity. | String | Required | +| `constant_properties` | List of constant properties. Defaults to None. | List | Optional | +| `base_property` | The property from the base semantic model that you want to hold constant. | Entity or Dimension | Optional | +| `conversion_property` | The property from the conversion semantic model that you want to hold constant. | Entity or Dimension | Optional | The following code example displays the complete specification for conversion metrics and details how they're applied: From e290f923f84b321cf3e25d7456b6a1ed0814b8ee Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:13:38 +0000 Subject: [PATCH 09/60] Update website/docs/docs/build/conversion-metrics.md --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index e9dce986641..1856d6a38ec 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -22,7 +22,7 @@ The specification for conversion metrics is as follows: | `description` | The description of the metric. | String | Optional | | `type` | The type of the metric (such as derived, ratio, and so on). In this case, set as 'conversion' | String | Required | | `label` | Displayed value in downstream tools. | String | Required | -| `type_parameters` | Specific configurations for each metric type. | List | Required | +| `type_params` | Specific configurations for each metric type. | List | Required | | `conversion_type_params` | Additional configuration specific to conversion metrics. | List | Required | | `entity` | The entity for each conversion event. | Entity | Required | | `calculation` | Method of calculation. Either `conversion_rate` or `conversions`. Default is `conversion_rate`. | String | Required | From 43a8732caab86fb1c6e12a6d5147bf96e9615e33 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:14:25 +0000 Subject: [PATCH 10/60] Update website/docs/docs/build/conversion-metrics.md --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 1856d6a38ec..0d311b287ca 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -25,7 +25,7 @@ The specification for conversion metrics is as follows: | `type_params` | Specific configurations for each metric type. | List | Required | | `conversion_type_params` | Additional configuration specific to conversion metrics. | List | Required | | `entity` | The entity for each conversion event. | Entity | Required | -| `calculation` | Method of calculation. Either `conversion_rate` or `conversions`. Default is `conversion_rate`. | String | Required | +| `calculation` | Method of calculation. Either `conversion_rate` or `conversions`. Defaults to `conversion_rate`. | String | Optional | | `base_measure` | The base conversion event measure. | Measure | Required | | `conversion_measure` | The conversion event measure. | Measure | Required | | `window` | The time window for the conversion event, such as 7 days, 1 week, 3 months. Defaults to infinity. | String | Required | From 437db25b2a44efb24dfd25add0b54d0f55c31698 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:22:04 +0000 Subject: [PATCH 11/60] Update conversion-metrics.md fold will's feedback --- website/docs/docs/build/conversion-metrics.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 0d311b287ca..0457d54afee 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -86,7 +86,7 @@ Next, we define a conversion metric as follows: - name: visit_to_buy_conversion_rate_7d description: "Conversion rate from visiting to transaction in 7 days" type: conversion - label: Visit to Buy Conversion Rate (7 day window) + label: Visit to Buy Conversion Rate (7-day window) type_params: conversion_type_params: base_measure: visits @@ -135,9 +135,9 @@ Instead of returning the raw visit values, use window functions to link conversi ```sql select - first_value(v.ds) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc nulls first) as v_ds, - first_value(v.user_id) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc nulls first) as user_id, - first_value(v.referrer_id) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc nulls first) as referrer_id, + first_value(v.ds) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc) as v_ds, + first_value(v.user_id) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc) as user_id, + first_value(v.referrer_id) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc) as referrer_id, b.ds, b.uuid, 1 as buys @@ -169,9 +169,9 @@ Instead of regular select used in the [Step 2](#step-2-refine-with-window-functi ```sql select distinct - first_value(v.ds) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc nulls first) as v_ds, - first_value(v.user_id) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc nulls first) as user_id, - first_value(v.referrer_id) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc nulls first) as referrer_id, + first_value(v.ds) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc) as v_ds, + first_value(v.user_id) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc) as user_id, + first_value(v.referrer_id) over (partition by b.ds, b.user_id, b.uuid order by v.ds desc) as referrer_id, b.ds, b.uuid, 1 as buys @@ -241,12 +241,12 @@ Use the following additional settings to customize your conversion metrics: - Null conversion values: Set null conversions to zero using `fill_nulls_with`. - Calculation type: Choose between showing raw conversions or conversion rate. -- Constant property: Add conditions to join conversions on constant properties for specific scenarios. +- Constant property: Add conditions for specific scenarios to join conversions on constant properties. -To return zero in the final data set, you may want to set the value of a null conversion event to zero instead of null. You can add the `fill_nulls_with` parameter to your conversion metric definition like this: +To return zero in the final data set, you can set the value of a null conversion event to zero instead of null. You can add the `fill_nulls_with` parameter to your conversion metric definition like this: ```yaml - name: vist_to_buy_conversion_rate_7_day_window From 2215f00394099c488458a9f3da34288c5e6f133f Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Wed, 10 Jan 2024 13:24:56 +0000 Subject: [PATCH 12/60] add in about mf page --- website/docs/docs/build/about-metricflow.md | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/docs/build/about-metricflow.md b/website/docs/docs/build/about-metricflow.md index ea2efcabf06..77b19a02d79 100644 --- a/website/docs/docs/build/about-metricflow.md +++ b/website/docs/docs/build/about-metricflow.md @@ -63,6 +63,7 @@ Metrics, which is a key concept, are functions that combine measures, constraint MetricFlow supports different metric types: +- [Conversion](/docs/build/conversion) — Helps you track when a base event and a subsequent conversion event occurs for an entity within a set time period. - [Cumulative](/docs/build/cumulative) — Aggregates a measure over a given window. - [Derived](/docs/build/derived) — An expression of other metrics, which allows you to do calculations on top of metrics. - [Ratio](/docs/build/ratio) — Create a ratio out of two measures, like revenue per customer. From 4cb9141610f25ceefda1a61a2164c5baafd30574 Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Wed, 10 Jan 2024 13:28:36 +0000 Subject: [PATCH 13/60] spell out infinity --- website/docs/docs/build/conversion-metrics.md | 2 +- website/docs/docs/build/metrics-overview.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 0457d54afee..e6f77c0a9fc 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -46,7 +46,7 @@ metrics: calculation: _calculation_type_ # Optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits), and more to come. base_measure: _measure_ # Required conversion_measure: _measure_ # Required - window: _time_window_ # Optional. default: inf. window to join the two events on. Follows similar format as time windows elsewhere (such as, 7 days) + window: _time_window_ # Optional. default: infinity. window to join the two events on. Follows similar format as time windows elsewhere (such as, 7 days) constant_properties: # Optional. List of constant properties default: None - base_property: _dimension_or_entity_ # Required. A reference to a dimension/entity of the semantic model linked to the base_measure conversion_property: _dimension_or_entity_ # Same as base above, but to the semantic model of the conversion_measure diff --git a/website/docs/docs/build/metrics-overview.md b/website/docs/docs/build/metrics-overview.md index 47d8b698c71..904a3b6aeba 100644 --- a/website/docs/docs/build/metrics-overview.md +++ b/website/docs/docs/build/metrics-overview.md @@ -63,7 +63,7 @@ metrics: calculation: _calculation_type_ # Optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits), and more to come. base_measure: _measure_ # Required conversion_measure: _measure_ # Required - window: _time_window_ # Optional. default: inf. window to join the two events on. Follows similar format as time windows elsewhere (such as, 7 days) + window: _time_window_ # Optional. default: infinity. window to join the two events on. Follows similar format as time windows elsewhere (such as, 7 days) constant_properties: # Optional. List of constant properties default: None - base_property: _dimension_or_entity_ # Required. A reference to a dimension/entity of the semantic model linked to the base_measure conversion_property: _dimension_or_entity_ # Same as base above, but to the semantic model of the conversion_measure From 4b44e3d6feff264b2761d0b3825c97c797b6368d Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:11:06 +0000 Subject: [PATCH 14/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index e6f77c0a9fc..528184eedd5 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -6,7 +6,7 @@ sidebar_label: Conversion tags: [Metrics, Semantic Layer] --- -Conversion metrics allow us to define when a base event happens and a subsequent conversion event happens for a specific entity within some time range. +Conversion metrics allow you to define when a base event and a subsequent conversion event happen for a specific entity within some time range. - **Example**: Track how often a user (entity) completes a visit (base event) and then makes a purchase (conversion event) within 7 days (time window). - **Requirements**: A time range and an entity to join on. From 71da2df18ef3c124e3e5d1d71a215edcb6a82713 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:15:16 +0000 Subject: [PATCH 15/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 528184eedd5..52e07fe2779 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -20,7 +20,7 @@ The specification for conversion metrics is as follows: | --- | --- | --- | --- | | `name` | The name of the metric. | String | Required | | `description` | The description of the metric. | String | Optional | -| `type` | The type of the metric (such as derived, ratio, and so on). In this case, set as 'conversion' | String | Required | +| `type` | The type of metric (such as derived, ratio, and so on.). In this case, set as 'conversion' | String | Required | | `label` | Displayed value in downstream tools. | String | Required | | `type_params` | Specific configurations for each metric type. | List | Required | | `conversion_type_params` | Additional configuration specific to conversion metrics. | List | Required | From c5451b02e95224bf5967bf8b8a4108a813cac3c0 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:17:33 +0000 Subject: [PATCH 16/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 52e07fe2779..2acdd8f7692 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -54,7 +54,7 @@ metrics: ## Conversion metric example -The following example will measure conversions from website visits (`VISITS` table) to order completions (`BUYS` table). Let's calculate a conversion metric for this scenario step by step. +The following example will measure conversions from website visits (`VISITS` table) to order completions (`BUYS` table) and calculate a conversion metric for this scenario step by step. Suppose we have two semantic models, `VISITS` and `BUYS`: From b16da0f410047e41964289303efbc8323909a708 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:17:52 +0000 Subject: [PATCH 17/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 2acdd8f7692..65663765b16 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -56,7 +56,7 @@ metrics: The following example will measure conversions from website visits (`VISITS` table) to order completions (`BUYS` table) and calculate a conversion metric for this scenario step by step. -Suppose we have two semantic models, `VISITS` and `BUYS`: +Suppose you have two semantic models, `VISITS` and `BUYS`: - The `VISITS` table represents visits to an e-commerce site - The `BUYS` table represents someone completing an order on that site. From a583c2970c5242ab7a5dc08e4c808ef9c1170eff Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:20:31 +0000 Subject: [PATCH 18/60] Update conversion-metrics.md --- website/docs/docs/build/conversion-metrics.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 65663765b16..6bfc0ba2521 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -42,14 +42,14 @@ metrics: type: conversion type_params: conversion_type_params: - entity: _entity_ # Required - calculation: _calculation_type_ # Optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits), and more to come. - base_measure: _measure_ # Required - conversion_measure: _measure_ # Required - window: _time_window_ # Optional. default: infinity. window to join the two events on. Follows similar format as time windows elsewhere (such as, 7 days) + entity: ENTITY # Required + calculation: CALCULATION_TYPE # Optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits), and more to come. + base_measure: MEASURE # Required + conversion_measure: MEASURE # Required + window: TIME_WINDOW # Optional. default: infinity. window to join the two events. Follows a similar format as time windows elsewhere (such as 7 days) constant_properties: # Optional. List of constant properties default: None - - base_property: _dimension_or_entity_ # Required. A reference to a dimension/entity of the semantic model linked to the base_measure - conversion_property: _dimension_or_entity_ # Same as base above, but to the semantic model of the conversion_measure + - base_property: DIMENSION or ENTITY # Required. A reference to a dimension/entity of the semantic model linked to the base_measure + conversion_property: DIMENSION or ENTITY # Same as base above, but to the semantic model of the conversion_measure ``` ## Conversion metric example From c4f9fb75d383d5005b051f4922aea46872a4eb29 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:20:51 +0000 Subject: [PATCH 19/60] Update website/docs/docs/build/conversion-metrics.md --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 6bfc0ba2521..7293cedce8e 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -28,7 +28,7 @@ The specification for conversion metrics is as follows: | `calculation` | Method of calculation. Either `conversion_rate` or `conversions`. Defaults to `conversion_rate`. | String | Optional | | `base_measure` | The base conversion event measure. | Measure | Required | | `conversion_measure` | The conversion event measure. | Measure | Required | -| `window` | The time window for the conversion event, such as 7 days, 1 week, 3 months. Defaults to infinity. | String | Required | +| `window` | The time window for the conversion event, such as 7 days, 1 week, 3 months. Defaults to infinity. | String | Optional | | `constant_properties` | List of constant properties. Defaults to None. | List | Optional | | `base_property` | The property from the base semantic model that you want to hold constant. | Entity or Dimension | Optional | | `conversion_property` | The property from the conversion semantic model that you want to hold constant. | Entity or Dimension | Optional | From f232b8f37af37aa282ae7dadc3a80a4f2e6845e7 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:21:12 +0000 Subject: [PATCH 20/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 7293cedce8e..340e962688b 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -58,7 +58,7 @@ The following example will measure conversions from website visits (`VISITS` tab Suppose you have two semantic models, `VISITS` and `BUYS`: -- The `VISITS` table represents visits to an e-commerce site +- The `VISITS` table represents visits to an e-commerce site. - The `BUYS` table represents someone completing an order on that site. The underlying tables look like the following: From 466c8ee8c98b2edf2b4cb6b8dd1b60ab6e05027b Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:21:32 +0000 Subject: [PATCH 21/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 340e962688b..5b3ede57273 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -80,7 +80,7 @@ Records completed orders with `USER_ID` and `REFERRER_ID`. | 2020-01-02 | bob | facebook | | 2020-01-07 | bob | amazon | -Next, we define a conversion metric as follows: +Next, define a conversion metric as follows: ```yaml - name: visit_to_buy_conversion_rate_7d From f847e969fb920d6387cf36304edba9c1a8fba0dc Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:22:06 +0000 Subject: [PATCH 22/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 5b3ede57273..d1ca853b26e 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -119,7 +119,7 @@ on v.user_id = b.user_id and v.ds <= b.ds and v.ds > b.ds - interval '7 day' ``` -The dataset returns the following: +The dataset returns the following (note that there are two potential conversion events for the first visit): Note that there are two potential conversion events for the first visit. | V.DS | V.USER_ID | V.REFERRER_ID | B.DS | UUID | BUYS | From 7d8309d0c4af4036becb2771372dc39349d6c8b9 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:22:27 +0000 Subject: [PATCH 23/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 1 - 1 file changed, 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index d1ca853b26e..e5f998cc605 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -120,7 +120,6 @@ v.user_id = b.user_id and v.ds <= b.ds and v.ds > b.ds - interval '7 day' ``` The dataset returns the following (note that there are two potential conversion events for the first visit): -Note that there are two potential conversion events for the first visit. | V.DS | V.USER_ID | V.REFERRER_ID | B.DS | UUID | BUYS | | --- | --- | --- | --- | --- | --- | From 2a44a704506a16d45cb6f068e282abfbff931cbb Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:22:49 +0000 Subject: [PATCH 24/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index e5f998cc605..eaf2ce7f004 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -158,7 +158,7 @@ The dataset returns the following: | 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | | 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | -This workflow links the two conversions to the correct visit events. Due to the join, we end up with multiple combinations, leading to fanout results. After applying the window function, duplicates appear. +This workflow links the two conversions to the correct visit events. Due to the join, you end up with multiple combinations, leading to fanout results. After applying the window function, duplicates appear. To resolve this and eliminate duplicates, use a distinct select. The UUID also helps identify which conversion is unique. The next steps provide more detail on how to do this. From e348ea4f860d77bb9fa356cb419146107dacabac Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:23:06 +0000 Subject: [PATCH 25/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index eaf2ce7f004..a63ce585d67 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -189,7 +189,7 @@ The dataset returns the following: | 2020-01-01 | bob | facebook | 2020-01-02 | uuid1 | 1 | | 2020-01-07 | bob | amazon | 2020-01-07 | uuid2 | 1 | -We now have a dataset where every conversion is connected to a visit event. To proceed: +You now have a dataset where every conversion is connected to a visit event. To proceed: 1. Sum up the total conversions in the "conversions" table. 2. Combine this table with the "opportunities" table, matching them based on group keys. From cfa6c27917335d4cbedf6a27becd5b24e2bb72a3 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:23:22 +0000 Subject: [PATCH 26/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index a63ce585d67..9c30f62ae07 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -197,7 +197,7 @@ You now have a dataset where every conversion is connected to a visit event. To ### Step 4: Aggregate and calculate -Now that we’ve tied each conversion event to a visit, we can calculate the aggregated conversions and opportunities measures. Then we can join them to calculate the actual conversion rate. The SQL to calculate the conversion rate is as follows: +Now that you’ve tied each conversion event to a visit, you can calculate the aggregated conversions and opportunities measures. Then, you can join them to calculate the actual conversion rate. The SQL to calculate the conversion rate is as follows: ```sql select From beda09f424886449638c46d8ca57346eb4744ecb Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:23:53 +0000 Subject: [PATCH 27/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 9c30f62ae07..f05c9d48d2d 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -238,7 +238,7 @@ group by Use the following additional settings to customize your conversion metrics: -- Null conversion values: Set null conversions to zero using `fill_nulls_with`. +- **Null conversion values:** Set null conversions to zero using `fill_nulls_with`. - Calculation type: Choose between showing raw conversions or conversion rate. - Constant property: Add conditions for specific scenarios to join conversions on constant properties. From 5be89e86046f57292c13fbd5d05faf36ccc2e78e Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:24:31 +0000 Subject: [PATCH 28/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index f05c9d48d2d..a410f006487 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -239,7 +239,7 @@ group by Use the following additional settings to customize your conversion metrics: - **Null conversion values:** Set null conversions to zero using `fill_nulls_with`. -- Calculation type: Choose between showing raw conversions or conversion rate. +- **Calculation type:** Choose between showing raw conversions or conversion rate. - Constant property: Add conditions for specific scenarios to join conversions on constant properties. From bc73503c012cf913cf1c3f1b012ddca6afc775ba Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:24:46 +0000 Subject: [PATCH 29/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index a410f006487..e67913213a8 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -300,7 +300,7 @@ You can change the default to display the number of conversions by setting the ` You can add a constant property to a conversion metric to count only those conversions where a specific dimension or entity matches in both the base and conversion events. -For example, if you're at an e-commerce company and want to answer the following questions: +For example, if you're at an e-commerce company and want to answer the following question: - _How often did visitors convert from `View Item Details` to `Complete Purchase` with the same product in each step?_
- What makes this question tricky to answer is users could have completed these two conversion milestones across many products. For example, viewed a pair of shoes, then a T-shirt, and eventually checked out with a bow tie. This would still count as a conversion, even though the conversion event only happened for the bow tie. From ed23be1f27a8948d64a5d07508df63e1e7c1070d Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:25:00 +0000 Subject: [PATCH 30/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index e67913213a8..d1aa5fba137 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -240,7 +240,7 @@ Use the following additional settings to customize your conversion metrics: - **Null conversion values:** Set null conversions to zero using `fill_nulls_with`. - **Calculation type:** Choose between showing raw conversions or conversion rate. -- Constant property: Add conditions for specific scenarios to join conversions on constant properties. +- **Constant property:** Add conditions for specific scenarios to join conversions on constant properties. From 9eddea55730f26c6fb98c709461894edefb12bce Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:25:23 +0000 Subject: [PATCH 31/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index d1aa5fba137..baa99b8adec 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -264,7 +264,7 @@ To return zero in the final data set, you can set the value of a null conversion ``` -This will return the following result set: +This will return the following results: From 089d56b32dcc6ff5b7b0ed8e2d5deea3d9832fb4 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:25:42 +0000 Subject: [PATCH 32/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index baa99b8adec..bfadd4d10ab 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -302,7 +302,7 @@ You can add a constant property to a conversion metric to count only those conve For example, if you're at an e-commerce company and want to answer the following question: - _How often did visitors convert from `View Item Details` to `Complete Purchase` with the same product in each step?_
- - What makes this question tricky to answer is users could have completed these two conversion milestones across many products. For example, viewed a pair of shoes, then a T-shirt, and eventually checked out with a bow tie. This would still count as a conversion, even though the conversion event only happened for the bow tie. + - This question is tricky to answer because users could have completed these two conversion milestones across many products. For example, they may have viewed a pair of shoes, then a T-shirt, and eventually checked out with a bow tie. This would still count as a conversion, even though the conversion event only happened for the bow tie. Back to our initial questions, we want to see how many customers viewed an item detail page and then completed a purchase for the _same_ product. From 8cb6e0f953ace11a5620f40cd5ec15f00054081b Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:26:02 +0000 Subject: [PATCH 33/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index bfadd4d10ab..cb3c752517d 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -304,7 +304,7 @@ For example, if you're at an e-commerce company and want to answer the following - _How often did visitors convert from `View Item Details` to `Complete Purchase` with the same product in each step?_
- This question is tricky to answer because users could have completed these two conversion milestones across many products. For example, they may have viewed a pair of shoes, then a T-shirt, and eventually checked out with a bow tie. This would still count as a conversion, even though the conversion event only happened for the bow tie. -Back to our initial questions, we want to see how many customers viewed an item detail page and then completed a purchase for the _same_ product. +Back to the initial questions, you want to see how many customers viewed an item detail page and then completed a purchase for the _same_ product. In this case, we would want to set `product_id` as the constant property. We would specify this in the configs as follows: From 8ed5662c460e1110ae41583221f6a277c3418750 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:26:32 +0000 Subject: [PATCH 34/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index cb3c752517d..52fdf4acc3c 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -325,7 +325,7 @@ In this case, we would want to set `product_id` as the constant property. We wou conversion_property: product ``` -We will add an additional condition to the join to make sure the constant property is the same across conversion. +You will add an additional condition to the join to make sure the constant property is the same across conversions. ```sql select distinct From 14f0c23fd5f12f6357438a2628b2c09baff85ebc Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:29:02 +0000 Subject: [PATCH 35/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 52fdf4acc3c..36f4f499425 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -306,7 +306,7 @@ For example, if you're at an e-commerce company and want to answer the following Back to the initial questions, you want to see how many customers viewed an item detail page and then completed a purchase for the _same_ product. -In this case, we would want to set `product_id` as the constant property. We would specify this in the configs as follows: +In this case, you want to set `product_id` as the constant property. You can specify this in the configs as follows: ```yaml - name: view_item_detail_to_purchase_with_same_item From e5e2edd7ec16718bbc5be5bc21b74cfcadf1a2ca Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:29:40 +0000 Subject: [PATCH 36/60] Update website/docs/docs/build/conversion-metrics.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 36f4f499425..b8c5a744ffd 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -29,7 +29,7 @@ The specification for conversion metrics is as follows: | `base_measure` | The base conversion event measure. | Measure | Required | | `conversion_measure` | The conversion event measure. | Measure | Required | | `window` | The time window for the conversion event, such as 7 days, 1 week, 3 months. Defaults to infinity. | String | Optional | -| `constant_properties` | List of constant properties. Defaults to None. | List | Optional | +| `constant_properties` | List of constant properties. | List | Optional | | `base_property` | The property from the base semantic model that you want to hold constant. | Entity or Dimension | Optional | | `conversion_property` | The property from the conversion semantic model that you want to hold constant. | Entity or Dimension | Optional | From d42745d81011f49c128b623f8cc055f0d04f8b0d Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Wed, 10 Jan 2024 17:30:03 +0000 Subject: [PATCH 37/60] add --- website/docs/docs/build/metrics-overview.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/website/docs/docs/build/metrics-overview.md b/website/docs/docs/build/metrics-overview.md index 904a3b6aeba..e669b59dfee 100644 --- a/website/docs/docs/build/metrics-overview.md +++ b/website/docs/docs/build/metrics-overview.md @@ -59,14 +59,14 @@ metrics: type: conversion type_params: conversion_type_params: - entity: _entity_ # Required - calculation: _calculation_type_ # Optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits), and more to come. - base_measure: _measure_ # Required - conversion_measure: _measure_ # Required - window: _time_window_ # Optional. default: infinity. window to join the two events on. Follows similar format as time windows elsewhere (such as, 7 days) + entity: ENTITY # Required + calculation: CALCULATION_TYPE # Optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits), and more to come. + base_measure: MEASURE # Required + conversion_measure: MEASURE # Required + window: TIME_WINDOW # Optional. default: infinity. window to join the two events. Follows a similar format as time windows elsewhere (such as 7 days) constant_properties: # Optional. List of constant properties default: None - - base_property: _dimension_or_entity_ # Required. A reference to a dimension/entity of the semantic model linked to the base_measure - conversion_property: _dimension_or_entity_ # Same as base above, but to the semantic model of the conversion_measure + - base_property: DIMENSION or ENTITY # Required. A reference to a dimension/entity of the semantic model linked to the base_measure + conversion_property: DIMENSION or ENTITY # Same as base above, but to the semantic model of the conversion_measure ``` ### Cumulative metrics From 98b797e21bca5c42322d06b234dfa1760e81e692 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:34:17 +0000 Subject: [PATCH 38/60] Update conversion-metrics.md --- website/docs/docs/build/conversion-metrics.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index b8c5a744ffd..53519a4e69e 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -8,9 +8,7 @@ tags: [Metrics, Semantic Layer] Conversion metrics allow you to define when a base event and a subsequent conversion event happen for a specific entity within some time range. -- **Example**: Track how often a user (entity) completes a visit (base event) and then makes a purchase (conversion event) within 7 days (time window). -- **Requirements**: A time range and an entity to join on. -- **How it differs from [Ratio metrics](/docs/build/ratio)**: Includes an entity in the pre-aggregated join. +For example, using conversion metrics allows you to track how often a user (entity) completes a visit (base event) and then makes a purchase (conversion event) within 7 days (time window). You would need to add a time range and an entity to join. Conversion metrics are different from [ratio metrics](/docs/build/ratio) because you need to include an entity in the pre-aggregated join. ## Parameters From 6e3571a486369a77ad1e99a0258d0b3755d20392 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 10 Jan 2024 18:21:19 +0000 Subject: [PATCH 39/60] Update website/docs/docs/build/conversion-metrics.md --- website/docs/docs/build/conversion-metrics.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 53519a4e69e..c328d61644a 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -8,7 +8,9 @@ tags: [Metrics, Semantic Layer] Conversion metrics allow you to define when a base event and a subsequent conversion event happen for a specific entity within some time range. -For example, using conversion metrics allows you to track how often a user (entity) completes a visit (base event) and then makes a purchase (conversion event) within 7 days (time window). You would need to add a time range and an entity to join. Conversion metrics are different from [ratio metrics](/docs/build/ratio) because you need to include an entity in the pre-aggregated join. +For example, using conversion metrics allows you to track how often a user (entity) completes a visit (base event) and then makes a purchase (conversion event) within 7 days (time window). You would need to add a time range and an entity to join. + +Conversion metrics are different from [ratio metrics](/docs/build/ratio) because you need to include an entity in the pre-aggregated join. ## Parameters From 27d72a1d23a195392324c01d61adac7d4e7aec0f Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Fri, 12 Jan 2024 10:02:14 +0000 Subject: [PATCH 40/60] add link --- website/snippets/_sl-define-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/snippets/_sl-define-metrics.md b/website/snippets/_sl-define-metrics.md index af3ee9f297f..fe169b4a5b4 100644 --- a/website/snippets/_sl-define-metrics.md +++ b/website/snippets/_sl-define-metrics.md @@ -1,6 +1,6 @@ Now that you've created your first semantic model, it's time to define your first metric! You can define metrics with the dbt Cloud IDE or command line. -MetricFlow supports different metric types like [simple](/docs/build/simple), [ratio](/docs/build/ratio), [cumulative](/docs/build/cumulative), and [derived](/docs/build/derived). It's recommended that you read the [metrics overview docs](/docs/build/metrics-overview) before getting started. +MetricFlow supports different metric types like [conversion](/docs/build/conversion), [simple](/docs/build/simple), [ratio](/docs/build/ratio), [cumulative](/docs/build/cumulative), and [derived](/docs/build/derived). It's recommended that you read the [metrics overview docs](/docs/build/metrics-overview) before getting started. 1. You can define metrics in the same YAML files as your semantic models or create a new file. If you want to create your metrics in a new file, create another directory called `/models/metrics`. The file structure for metrics can become more complex from here if you need to further organize your metrics, for example, by data source or business line. From 4e3161849fb459d11b580907c6bfa675872e30a8 Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 12 Jan 2024 17:25:20 -0800 Subject: [PATCH 41/60] Update conversion-metrics.md update metric to match image --- website/docs/docs/build/conversion-metrics.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index c328d61644a..055019745ee 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -249,18 +249,18 @@ To return zero in the final data set, you can set the value of a null conversion ```yaml - name: vist_to_buy_conversion_rate_7_day_window - description: "Conversion rate from MQL to seller" + description: "Conversion rate from viewing a page to making a purchase" type: conversion - label: MQL to Seller Conversion Rate (1 week day window) + label: Visit to Seller Conversion Rate (7 day window) type_params: conversion_type_params: calculation: conversions - base_measure: mqls + base_measure: visits conversion_measure: - name: sellers + name: buys fill_nulls_with: 0 - entity: mql - window: 1 week + entity: user + window: 7 days ``` From b320c136aa5aa3e3c1a3f1f1da183bc5f2c90eb7 Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Mon, 15 Jan 2024 10:26:37 +0000 Subject: [PATCH 42/60] fix links --- ...materializations-guide-2-available-materializations.md | 8 ++++---- website/docs/docs/running-a-dbt-project/using-threads.md | 2 +- website/vercel.json | 5 +++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/website/docs/best-practices/materializations/materializations-guide-2-available-materializations.md b/website/docs/best-practices/materializations/materializations-guide-2-available-materializations.md index 9910e5f8269..e341b6ad1a1 100644 --- a/website/docs/best-practices/materializations/materializations-guide-2-available-materializations.md +++ b/website/docs/best-practices/materializations/materializations-guide-2-available-materializations.md @@ -9,12 +9,12 @@ hoverSnippet: Read this guide to understand the different types of materializati Views and tables and incremental models, oh my! In this section we’ll start getting our hands dirty digging into the three basic materializations that ship with dbt. They are considerably less scary and more helpful than lions, tigers, or bears — although perhaps not as cute (can data be cute? We at dbt Labs think so). We’re going to define, implement, and explore: -- 🔍 **views** -- ⚒️ **tables** -- 📚 **incremental model** +- 🔍 [**views**](/docs/build/materializations#view) +- ⚒️ [**tables**](m/docs/build/materializations#table) +- 📚 [**incremental model**](/docs/build/materializations#incremental) :::info -👻 There is a fourth default materialization available in dbt called **ephemeral materialization**. It is less broadly applicable than the other three, and better deployed for specific use cases that require weighing some tradeoffs. We chose to leave it out of this guide and focus on the three materializations that will power 99% of your modeling needs. +👻 There is a fourth default materialization available in dbt called [**ephemeral materialization**](/docs/build/materializations#ephemeral). It is less broadly applicable than the other three, and better deployed for specific use cases that require weighing some tradeoffs. We chose to leave it out of this guide and focus on the three materializations that will power 99% of your modeling needs. ::: **Views and Tables are the two basic categories** of object that we can create across warehouses. They exist natively as types of objects in the warehouse, as you can see from this screenshot of Snowflake (depending on your warehouse the interface will look a little different). **Incremental models** and other materializations types are a little bit different. They tell dbt to **construct tables in a special way**. diff --git a/website/docs/docs/running-a-dbt-project/using-threads.md b/website/docs/docs/running-a-dbt-project/using-threads.md index 5eede7abc27..af00dd9cc68 100644 --- a/website/docs/docs/running-a-dbt-project/using-threads.md +++ b/website/docs/docs/running-a-dbt-project/using-threads.md @@ -22,5 +22,5 @@ You will define the number of threads in your `profiles.yml` file (for dbt Core ## Related docs -- [About profiles.yml](https://docs.getdbt.com/reference/profiles.yml) +- [About profiles.yml](/docs/core/connect-data-platform/profiles.yml) - [dbt Cloud job scheduler](/docs/deploy/job-scheduler) diff --git a/website/vercel.json b/website/vercel.json index b662e1c2144..1e4cc2fb021 100644 --- a/website/vercel.json +++ b/website/vercel.json @@ -2,6 +2,11 @@ "cleanUrls": true, "trailingSlash": false, "redirects": [ + { + "source": "/reference/profiles.yml", + "destination": "/docs/core/connect-data-platform/profiles.yml", + "permanent": true + }, { "source": "/docs/cloud/dbt-cloud-ide/dbt-cloud-tips", "destination": "/docs/build/dbt-tips", From ed6ab9ac5a0668544d8bd1ef02da98574897eaac Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Mon, 15 Jan 2024 10:39:08 +0000 Subject: [PATCH 43/60] fix blog links --- website/blog/2023-08-01-announcing-materialized-views.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/blog/2023-08-01-announcing-materialized-views.md b/website/blog/2023-08-01-announcing-materialized-views.md index eb9716e73a5..3b801c7c719 100644 --- a/website/blog/2023-08-01-announcing-materialized-views.md +++ b/website/blog/2023-08-01-announcing-materialized-views.md @@ -21,7 +21,7 @@ and updates on how to test MVs. The year was 2020. I was a kitten-only household, and dbt Labs was still Fishtown Analytics. A enterprise customer I was working with, Jetblue, asked me for help running their dbt models every 2 minutes to meet a 5 minute SLA. -After getting over the initial terror, we talked through the use case and soon realized there was a better option. Together with my team, I created [lambda views](https://discourse.getdbt.com/t/how-to-create-near-real-time-models-with-just-dbt-sql/1457%20?) to meet the need. +After getting over the initial terror, we talked through the use case and soon realized there was a better option. Together with my team, I created [lambda views](https://discourse.getdbt.com/t/how-to-create-near-real-time-models-with-just-dbt-sql/1457) to meet the need. Flash forward to 2023. I’m writing this as my giant dog snores next to me (don’t worry the cats have multiplied as well). Jetblue has outgrown lambda views due to performance constraints (a view can only be so performant) and we are at another milestone in dbt’s journey to support streaming. What. a. time. @@ -32,8 +32,8 @@ Today we are announcing that we now support Materialized Views in dbt. So, what Materialized views are now an out of the box materialization in your dbt project once you upgrade to the latest version of dbt v1.6 on these following adapters: - [dbt-postgres](/reference/resource-configs/postgres-configs#materialized-views) -- [dbt-redshift](reference/resource-configs/redshift-configs#materialized-views) -- [dbt-snowflake](reference/resource-configs/snowflake-configs#dynamic-tables) +- [dbt-redshift](/reference/resource-configs/redshift-configs#materialized-views) +- [dbt-snowflake](/reference/resource-configs/snowflake-configs#dynamic-tables) - [dbt-databricks](/reference/resource-configs/databricks-configs#materialized-views-and-streaming-tables) - [dbt-materialize*](/reference/resource-configs/materialize-configs#incremental-models-materialized-views) - [dbt-trino*](/reference/resource-configs/trino-configs#materialized-view) @@ -227,4 +227,4 @@ Depending on how you orchestrate your materialized views, you can either run the ## Conclusion -Well, I’m excited for everyone to remove the lines in your packages.yml that installed your experimental package (at least if you’re using it for MVs) and start to get your hands dirty. We are still new in our journey and I look forward to hearing all the things you are creating and how we can better our best practices in this. \ No newline at end of file +Well, I’m excited for everyone to remove the lines in your packages.yml that installed your experimental package (at least if you’re using it for MVs) and start to get your hands dirty. We are still new in our journey and I look forward to hearing all the things you are creating and how we can better our best practices in this. From 19436402c3e79f19e75a3c41ae171c589c37aade Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Mon, 15 Jan 2024 10:41:20 +0000 Subject: [PATCH 44/60] remove m --- .../materializations-guide-2-available-materializations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/best-practices/materializations/materializations-guide-2-available-materializations.md b/website/docs/best-practices/materializations/materializations-guide-2-available-materializations.md index e341b6ad1a1..1096c07cde7 100644 --- a/website/docs/best-practices/materializations/materializations-guide-2-available-materializations.md +++ b/website/docs/best-practices/materializations/materializations-guide-2-available-materializations.md @@ -10,7 +10,7 @@ hoverSnippet: Read this guide to understand the different types of materializati Views and tables and incremental models, oh my! In this section we’ll start getting our hands dirty digging into the three basic materializations that ship with dbt. They are considerably less scary and more helpful than lions, tigers, or bears — although perhaps not as cute (can data be cute? We at dbt Labs think so). We’re going to define, implement, and explore: - 🔍 [**views**](/docs/build/materializations#view) -- ⚒️ [**tables**](m/docs/build/materializations#table) +- ⚒️ [**tables**](/docs/build/materializations#table) - 📚 [**incremental model**](/docs/build/materializations#incremental) :::info From 90819f1f895813785eb5976ebbe05d23724f8a0d Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Mon, 15 Jan 2024 15:32:22 +0000 Subject: [PATCH 45/60] Update sl-graphql.md clarify schema explorer urls for other regions --- website/docs/docs/dbt-cloud-apis/sl-graphql.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/website/docs/docs/dbt-cloud-apis/sl-graphql.md b/website/docs/docs/dbt-cloud-apis/sl-graphql.md index 56a4ac7ba59..e610c6c52c6 100644 --- a/website/docs/docs/dbt-cloud-apis/sl-graphql.md +++ b/website/docs/docs/dbt-cloud-apis/sl-graphql.md @@ -22,7 +22,18 @@ GraphQL has several advantages, such as self-documenting, having a strong typing ## dbt Semantic Layer GraphQL API -The dbt Semantic Layer GraphQL API allows you to explore and query metrics and dimensions. Due to its self-documenting nature, you can explore the calls conveniently through the [schema explorer](https://semantic-layer.cloud.getdbt.com/api/graphql). +The dbt Semantic Layer GraphQL API allows you to explore and query metrics and dimensions. Due to its self-documenting nature, you can explore the calls conveniently through a schema explorer. The schema explorer URLs vary depending on your [deployment region](/docs/cloud/about-cloud/regions-ip-addresses). Use the following table to find the right link for your region: + +| Deployment type | Schema explorer URL | +| --------------- | ------------------- | +| North America multi-tenant | https://semantic-layer.cloud.getdbt.com/api/graphql | +| EMEA multi-tenant | https://semantic-layer.emea.dbt.com/api/graphql | +| APAC multi-tenant | https://semantic-layer.au.dbt.com/api/graphql | +| Single tenant* | `https://semantic-layer.YOUR_ACCESS_URL.com/api/graphql`| +| North America Cell 1** | `https://semantic-layer.YOUR_ACCOUNT_PREFIX.us1.dbt.com/api/graphql` | + +*Note for Single tenant users: Replace `YOUR_ACCESS_URL` with your specific account prefix with the appropriate Access URL for your region and plan. For example, if your access URL is `ABC123.getdbtcom`, your URL will be `https://semantic-layer.ABC123.getdbt.com/api/graphql`. +**Note for North America Cell 1 users: Replace `YOUR_ACCOUNT_PREFIX` with your specific account prefix. For example, if your account prefix is `xyz`, your URL will be `https://semantic-layer.xyz.us1.dbt.com/api/graphql`. dbt Partners can use the Semantic Layer GraphQL API to build an integration with the dbt Semantic Layer. From 8adedaf0c63916afd056a2e9cc3ca771b9844b6d Mon Sep 17 00:00:00 2001 From: mirnawong1 Date: Mon, 15 Jan 2024 16:08:23 +0000 Subject: [PATCH 46/60] turn to table --- website/docs/docs/dbt-cloud-apis/sl-graphql.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/website/docs/docs/dbt-cloud-apis/sl-graphql.md b/website/docs/docs/dbt-cloud-apis/sl-graphql.md index e610c6c52c6..8ccc1e70e34 100644 --- a/website/docs/docs/dbt-cloud-apis/sl-graphql.md +++ b/website/docs/docs/dbt-cloud-apis/sl-graphql.md @@ -22,18 +22,20 @@ GraphQL has several advantages, such as self-documenting, having a strong typing ## dbt Semantic Layer GraphQL API -The dbt Semantic Layer GraphQL API allows you to explore and query metrics and dimensions. Due to its self-documenting nature, you can explore the calls conveniently through a schema explorer. The schema explorer URLs vary depending on your [deployment region](/docs/cloud/about-cloud/regions-ip-addresses). Use the following table to find the right link for your region: +The dbt Semantic Layer GraphQL API allows you to explore and query metrics and dimensions. Due to its self-documenting nature, you can explore the calls conveniently through a schema explorer. + +The schema explorer URLs vary depending on your [deployment region](/docs/cloud/about-cloud/regions-ip-addresses). Use the following table to find the right link for your region: | Deployment type | Schema explorer URL | | --------------- | ------------------- | | North America multi-tenant | https://semantic-layer.cloud.getdbt.com/api/graphql | | EMEA multi-tenant | https://semantic-layer.emea.dbt.com/api/graphql | | APAC multi-tenant | https://semantic-layer.au.dbt.com/api/graphql | -| Single tenant* | `https://semantic-layer.YOUR_ACCESS_URL.com/api/graphql`| -| North America Cell 1** | `https://semantic-layer.YOUR_ACCOUNT_PREFIX.us1.dbt.com/api/graphql` | +| Single tenant | `https://semantic-layer.YOUR_ACCESS_URL.com/api/graphql`

Replace `YOUR_ACCESS_URL` with your specific account prefix with the appropriate Access URL for your region and plan.| +| North America Cell 1 | `https://semantic-layer.YOUR_ACCOUNT_PREFIX.us1.dbt.com/api/graphql`

Replace `YOUR_ACCOUNT_PREFIX` with your specific account prefix and make sure you leave `us1.dbt.com` in the URL. |
-*Note for Single tenant users: Replace `YOUR_ACCESS_URL` with your specific account prefix with the appropriate Access URL for your region and plan. For example, if your access URL is `ABC123.getdbtcom`, your URL will be `https://semantic-layer.ABC123.getdbt.com/api/graphql`. -**Note for North America Cell 1 users: Replace `YOUR_ACCOUNT_PREFIX` with your specific account prefix. For example, if your account prefix is `xyz`, your URL will be `https://semantic-layer.xyz.us1.dbt.com/api/graphql`. +**Example** +- If your access URL is `ABC123.getdbt.com`, your schema explorer URL will be `https://semantic-layer.ABC123.getdbt.com/api/graphql`. dbt Partners can use the Semantic Layer GraphQL API to build an integration with the dbt Semantic Layer. From f26fc84ed2f51172ef36ff38a74c82c762bf0d1c Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 15 Jan 2024 18:38:45 -0800 Subject: [PATCH 47/60] Update conversion-metrics.md fix typo --- website/docs/docs/build/conversion-metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 055019745ee..4b3b431084c 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -277,7 +277,7 @@ Use the conversion calculation parameter to either show the raw number of conver You can change the default to display the number of conversions by setting the `calculation: conversion` parameter: ```yaml -- name: vist_to_buy_conversions_1_week_window +- name: visit_to_buy_conversions_1_week_window description: "Visit to Buy Conversions" type: conversion label: Visit to Buy Conversions (1 week window) From 1974b6783f02aa607dc66447bb21520eb9fdd3ba Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Tue, 16 Jan 2024 10:01:31 +0000 Subject: [PATCH 48/60] update code to align with table updated code example so it matched the table. also added `label` parameter --- website/docs/docs/build/conversion-metrics.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/website/docs/docs/build/conversion-metrics.md b/website/docs/docs/build/conversion-metrics.md index 4b3b431084c..2238655fbe0 100644 --- a/website/docs/docs/build/conversion-metrics.md +++ b/website/docs/docs/build/conversion-metrics.md @@ -38,10 +38,11 @@ The following code example displays the complete specification for conversion me ```yaml metrics: - name: The metric name # Required - description: the metric description # Required - type: conversion - type_params: - conversion_type_params: + description: the metric description # Optional + type: conversion # Required + label: # Required + type_params: # Required + conversion_type_params: # Required entity: ENTITY # Required calculation: CALCULATION_TYPE # Optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits), and more to come. base_measure: MEASURE # Required From 8c7c46281a604a50b689000489f2e8243d802b6c Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Tue, 16 Jan 2024 10:12:30 +0000 Subject: [PATCH 49/60] Update metrics-overview.md --- website/docs/docs/build/metrics-overview.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/website/docs/docs/build/metrics-overview.md b/website/docs/docs/build/metrics-overview.md index e669b59dfee..13a3c528348 100644 --- a/website/docs/docs/build/metrics-overview.md +++ b/website/docs/docs/build/metrics-overview.md @@ -14,7 +14,7 @@ The keys for metrics definitions are: | Parameter | Description | Type | | --------- | ----------- | ---- | | `name` | Provide the reference name for the metric. This name must be unique amongst all metrics. | Required | -| `description` | Provide the description for your metric. | Optional | +| `description` | Describe your metric. | Optional | | `type` | Define the type of metric, which can be `simple`, `ratio`, `cumulative`, or `derived`. | Required | | `type_params` | Additional parameters used to configure metrics. `type_params` are different for each metric type. | Required | | `config` | Provide the specific configurations for your metric. | Optional | @@ -55,10 +55,11 @@ This page explains the different supported metric types you can add to your dbt ```yaml metrics: - name: The metric name # Required - description: the metric description # Required - type: conversion - type_params: - conversion_type_params: + description: the metric description # Optional + type: conversion # Required + label: # Required + type_params: # Required + conversion_type_params: # Required entity: ENTITY # Required calculation: CALCULATION_TYPE # Optional. default: conversion_rate. options: conversions(buys) or conversion_rate (buys/visits), and more to come. base_measure: MEASURE # Required @@ -71,10 +72,10 @@ metrics: ### Cumulative metrics -[Cumulative metrics](/docs/build/cumulative) aggregate a measure over a given window. If no window is specified, the window would accumulate the measure over all time. **Note**, you will need to create the [time spine model](/docs/build/metricflow-time-spine) before you add cumulative metrics. +[Cumulative metrics](/docs/build/cumulative) aggregate a measure over a given window. If no window is specified, the window will accumulate the measure overall time. **Note**, you will need to create the [time spine model](/docs/build/metricflow-time-spine) before you add cumulative metrics. ```yaml -# Cumulative metrics aggregate a measure over a given window. The window is considered infinite if no window parameter is passed (accumulate the measure over all time) +# Cumulative metrics aggregate a measure over a given window. The window is considered infinite if no window parameter is passed (accumulate the measure overall time) metrics: - name: wau_rolling_7 owners: @@ -126,7 +127,7 @@ metrics: ### Ratio metrics -[Ratio metrics](/docs/build/ratio) involve a numerator metric and a denominator metric. A `constraint` string can be applied, to both numerator and denominator, or applied separately to the numerator or denominator. +[Ratio metrics](/docs/build/ratio) involve a numerator metric and a denominator metric. A `constraint` string can be applied to both the numerator and denominator or separately to the numerator or denominator. ```yaml # Ratio Metric @@ -192,9 +193,6 @@ You can set more metadata for your metrics, which can be used by other tools lat - **Description** — Write a detailed description of the metric. - - - ## Related docs - [Semantic models](/docs/build/semantic-models) From 11c105bd0b76d5c4fbf7284819e91c1b3a0ec8d3 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Tue, 16 Jan 2024 11:02:55 +0000 Subject: [PATCH 50/60] Update content-style-guide.md add this clarification per docs discussion a few weeks back. [source](https://www.notion.so/dbtlabs/Docs-team-meeting-8852fdf3f9354945aba185625e8eaec4?pvs=4) --- contributing/content-style-guide.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contributing/content-style-guide.md b/contributing/content-style-guide.md index 4ebbf83bf5f..c6b85d7148d 100644 --- a/contributing/content-style-guide.md +++ b/contributing/content-style-guide.md @@ -519,6 +519,7 @@ enter (in the command line) | type (in the command line) email | e-mail on dbt | on a remote server person, human | client, customer +plan(s), account | organization, customer press (a key) | hit, tap recommended limit | soft limit sign in | log in, login @@ -529,6 +530,8 @@ dbt Cloud CLI | CLI, dbt CLI dbt Core | CLI, dbt CLI +Make sure you keep the reader close to the content and documentation (second person). For example, to explain that a feature is available to a particular dbt Cloud plan — use “XYZ is available on Enterprise plans” or “People on Enterprise plans can XYZ..” to keep users closer to the documentation. This will signal to users to check their plan or account status on their own. + ## Links Links embedded in the documentation are about trust. Users trust that we will lead them to sites or pages related to their reading content. In order to maintain that trust, it's important that links are transparent, up-to-date, and lead to legitimate resources. From ec15e5ee86aa64656548b4a4bacad086d0b54504 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:58:00 +0000 Subject: [PATCH 51/60] Update website/docs/docs/dbt-cloud-apis/sl-graphql.md --- website/docs/docs/dbt-cloud-apis/sl-graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/dbt-cloud-apis/sl-graphql.md b/website/docs/docs/dbt-cloud-apis/sl-graphql.md index 8ccc1e70e34..7785812f1b1 100644 --- a/website/docs/docs/dbt-cloud-apis/sl-graphql.md +++ b/website/docs/docs/dbt-cloud-apis/sl-graphql.md @@ -32,7 +32,7 @@ The schema explorer URLs vary depending on your [deployment region](/docs/cloud/ | EMEA multi-tenant | https://semantic-layer.emea.dbt.com/api/graphql | | APAC multi-tenant | https://semantic-layer.au.dbt.com/api/graphql | | Single tenant | `https://semantic-layer.YOUR_ACCESS_URL.com/api/graphql`

Replace `YOUR_ACCESS_URL` with your specific account prefix with the appropriate Access URL for your region and plan.| -| North America Cell 1 | `https://semantic-layer.YOUR_ACCOUNT_PREFIX.us1.dbt.com/api/graphql`

Replace `YOUR_ACCOUNT_PREFIX` with your specific account prefix and make sure you leave `us1.dbt.com` in the URL. |
+| North America Cell 1 | `https://YOUR_ACCOUNT_PREFIX.semantic-layer.us1.dbt.com/api/graphql`

Replace `YOUR_ACCOUNT_PREFIX` with your specific account prefix and make sure you leave `us1.dbt.com` in the URL. |
**Example** - If your access URL is `ABC123.getdbt.com`, your schema explorer URL will be `https://semantic-layer.ABC123.getdbt.com/api/graphql`. From 4100168b502e525b3b907415dd61368440a00123 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:58:33 +0000 Subject: [PATCH 52/60] Update website/docs/docs/dbt-cloud-apis/sl-graphql.md --- website/docs/docs/dbt-cloud-apis/sl-graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/dbt-cloud-apis/sl-graphql.md b/website/docs/docs/dbt-cloud-apis/sl-graphql.md index 7785812f1b1..7306653e859 100644 --- a/website/docs/docs/dbt-cloud-apis/sl-graphql.md +++ b/website/docs/docs/dbt-cloud-apis/sl-graphql.md @@ -31,7 +31,7 @@ The schema explorer URLs vary depending on your [deployment region](/docs/cloud/ | North America multi-tenant | https://semantic-layer.cloud.getdbt.com/api/graphql | | EMEA multi-tenant | https://semantic-layer.emea.dbt.com/api/graphql | | APAC multi-tenant | https://semantic-layer.au.dbt.com/api/graphql | -| Single tenant | `https://semantic-layer.YOUR_ACCESS_URL.com/api/graphql`

Replace `YOUR_ACCESS_URL` with your specific account prefix with the appropriate Access URL for your region and plan.| +| Single tenant | `https://YOUR_ACCESS_URL.semantic-layer/api/graphql`

Replace `YOUR_ACCESS_URL` with your specific account prefix with the appropriate Access URL for your region and plan.| | North America Cell 1 | `https://YOUR_ACCOUNT_PREFIX.semantic-layer.us1.dbt.com/api/graphql`

Replace `YOUR_ACCOUNT_PREFIX` with your specific account prefix and make sure you leave `us1.dbt.com` in the URL. |
**Example** From cdd5767068815e9a0009a0d16a2604aa03456460 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:58:53 +0000 Subject: [PATCH 53/60] Update website/docs/docs/dbt-cloud-apis/sl-graphql.md --- website/docs/docs/dbt-cloud-apis/sl-graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/dbt-cloud-apis/sl-graphql.md b/website/docs/docs/dbt-cloud-apis/sl-graphql.md index 7306653e859..e8392d1357d 100644 --- a/website/docs/docs/dbt-cloud-apis/sl-graphql.md +++ b/website/docs/docs/dbt-cloud-apis/sl-graphql.md @@ -35,7 +35,7 @@ The schema explorer URLs vary depending on your [deployment region](/docs/cloud/ | North America Cell 1 | `https://YOUR_ACCOUNT_PREFIX.semantic-layer.us1.dbt.com/api/graphql`

Replace `YOUR_ACCOUNT_PREFIX` with your specific account prefix and make sure you leave `us1.dbt.com` in the URL. |
**Example** -- If your access URL is `ABC123.getdbt.com`, your schema explorer URL will be `https://semantic-layer.ABC123.getdbt.com/api/graphql`. +- If your access URL is `ABC123.getdbt.com`, your schema explorer URL will be `https://ABC123.getdbt.com.semantic-layer/api/graphql`. dbt Partners can use the Semantic Layer GraphQL API to build an integration with the dbt Semantic Layer. From d5e8e1084ed36112322a0efb1c13659183894486 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Tue, 16 Jan 2024 15:54:17 +0000 Subject: [PATCH 54/60] Update website/docs/docs/dbt-cloud-apis/sl-graphql.md --- website/docs/docs/dbt-cloud-apis/sl-graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/dbt-cloud-apis/sl-graphql.md b/website/docs/docs/dbt-cloud-apis/sl-graphql.md index e8392d1357d..edc3d1d2d8b 100644 --- a/website/docs/docs/dbt-cloud-apis/sl-graphql.md +++ b/website/docs/docs/dbt-cloud-apis/sl-graphql.md @@ -32,7 +32,7 @@ The schema explorer URLs vary depending on your [deployment region](/docs/cloud/ | EMEA multi-tenant | https://semantic-layer.emea.dbt.com/api/graphql | | APAC multi-tenant | https://semantic-layer.au.dbt.com/api/graphql | | Single tenant | `https://YOUR_ACCESS_URL.semantic-layer/api/graphql`

Replace `YOUR_ACCESS_URL` with your specific account prefix with the appropriate Access URL for your region and plan.| -| North America Cell 1 | `https://YOUR_ACCOUNT_PREFIX.semantic-layer.us1.dbt.com/api/graphql`

Replace `YOUR_ACCOUNT_PREFIX` with your specific account prefix and make sure you leave `us1.dbt.com` in the URL. |
+| North America Cell 1 | `https://YOUR_ACCOUNT_PREFIX.semantic-layer..dbt.com/api/graphql`

Replace `YOUR_ACCOUNT_PREFIX` with your specific account prefix and make sure you leave `us1.dbt.com` in the URL. |
**Example** - If your access URL is `ABC123.getdbt.com`, your schema explorer URL will be `https://ABC123.getdbt.com.semantic-layer/api/graphql`. From f1becc1f205935cad81a5dd2d7699a0757aaa595 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:01:08 +0000 Subject: [PATCH 55/60] Update sl-graphql.md --- website/docs/docs/dbt-cloud-apis/sl-graphql.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/docs/dbt-cloud-apis/sl-graphql.md b/website/docs/docs/dbt-cloud-apis/sl-graphql.md index edc3d1d2d8b..e1caf6c70b8 100644 --- a/website/docs/docs/dbt-cloud-apis/sl-graphql.md +++ b/website/docs/docs/dbt-cloud-apis/sl-graphql.md @@ -32,10 +32,10 @@ The schema explorer URLs vary depending on your [deployment region](/docs/cloud/ | EMEA multi-tenant | https://semantic-layer.emea.dbt.com/api/graphql | | APAC multi-tenant | https://semantic-layer.au.dbt.com/api/graphql | | Single tenant | `https://YOUR_ACCESS_URL.semantic-layer/api/graphql`

Replace `YOUR_ACCESS_URL` with your specific account prefix with the appropriate Access URL for your region and plan.| -| North America Cell 1 | `https://YOUR_ACCOUNT_PREFIX.semantic-layer..dbt.com/api/graphql`

Replace `YOUR_ACCOUNT_PREFIX` with your specific account prefix and make sure you leave `us1.dbt.com` in the URL. |
+| Multi-cell | `https://YOUR_ACCOUNT_PREFIX.semantic-layer.REGION.dbt.com/api/graphql`

Replace `YOUR_ACCOUNT_PREFIX` with your specific account identifier and `REGION` with your location, which could be `us1.dbt.com`. |
**Example** -- If your access URL is `ABC123.getdbt.com`, your schema explorer URL will be `https://ABC123.getdbt.com.semantic-layer/api/graphql`. +- If your Single tenant access URL is `ABC123.getdbt.com`, your schema explorer URL will be `https://ABC123.getdbt.com.semantic-layer/api/graphql`. dbt Partners can use the Semantic Layer GraphQL API to build an integration with the dbt Semantic Layer. From de140cfb6c01f63d103dd5d1ed910eb9e6660077 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:04:48 +0000 Subject: [PATCH 56/60] Update website/docs/docs/build/metrics-overview.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/metrics-overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/metrics-overview.md b/website/docs/docs/build/metrics-overview.md index 13a3c528348..35dc8f1f1c6 100644 --- a/website/docs/docs/build/metrics-overview.md +++ b/website/docs/docs/build/metrics-overview.md @@ -75,7 +75,7 @@ metrics: [Cumulative metrics](/docs/build/cumulative) aggregate a measure over a given window. If no window is specified, the window will accumulate the measure overall time. **Note**, you will need to create the [time spine model](/docs/build/metricflow-time-spine) before you add cumulative metrics. ```yaml -# Cumulative metrics aggregate a measure over a given window. The window is considered infinite if no window parameter is passed (accumulate the measure overall time) +# Cumulative metrics aggregate a measure over a given window. The window is considered infinite if no window parameter is passed (accumulate the measure over all of time) metrics: - name: wau_rolling_7 owners: From d89dd897568fa6378b59cef3ea22fb128b0f6f96 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:05:01 +0000 Subject: [PATCH 57/60] Update website/docs/docs/build/metrics-overview.md Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- website/docs/docs/build/metrics-overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/metrics-overview.md b/website/docs/docs/build/metrics-overview.md index 35dc8f1f1c6..ea602d0953f 100644 --- a/website/docs/docs/build/metrics-overview.md +++ b/website/docs/docs/build/metrics-overview.md @@ -72,7 +72,7 @@ metrics: ### Cumulative metrics -[Cumulative metrics](/docs/build/cumulative) aggregate a measure over a given window. If no window is specified, the window will accumulate the measure overall time. **Note**, you will need to create the [time spine model](/docs/build/metricflow-time-spine) before you add cumulative metrics. +[Cumulative metrics](/docs/build/cumulative) aggregate a measure over a given window. If no window is specified, the window will accumulate the measure over all of the recorded time period. Note that you will need to create the [time spine model](/docs/build/metricflow-time-spine) before you add cumulative metrics. ```yaml # Cumulative metrics aggregate a measure over a given window. The window is considered infinite if no window parameter is passed (accumulate the measure over all of time) From 0a62cc1eecde1bcb70bc56b21b322092b6e83960 Mon Sep 17 00:00:00 2001 From: Joel Labes Date: Wed, 17 Jan 2024 08:29:57 +1300 Subject: [PATCH 58/60] Include brew update command in Cloud CLI install docs (#4758) ## What are you changing in this pull request and why? After discussion in [this thread](https://dbt-labs.slack.com/archives/C051TUB7S9W/p1705431390401459?thread_ts=1705362864.627909&cid=C051TUB7S9W). Also fixed a copy-paste mistake while I was there --- website/docs/docs/cloud/cloud-cli-installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/docs/cloud/cloud-cli-installation.md b/website/docs/docs/cloud/cloud-cli-installation.md index 7d459cdd91d..a378d58428c 100644 --- a/website/docs/docs/cloud/cloud-cli-installation.md +++ b/website/docs/docs/cloud/cloud-cli-installation.md @@ -223,7 +223,7 @@ During the public preview period, we recommend updating before filing a bug repo -To update the dbt Cloud CLI, run `brew upgrade dbt`. (You can also use `brew install dbt`). +To update the dbt Cloud CLI, run `brew update` and then `brew upgrade dbt`. @@ -235,7 +235,7 @@ To update, follow the same process explained in [Windows](/docs/cloud/cloud-cli- -To update, follow the same process explained in [Windows](/docs/cloud/cloud-cli-installation?install=linux#install-dbt-cloud-cli) and replace the existing `dbt` executable with the new one. +To update, follow the same process explained in [Linux](/docs/cloud/cloud-cli-installation?install=linux#install-dbt-cloud-cli) and replace the existing `dbt` executable with the new one. From 56faf65dd071bea9ed96d65fb18b9f6751042836 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 17 Jan 2024 10:34:04 +0000 Subject: [PATCH 59/60] Update contributing/content-style-guide.md --- contributing/content-style-guide.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/contributing/content-style-guide.md b/contributing/content-style-guide.md index c6b85d7148d..0360ef0e84c 100644 --- a/contributing/content-style-guide.md +++ b/contributing/content-style-guide.md @@ -530,7 +530,14 @@ dbt Cloud CLI | CLI, dbt CLI dbt Core | CLI, dbt CLI -Make sure you keep the reader close to the content and documentation (second person). For example, to explain that a feature is available to a particular dbt Cloud plan — use “XYZ is available on Enterprise plans” or “People on Enterprise plans can XYZ..” to keep users closer to the documentation. This will signal to users to check their plan or account status on their own. +Note, let's make sure we're talking to our readers and keep them close to the content and documentation (second person). + +For example, to explain that a feature is available to a particular dbt Cloud plan, you can use: +- “XYZ is available on Enterprise plans”, +- “If you're on an Enterprise plan, you can access XYZ..” or +- "Enterprise plans can access XYZ..." to keep users closer to the documentation. + +This will signal users to check their plan or account status independently. ## Links From 956ee2af5c99fa3111b214db6f4cffdd39acd668 Mon Sep 17 00:00:00 2001 From: mirnawong1 <89008547+mirnawong1@users.noreply.github.com> Date: Wed, 17 Jan 2024 10:43:03 +0000 Subject: [PATCH 60/60] Update content-style-guide.md replacing the word to with on --- contributing/content-style-guide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contributing/content-style-guide.md b/contributing/content-style-guide.md index 0360ef0e84c..58f5ba2b21c 100644 --- a/contributing/content-style-guide.md +++ b/contributing/content-style-guide.md @@ -532,9 +532,9 @@ dbt Core | CLI, dbt CLI Note, let's make sure we're talking to our readers and keep them close to the content and documentation (second person). -For example, to explain that a feature is available to a particular dbt Cloud plan, you can use: -- “XYZ is available on Enterprise plans”, -- “If you're on an Enterprise plan, you can access XYZ..” or +For example, to explain that a feature is available on a particular dbt Cloud plan, you can use: +- “XYZ is available on Enterprise plans” +- “If you're on an Enterprise plan, you can access XYZ..” - "Enterprise plans can access XYZ..." to keep users closer to the documentation. This will signal users to check their plan or account status independently.