<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Data-Eng on Max Halford</title><link>https://maxhalford.github.io/tags/data-eng/</link><description>Recent content in Data-Eng on Max Halford</description><generator>Hugo</generator><language>en-US</language><managingEditor>maxhalford25@gmail.com (Max Halford)</managingEditor><webMaster>maxhalford25@gmail.com (Max Halford)</webMaster><lastBuildDate>Tue, 21 Jul 2026 21:18:41 +0200</lastBuildDate><atom:link href="https://maxhalford.github.io/tags/data-eng/index.xml" rel="self" type="application/rss+xml"/><item><title>Lower your warehouse costs via DuckDB transpilation</title><link>https://maxhalford.github.io/blog/warehouse-cost-reduction-quack-mode/</link><pubDate>Thu, 12 Mar 2026 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/warehouse-cost-reduction-quack-mode/</guid><description>&lt;p&gt;Many people &lt;a href="https://survey.stackoverflow.co/2025/technology#2-databases"&gt;seem to admire&lt;/a&gt; DuckDB. But most of us are stuck with our traditional warehouses, because they&amp;rsquo;re entrenched in our data stacks and IT landscape. This is with good reason: BigQuery, Snowflake, ClickHouse and co. are great software. But they&amp;rsquo;re not cheap, and keeping a warehouse&amp;rsquo;s monthly bill under control is non-trivial.&lt;/p&gt;
&lt;p&gt;What if you could get the best of both worlds? Tables could be kept in your warehouse of choice, but computed with DuckDB. There&amp;rsquo;s been some discussion on multi-engine warehouses &amp;ndash; see &lt;a href="https://juhache.substack.com/p/multi-engine-stacks-deserve-to-be"&gt;this article&lt;/a&gt; by Julien Hurault and Sung Won Chung. But their proposition is to assign each table to one engine. Multi-engine stacks can be useful, and SQLMesh provides &lt;a href="https://sqlmesh.readthedocs.io/en/latest/guides/multi_engine"&gt;support&lt;/a&gt; for it. But to me it sounds too sophisticated, and I&amp;rsquo;m not convinced it&amp;rsquo;s what most practitioners want/need.&lt;/p&gt;</description></item><item><title>Row level lineage at Carbonfact</title><link>https://maxhalford.github.io/blog/row-level-lineage/</link><pubDate>Fri, 09 Jan 2026 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/row-level-lineage/</guid><description/></item><item><title>Thoughts on DuckLake</title><link>https://maxhalford.github.io/blog/ducklake-thoughts/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/ducklake-thoughts/</guid><description>&lt;p&gt;&lt;a href="https://ducklake.select/"&gt;DuckLake&lt;/a&gt; is the new data lake/warehouse from the makers of DuckDB. I really like the direction they&amp;rsquo;re taking. I&amp;rsquo;m hopeful it has the potential to streamline the data engineering workflow for many people, vastly reducing costs along the way.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m a bit of a nut and don&amp;rsquo;t use SQLMesh or dbt. Instead, I built &lt;a href="https://github.com/carbonfact/lea"&gt;lea&lt;/a&gt; a few years ago, and we still use it at &lt;a href="https://carbonfact.org"&gt;Carbonfact&lt;/a&gt;. I would probably pick SQLMesh if I had to start over, but lea allows me to explore new ideas, so I&amp;rsquo;m sticking to it for now.&lt;/p&gt;</description></item><item><title>Minimizing the runtime of a SQL DAG</title><link>https://maxhalford.github.io/blog/minimizing-sql-dag-runtime/</link><pubDate>Sat, 08 Feb 2025 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/minimizing-sql-dag-runtime/</guid><description>&lt;p&gt;I recently looked into reducing the runtime of &lt;a href="https://www.carbonfact.com/"&gt;Carbonfact&lt;/a&gt;&amp;rsquo;s SQL DAG. Our DAG is made up of roughly 160 SQL queries. It takes about 10 minutes to run with BigQuery, using on-demand pricing. It&amp;rsquo;s decent. However, the results of our DAG feed customer dashboards, and we have the (bad) habit of refreshing the DAG several times a day. Reducing the runtime by a few minutes can be a nice quality-of-life improvement.&lt;/p&gt;</description></item><item><title>A training set for bike sharing forecasting</title><link>https://maxhalford.github.io/blog/bike-sharing-forecasting-training-set/</link><pubDate>Thu, 04 Apr 2024 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/bike-sharing-forecasting-training-set/</guid><description>&lt;style&gt;
table {
 font-family: monospace; /* Apply monospace font */
}

