Skip to content

Commit

Permalink
Merge branch 'current' into mwong-hover-images
Browse files Browse the repository at this point in the history
  • Loading branch information
mirnawong1 authored Jan 19, 2024
2 parents 75186c7 + 20877b7 commit 14ee386
Show file tree
Hide file tree
Showing 32 changed files with 660 additions and 46 deletions.
10 changes: 10 additions & 0 deletions contributing/content-style-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -529,6 +530,15 @@ dbt Cloud CLI | CLI, dbt CLI
dbt Core | CLI, dbt CLI
</div></b>

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

## 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.
Expand Down
8 changes: 4 additions & 4 deletions website/blog/2023-08-01-announcing-materialized-views.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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)
Expand Down Expand Up @@ -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.
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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
---
title: Serverless, free-tier data stack with dlt + dbt core.
description: "In this article, Euan shares his personal project to fetch property price data during his and his partner's house-hunting process, and how he created a serverless free-tier data stack by using Google Cloud Functions to run data ingestion tool dlt alongside dbt for transformation."
slug: serverless-dlt-dbt-stack

authors: [euan_johnston]

hide_table_of_contents: false

date: 2023-01-15
is_featured: false
---



## The problem, the builder and tooling

**The problem**: My partner and I are considering buying a property in Portugal. There is no reference data for the real estate market here - how many houses are being sold, for what price? Nobody knows except the property office and maybe the banks, and they don’t readily divulge this information. The only data source we have is Idealista, which is a portal where real estate agencies post ads.

Unfortunately, there are significantly fewer properties than ads - it seems many real estate companies re-post the same ad that others do, with intentionally different data and often misleading bits of info. The real estate agencies do this so the interested parties reach out to them for clarification, and from there they can start a sales process. At the same time, the website with the ads is incentivised to allow this to continue as they get paid per ad, not per property.

**The builder:** I’m a data freelancer who deploys end to end solutions, so when I have a data problem, I cannot just let it go.

