Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add conversion-metrics-docs #4724

Merged
merged 53 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
fc17dd1
add conversion-metrics-docs
Jstein77 Jan 8, 2024
897a938
Merge branch 'current' into js-conversion-metrics
mirnawong1 Jan 9, 2024
10709aa
edits to conversion metrics v1
mirnawong1 Jan 9, 2024
fe44dbc
more changes v2
mirnawong1 Jan 9, 2024
f62e3c6
edits v3
mirnawong1 Jan 9, 2024
7714cd3
v4
mirnawong1 Jan 9, 2024
c9cfe84
add in metrics overview page
mirnawong1 Jan 9, 2024
516f169
tweak for clarity
mirnawong1 Jan 9, 2024
1d195d0
Merge branch 'current' into js-conversion-metrics
mirnawong1 Jan 9, 2024
2e487c4
turn to code
mirnawong1 Jan 9, 2024
5c13a46
Merge branch 'js-conversion-metrics' of https://github.com/dbt-labs/d…
mirnawong1 Jan 9, 2024
310c79c
Merge branch 'current' into js-conversion-metrics
mirnawong1 Jan 9, 2024
e290f92
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
43a8732
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
437db25
Update conversion-metrics.md
mirnawong1 Jan 10, 2024
2215f00
add in about mf page
mirnawong1 Jan 10, 2024
4cb9141
spell out infinity
mirnawong1 Jan 10, 2024
4cf6529
Merge branch 'current' into js-conversion-metrics
mirnawong1 Jan 10, 2024
d8003b0
Merge branch 'current' into js-conversion-metrics
mirnawong1 Jan 10, 2024
4b44e3d
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
71da2df
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
c5451b0
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
b16da0f
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
a583c29
Update conversion-metrics.md
mirnawong1 Jan 10, 2024
c4f9fb7
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
f232b8f
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
466c8ee
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
f847e96
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
7d8309d
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
2a44a70
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
e348ea4
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
cfa6c27
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
beda09f
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
5be89e8
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
bc73503
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
ed23be1
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
9eddea5
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
089d56b
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
8cb6e0f
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
8ed5662
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
14f0c23
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
e5e2edd
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
d42745d
add
mirnawong1 Jan 10, 2024
f0cbf80
Merge branch 'js-conversion-metrics' of https://github.com/dbt-labs/d…
mirnawong1 Jan 10, 2024
98b797e
Update conversion-metrics.md
mirnawong1 Jan 10, 2024
6f7d840
Merge branch 'current' into js-conversion-metrics
mirnawong1 Jan 10, 2024
6e3571a
Update website/docs/docs/build/conversion-metrics.md
mirnawong1 Jan 10, 2024
4ed917d
Merge branch 'current' into js-conversion-metrics
mirnawong1 Jan 12, 2024
27d72a1
add link
mirnawong1 Jan 12, 2024
4e31618
Update conversion-metrics.md
Jstein77 Jan 13, 2024
099b1d9
Merge branch 'current' into js-conversion-metrics
mirnawong1 Jan 15, 2024
316ec42
Merge branch 'current' into js-conversion-metrics
mirnawong1 Jan 15, 2024
f26fc84
Update conversion-metrics.md
Jstein77 Jan 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions website/docs/docs/build/about-metricflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
351 changes: 351 additions & 0 deletions website/docs/docs/build/conversion-metrics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,351 @@
---
title: "Conversion metrics"
id: conversion
description: "Use Conversion metrics to measure conversion events."
sidebar_label: Conversion
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).
mirnawong1 marked this conversation as resolved.
Show resolved Hide resolved
- **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.
mirnawong1 marked this conversation as resolved.
Show resolved Hide resolved

## Parameters

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 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 |
| `entity` | The entity for each conversion event. | Entity | 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 | Optional |
| `constant_properties` | List of constant properties. Defaults to None. | List | Optional |
mirnawong1 marked this conversation as resolved.
Show resolved Hide resolved
| `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:

```yaml
metrics:
mirnawong1 marked this conversation as resolved.
Show resolved Hide resolved
- 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: 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
```
mirnawong1 marked this conversation as resolved.
Show resolved Hide resolved

## Conversion metric example

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 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.

The underlying tables look like the following:

`VISITS`<br />
Contains user visits with `USER_ID` and `REFERRER_ID`.

| DS | USER_ID | REFERRER_ID |
| --- | --- | --- |
| 2020-01-01 | bob | facebook |
| 2020-01-04 | bob | google |
| 2020-01-07 | bob | amazon |

`BUYS`<br />
Records completed orders with `USER_ID` and `REFERRER_ID`.

| DS | USER_ID | REFERRER_ID |
| --- | --- | --- |
| 2020-01-02 | bob | facebook |
| 2020-01-07 | bob | amazon |

Next, define a conversion metric as follows:

```yaml
- 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)
type_params:
conversion_type_params:
base_measure: visits
conversion_measure: sellers
entity: user
window: 7 days
```

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: 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 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:
mirnawong1 marked this conversation as resolved.
Show resolved Hide resolved

```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 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 |
| --- | --- | --- | --- | --- | --- |
| 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: 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:

```sql
select
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
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'

```

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 |
| 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, 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.

### Step 3: Remove 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) 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
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';
```

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 |

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.
3. Calculate the conversion rate.

### Step 4: Aggregate and calculate

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
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, add --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
metric_time__day
```

### 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 for specific scenarios to join conversions on constant properties.

<Tabs>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turned this content to tabs

<TabItem value="null" label="Set null conversion events to zero">

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
mirnawong1 marked this conversation as resolved.
Show resolved Hide resolved
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

```
mirnawong1 marked this conversation as resolved.
Show resolved Hide resolved

This will return the following results:

<Lightbox src="/img/docs/dbt-cloud/semantic-layer/conversion-metrics-fill-null.png" width="75%" title="Conversion metric with fill nulls with parameter"/>

</TabItem>

<TabItem value="calctype" label="Set calculation type 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
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
```

</TabItem>

<TabItem value="constproperty" label="Set constant property">

mirnawong1 marked this conversation as resolved.
Show resolved Hide resolved
*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 question:
- _How often did visitors convert from `View Item Details` to `Complete Purchase` with the same product in each step?_<br />
- 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 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:
mirnawong1 marked this conversation as resolved.
Show resolved Hide resolved

```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
```

You will add an additional condition to the join to make sure the constant property is the same across conversions.

```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
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

```

</TabItem>
</Tabs>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ends rather abruptly. Do we want to have any summary or closing statement at the end?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is consistent with all other metric types so it might be fine for now, until we add more functions. I'm going to cc @Jstein77 in case we can add more use cases or functions (like filter)?

22 changes: 22 additions & 0 deletions website/docs/docs/build/metrics-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <Lifecycle status='new'/>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding this bc it's a new feature for users and falls within the 'lifecycle' scope. will remove next month (reminder set)


[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
mirnawong1 marked this conversation as resolved.
Show resolved Hide resolved
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: 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
```

### 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.
Expand All @@ -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.
Expand Down
Loading
Loading