table td, table th {
 white-space: nowrap; /* Prevent text from wrapping */
}
&lt;/style&gt;
&lt;p&gt;Last night I went to a &lt;a href="https://www.meetup.com/fr-FR/tlse-data-science/"&gt;Toulouse Data Science&lt;/a&gt; meetup. The talks were about generative AI and information retrieval, which aren&amp;rsquo;t topics I&amp;rsquo;m knowledgeable about. However, one of the speakers was a &lt;a href="https://github.com/raphaelsty"&gt;friend&lt;/a&gt; of mine, so I went to support him. Toulouse used to be my hometown, so I bumped into a few people I knew. It was a nice evening.&lt;/p&gt;</description></item><item><title>Efficient ELT refreshes</title><link>https://maxhalford.github.io/blog/efficient-data-transformation/</link><pubDate>Fri, 01 Dec 2023 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/efficient-data-transformation/</guid><description>&lt;p&gt;A tenant of the modern data stack is the use of ELT (Extract, Load, Transform) over ETL (Extract, Transform, Load). In a nutshell, this means that most of the data transformation is done in the data warehouse. This has become the &lt;em&gt;de facto&lt;/em&gt; standard for modern data teams, and is epitomized by &lt;a href="https://www.getdbt.com/"&gt;dbt&lt;/a&gt; and its ecosystem. It&amp;rsquo;s a great time to be a data engineer!&lt;/p&gt;
&lt;p&gt;We at &lt;a href="https://www.carbonfact.com/"&gt;Carbonfact&lt;/a&gt; fully embrace the ELT paradigm. In fact, our whole platform is powered by BigQuery, which acts as our single source of truth. We have a main BigQuery dataset where we materialize several SQL views that power what our customers see.&lt;/p&gt;</description></item><item><title>Sh*t flows downhill, but not at Carbonfact</title><link>https://maxhalford.github.io/blog/shit-flows-downhill-but-not-at-carbonfact/</link><pubDate>Mon, 16 Oct 2023 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/shit-flows-downhill-but-not-at-carbonfact/</guid><description>&lt;p&gt;I&amp;rsquo;m writing this after watching the talk &lt;a href="https://josephreis.com/"&gt;Joe Reis&lt;/a&gt; gave at &lt;a href="https://bigdataldn.com/"&gt;Big Data LDN&lt;/a&gt;. It&amp;rsquo;s called &lt;a href="https://www.youtube.com/watch?app=desktop&amp;amp;v=OCClTPOEe5s&amp;amp;ref=blef.fr"&gt;Data Modeling is Dead! Long Live Data Modeling!&lt;/a&gt; It&amp;rsquo;s an easy-to-watch short talk that calls out on a few modern issues in the data world.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d like to bounce off one of Joe&amp;rsquo;s slides:&lt;/p&gt;
&lt;div align="center" &gt;
&lt;figure style="width: 80%; margin: 0;"&gt;
 &lt;img src="https://maxhalford.github.io/img/blog/shit-flows-downhill-but-not-at-carbonfact/shit-flows-downhill.png"&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;I&amp;rsquo;m aligned with Joe that many issues stem from the lack of unison between engineering and data teams. A fundamental aspect of the Modern Data Stack is to replicate/copy production data into an analytics warehouse. For instance, copying the production PostgreSQL database into BigQuery.&lt;/p&gt;</description></item><item><title>For analytics, don't use dynamic JSON keys</title><link>https://maxhalford.github.io/blog/no-dynamic-keys-in-json/</link><pubDate>Thu, 11 May 2023 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/no-dynamic-keys-in-json/</guid><description>&lt;p&gt;I love the JSON format. It&amp;rsquo;s the kind of love that grows on you with time. Like others, I&amp;rsquo;ve been using JSON everywhere for so many years, to the point where I just take it for granted.&lt;/p&gt;