**The tools:** I want to be able to run my project on [Google Cloud Functions](https://cloud.google.com/functions) due to the generous free tier. [dlt](https://dlthub.com/) is a new Python library for declarative data ingestion which I have wanted to test for some time. Finally, I will use dbt Core for transformation.

## The starting point

If I want to have reliable information on the state of the market I will need to:

- Grab the messy data from Idealista and historize it.
- Deduplicate existing listings.
- Try to infer what listings sold for how much.

Once I have deduplicated listings with some online history, I can get an idea:

- How expensive which properties are.
- How fast they get sold, hopefully a signal of whether they are “worth it” or not.

## Towards a solution

The solution has pretty standard components:

- An EtL pipeline. The little t stands for normalisation, such as transforming strings to dates or unpacking nested structures. This is handled by dlt functions written in Python.
- A transformation layer taking the source data loaded by my dlt functions and creating the tables necessary, handled by dbt.
- Due to the complexity of deduplication, I needed to add a human element to confirm the deduplication in Google Sheets.

These elements are reflected in the diagram below and further clarified in greater detail later in the article:

<Lightbox src="/img/blog/serverless-free-tier-data-stack-with-dlt-and-dbt-core/architecture_diagram.png" width="70%" title="Project architecture" />

### Ingesting the data

For ingestion, I use a couple of sources:

First, I ingest home listings from the Idealista API, accessed through [API Dojo's freemium wrapper](https://rapidapi.com/apidojo/api/idealista2). The dlt pipeline I created for ingestion is in [this repo](https://github.com/euanjohnston-dev/Idealista_pipeline).

After an initial round of transformation (described in the next section), the deduplicated data is loaded into BigQuery where I can query it from the Google Sheets client and manually review the deduplication.

When I'm happy with the results, I use the [ready-made dlt Sheets source connector](https://dlthub.com/docs/dlt-ecosystem/verified-sources/google_sheets) to pull the data back into BigQuery, [as defined here](https://github.com/euanjohnston-dev/gsheets_check_pipeline).

### Transforming the data

For transforming I use my favorite solution, dbt Core. For running and orchestrating dbt on Cloud Functions, I am using dlt’s dbt Core runner. The benefit of the runner in this context is that I can re-use the same credential setup, instead of creating a separate profiles.yml file.

This is the package I created: <https://github.com/euanjohnston-dev/idealista_dbt_pipeline>

### Production-readying the pipeline

To make the pipeline more “production ready”, I made some improvements:

- Using a credential store instead of hard-coding passwords, in this case Google Secret Manager.
- Be notified when the pipeline runs and what the outcome is. For this I sent data to Slack via a dlt decorator that posts the error on failure and the metadata on success.

```python
from dlt.common.runtime.slack import send_slack_message

def notify_on_completion(hook):
def decorator(func):
def wrapper(*args, **kwargs):
try:
load_info = func(*args, **kwargs)
message = f"Function {func.__name__} completed successfully. Load info: {load_info}"
send_slack_message(hook, message)
return load_info
except Exception as e:
message = f"Function {func.__name__} failed. Error: {str(e)}"
send_slack_message(hook, message)
raise
return wrapper
return decorator
```

## The outcome

The outcome was first and foremost a visualisation highlighting the unique properties available in my specific area of search. The map shown on the left of the page gives a live overview of location, number of duplicates (bubble size) and price (bubble colour) which can amongst other features be filtered using the sliders on the right. This represents a much better decluttered solution from which to observe the actual inventory available.

<Lightbox src="/img/blog/serverless-free-tier-data-stack-with-dlt-and-dbt-core/map_screenshot.png" width="70%" title="Dashboard mapping overview" />

Further charts highlight additional metrics which – now that deduplication is complete – can be accurately measured including most importantly, the development over time of “average price/square metre” and those properties which have been inferred to have been sold.

### Next steps

This version was very much about getting a base from which to analyze the properties for my own personal use case.

In terms of further development which could take place, I have had interest from people to run the solution on their own specific target area.

For this to work at scale I would need a more robust method to deal with duplicate attribution, which is a difficult problem as real estate agencies intentionally change details like number of rooms or surface area.

Perhaps this is a problem ML or GPT could solve equally well as a human, given the limited options available.

## Learnings and conclusion

The data problem itself was an eye opener into the real-estate market. It’s a messy market full of unknowns and noise, which adds a significant purchase risk to first time buyers.

Tooling wise, it was surprising how quick it was to set everything up. dlt integrates well with dbt and enables fast and simple data ingestion, making this project simpler than I thought it would be.

### dlt

Good:

- As a big fan of dbt I love how seamlessly the two solutions complement one another. dlt handles the data cleaning and normalisation automatically so I can focus on curating and modelling it in dbt. While the automatic unpacking leaves some small adjustments for the analytics engineer, it’s much better than cleaning and typing json in the database or in custom python code.
- When creating my first dummy pipeline I used duckdb. It felt like a great introduction into how simple it is to get started and provided a solid starting block before developing something for the cloud.

Bad:

- I did have a small hiccup with the google sheets connector assuming an oauth authentication over my desired sdk but this was relatively easy to rectify. (explicitly stating GcpServiceAccountCredentials in the init.py file for the source).
- Using both a verified source in the gsheets connector and building my own from Rapid API endpoints seemed equally intuitive. However I would have wanted more documentation on how to run these 2 pipelines in the same script with the dbt pipeline.

### dbt

No surprises there. I developed the project locally, and to deploy to cloud functions I injected credentials to dbt via the dlt runner. This meant I could re-use the setup I did for the other dlt pipelines.

```python
def dbt_run():
# make an authenticated connection with dlt to the dwh
pipeline = dlt.pipeline(
pipeline_name='dbt_pipeline',
destination='bigquery', # credentials read from env
dataset_name='dbt'
)
# make a venv in case we have lib conflicts between dlt and current env
venv = dlt.dbt.get_venv(pipeline)
# package the pipeline, dbt package and env
dbt = dlt.dbt.package(pipeline, "dbt/property_analytics", venv=venv)
# and run it
models = dbt.run_all()
# show outcome
for m in models:
print(f"Model {m.model_name} materialized in {m.time} with status {m.status} and message {m.message}"
```

### Cloud functions

While I had used cloud functions before, I had never previously set them up for dbt and I was able to easily follow dlt’s docs to run the pipelines there. Cloud functions is a great solution to cheaply run small scale pipelines and my running cost of the project is a few cents a month. If the insights drawn from the project help us save even 1% of a house price, the project will have been a success.

### To sum up

dlt feels like the perfect solution for anyone who has scratched the surface of python development. To be able to have schemas ready for transformation in such a short space of time is truly… transformational. As a freelancer, being able to accelerate the development of pipelines is a huge benefit within companies who are often frustrated with the amount of time it takes to start ‘showing value’.

I’d welcome the chance to discuss what’s been built to date or collaborate on any potential further development in the comments below.
10 changes: 10 additions & 0 deletions website/blog/authors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,16 @@ emily_riederer:
- icon: fa-readme
url: https://emilyriederer.com

euan_johnston:
image_url: /img/blog/authors/ejohnston.png
job_title: Freelance Business Intelligence manager
name: Euan Johnston
links:
- icon: fa-linkedin
url: https://www.linkedin.com/in/euan-johnston-610a05a8/
- icon: fa-github
url: https://github.com/euanjohnston-dev

grace_goheen:
image_url: /img/blog/authors/grace-goheen.jpeg
job_title: Analytics Engineer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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**](/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**.
Expand Down
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) &mdash; 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) &mdash; Aggregates a measure over a given window.
- [Derived](/docs/build/derived) &mdash; An expression of other metrics, which allows you to do calculations on top of metrics.
- [Ratio](/docs/build/ratio) &mdash; Create a ratio out of two measures, like revenue per customer.
Expand Down
Loading

0 comments on commit 14ee386

Please sign in to comment.