&lt;p&gt;I suppose the main thing I like about JSON is its flexibility. You can structure your JSONs without too much care. There will always be a way to consume and manipulate it. But I have discovered a bit of anti-pattern, which I believe is worth raising awareness about. Especially when you&amp;rsquo;re doing analytics.&lt;/p&gt;</description></item><item><title>A rant against dbt ref</title><link>https://maxhalford.github.io/blog/dbt-ref-rant/</link><pubDate>Tue, 28 Jun 2022 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/dbt-ref-rant/</guid><description>&lt;h2 id="disclaimer"&gt;Disclaimer&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Let me be absolutely clear: I think dbt is a great tool. Although this post is a rant, the goal is to be constructive and suggest an improvement.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="dbt-in-a-nutshell"&gt;dbt in a nutshell&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.getdbt.com/"&gt;dbt&lt;/a&gt; is a workflow orchestrator for SQL. In other words, it&amp;rsquo;s a fancy &lt;a href="https://en.wikipedia.org/wiki/Make_(software)"&gt;Make&lt;/a&gt; for data analytics. What makes dbt special is that it is the first workflow orchestrator that is dedicated to the SQL language. It said out loud what many data teams were thinking: you can get a lot done with SQL.&lt;/p&gt;</description></item><item><title>Dashboards and GROUPING SETS</title><link>https://maxhalford.github.io/blog/grouping-sets/</link><pubDate>Fri, 10 Sep 2021 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/grouping-sets/</guid><description>&lt;h2 id="motivation"&gt;Motivation&lt;/h2&gt;
&lt;p&gt;At &lt;a href="https://alan.com/"&gt;Alan&lt;/a&gt;, we do almost all our data analysis in SQL. Our data warehouse used to be &lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt;, and have since switched to &lt;a href="https://www.snowflake.com/"&gt;Snowflake&lt;/a&gt; for performance reasons. We load data into our warehouse with &lt;a href="https://airflow.apache.org/"&gt;Airflow&lt;/a&gt;. This includes dumps of our production database, third-party data, and health data from other actors in the health ecosystem. This is raw data. We transform this into prepared data via an in-house tool that resembles &lt;a href="https://www.getdbt.com/"&gt;dbt&lt;/a&gt;. You can read more about it &lt;a href="https://medium.com/alan/how-we-solve-the-problem-of-sharing-actionable-data-with-the-team-7e4afeff3cac"&gt;here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>An overview of dataset time travel</title><link>https://maxhalford.github.io/blog/dataset-time-travel/</link><pubDate>Wed, 07 Apr 2021 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/dataset-time-travel/</guid><description>&lt;h2 id="tldr"&gt;TLDR&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;re a data scientist. The engineers in your company overwrite data in the production database. You want to access overwritten data to train your models. How?&lt;/p&gt;
&lt;h2 id="i-thought-time-travel-only-existed-in-the-movies"&gt;I thought time travel only existed in the movies&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;re probably right, expect maybe for &lt;a href="https://en.wikipedia.org/wiki/Time_travel_claims_and_urban_legends#/Present-day_hipster_at_1941_bridge_opening"&gt;this guy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I want to discuss a concept that&amp;rsquo;s been on my mind for a while now. I like to call it &amp;ldquo;dataset time travel&amp;rdquo; because it has a nice ring to it. But the association of &amp;ldquo;time travel&amp;rdquo; and &amp;ldquo;data&amp;rdquo; has already been used elsewhere. It&amp;rsquo;s not something I&amp;rsquo;m pulling out from thin air. Essentially, what I want to discuss is the ability to view a dataset at any given point in the past. Having this ability is powerful, as it allows answering important business questions. As an example, let&amp;rsquo;s say we have a database table called &lt;code&gt;users&lt;/code&gt;. We might ask the following question:&lt;/p&gt;</description></item><item><title>A few intermediate pandas tricks</title><link>https://maxhalford.github.io/blog/pandas-tricks/</link><pubDate>Mon, 17 Aug 2020 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/pandas-tricks/</guid><description>&lt;p&gt;I want to use this post to share some &lt;code&gt;pandas&lt;/code&gt; snippets that I find useful. I use them from time to time, in particular when I&amp;rsquo;m doing &lt;a href="https://www.kaggle.com/search?q=time+series+in%3Acompetitions"&gt;time series competitions&lt;/a&gt; on platforms such as Kaggle. Like any data scientist, I perform similar data processing steps on different datasets. Usually, I put repetitive patterns in &lt;a href="https://github.com/MaxHalford/xam"&gt;&lt;code&gt;xam&lt;/code&gt;&lt;/a&gt;, which is my personal data science toolbox. However, I think that the following snippets are too small and too specific for being added into a library.&lt;/p&gt;</description></item><item><title>Finding fuzzy duplicates with pandas</title><link>https://maxhalford.github.io/blog/transitive-duplicates/</link><pubDate>Mon, 16 Sep 2019 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/transitive-duplicates/</guid><description>&lt;p&gt;Duplicate detection is the task of finding two or more instances in a dataset that are in fact identical. As an example, take the following toy dataset:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: center"&gt;&lt;/th&gt;
					&lt;th style="text-align: center"&gt;&lt;strong&gt;First name&lt;/strong&gt;&lt;/th&gt;
					&lt;th style="text-align: center"&gt;&lt;strong&gt;Last name&lt;/strong&gt;&lt;/th&gt;
					&lt;th style="text-align: center"&gt;&lt;strong&gt;Email&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;0&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Erlich&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Bachman&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;a href="mailto:eb@piedpiper.com"&gt;eb@piedpiper.com&lt;/a&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;1&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Erlich&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Bachmann&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;a href="mailto:eb@piedpiper.com"&gt;eb@piedpiper.com&lt;/a&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;2&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Erlik&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Bachman&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;a href="mailto:eb@piedpiper.co"&gt;eb@piedpiper.co&lt;/a&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;3&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Erlich&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Bachmann&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;a href="mailto:eb@piedpiper.com"&gt;eb@piedpiper.com&lt;/a&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each of these instances (rows, if you prefer) corresponds to the same &amp;ldquo;thing&amp;rdquo; &amp;ndash; note that I&amp;rsquo;m not using the word &amp;ldquo;entity&amp;rdquo; because &lt;a href="https://en.wikipedia.org/wiki/Record_linkage#/Entity_resolution"&gt;entity resolution&lt;/a&gt; is a different, and yet related, concept. In my experience there are two main reasons why data duplication may occur:&lt;/p&gt;</description></item><item><title>A smooth approach to putting machine learning into production</title><link>https://maxhalford.github.io/blog/machine-learning-production/</link><pubDate>Sat, 13 Jul 2019 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/machine-learning-production/</guid><description>&lt;p&gt;Putting machine learning into production is hard. Usually I&amp;rsquo;m doubtful of such statements, but in this case I&amp;rsquo;ve never met anyone for whom everything has gone smoothly. Most data scientists might agree that there is a huge gap between their local environment and a live environment. In fact, &amp;ldquo;productionalizing&amp;rdquo; machine learning is such a complex topic that entire companies have risen to address the issue. I&amp;rsquo;m not just talking about running a gigantic grid search and finding the best model, I&amp;rsquo;m talking about putting a machine learning model live so that it actually has a positive impact on your business/project. Off the top of my head: &lt;a href="https://www.cubonacci.com/"&gt;Cubonacci&lt;/a&gt;, &lt;a href="https://www.h2o.ai/"&gt;H2O&lt;/a&gt;, &lt;a href="https://cloud.google.com/automl/"&gt;Google AutoML&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/sagemaker/latest/dg/how-it-works-hosting.html"&gt;Amazon Sagemaker&lt;/a&gt;, and &lt;a href="https://www.datarobot.com/"&gt;DataRobot&lt;/a&gt;. In other words people are making money off businesses because data scientists and engineers are having a hard putting their models into production. In my opinion if a data scientist can&amp;rsquo;t put her model into production herself then something is wrong. Life should be simpler.&lt;/p&gt;</description></item><item><title>Skyline queries in Python</title><link>https://maxhalford.github.io/blog/skyline-queries/</link><pubDate>Tue, 21 May 2019 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/skyline-queries/</guid><description>&lt;p&gt;Imagine that you&amp;rsquo;re looking to buy a home. If you have an analytical mind then you might want to tackle this with a quantitative. Let&amp;rsquo;s suppose that you have a list of potential homes, and each home has some attributes that can help you compare them. As an example, we&amp;rsquo;ll consider three attributes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;price&lt;/code&gt; of the house, which you want to minimize&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;size&lt;/code&gt; of the house, which you want to maximize&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;city&lt;/code&gt; where the house if located, which you don&amp;rsquo;t really care about&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some houses will be objectively better than others because they will be cheaper and bigger. However, for some pairs of houses the comparison will not be as clear. It might be that house A is more expensive than house B but is also larger. In data analysis this set of best houses which are incomparable with each other is called a &lt;a href="https://en.wikipedia.org/wiki/Skyline_operator"&gt;skyline&lt;/a&gt;. As they say, a picture is worth a thousand words, so let&amp;rsquo;s draw one.&lt;/p&gt;</description></item></channel></rss>