在 Dataiku DSS 里做数据处理,可视化 Recipes 是我们每天都要打交道的东西。不管是 Prepare、Group、Join 还是 Window Recipe,大家打开界面后往往会发现,虽然每个 Recipe 的核心逻辑不一样,但左侧或右侧的面板里总有那么几个步骤长得差不多——其中出镜率最高的,就是 Pre-filter(预过滤)、Post-filter(后过滤)和 Computed columns(计算列)。
很多人在这三个地方吃过亏。有人把过滤条件写在了 Pre-filter 里,结果后面算出来的新列根本没法用;有人在 Computed columns 里写了一大串表达式,却因为数据类型没转对,整列算出来全是 null;还有人把本该在 Post-filter 里做的行筛选硬塞进预过滤,导致 Join 的时候关联键出了问题。这篇文章我就把这几个通用步骤彻底讲透,从设计思路到实操细节,再到我这些年踩过的坑,一次性说清楚。
1. 内容整体设计与思路拆解
先说设计思路。Dataiku DSS 把 Recipe 界面设计成“三步走”的通用框架,不是拍脑袋定的,而是基于一个很朴素的逻辑:你先决定要处理哪些数据,再决定怎么处理,最后再决定留下哪些结果。
这个逻辑说起来简单,但实际用起来很多人会混淆。我见过不少用户,在 Prepare Recipe 里先做了过滤,然后又想用过滤后的数据去算一个平均值,结果发现平均值算出来不对——因为预过滤是在每个独立行进入处理流程之前就生效的,它影响的是整个 Recipe 的输入数据范围。而后过滤是在所有计算完成之后才执行的,它只影响最终输出到下一个数据集的行集合,不会影响前面任何一步的计算结果。
我把这个关系梳理成一个简单的对照表:
| 步骤 | 执行时机 | 影响范围 | 典型用途 |
|---|---|---|---|
| Pre-filter(预过滤) | Recipe 开始处理前 | 影响后续所有步骤的输入数据 | 剔除无效行、缩小数据范围、减少计算量 |
| Computed columns(计算列) | 过滤之后、聚合或输出之前 | 只影响当前 Recipe 内部的计算结果 | 创建新字段、转换数据格式、计算衍生指标 |
| Post-filter(后过滤) | 所有计算完成后、输出前 | 只影响最终输出的行集合 | 根据计算结果筛选、条件化保留数据 |
这个顺序不是随便排的。预过滤放在最前面,是为了让后续的计算跑得更快、更准——你想想看,如果你有 1 亿行日志数据,其中 30% 是无效记录,不做预过滤就让计算机硬算,纯粹是浪费资源。计算列放在中间,是为了让它能消费预过滤后的干净数据,同时给后过滤提供筛选依据。后过滤放在最后,是因为有些筛选条件依赖于计算列的结果——比如你算完了客单价之后,想只保留客单价大于 100 元的订单,这种条件在预过滤阶段根本写不出来,因为你那时候还没有客单价这个字段。
这个设计的精髓在于:每一层只做自己该做的事,不能越界。预过滤不该去依赖计算列的结果,后过滤也不该去改变计算逻辑,否则整个 Recipe 的执行顺序就乱了。
2. 核心细节解析与实操要点
2.1 预过滤:数据进入处理管线之前的第一道闸门
预过滤写起来很简单,就是在 Recipe 的 Filters 区域加条件,但它背后的执行逻辑有很多讲究。
第一,预过滤是在数据读取之后、任何处理步骤开始之前执行的。这意味着它看不到你在 Recipe 里创建的任何新列,因为那些列还不存在。所以你在预过滤里只能引用数据集中原有的字段。如果你试图在预过滤里引用一个计算列,DS 会直接报错,或者更隐蔽的是——不会报错,但条件永远不成立,导致输出全空。
第二,预过滤的语法用的是 DSS 的标准过滤表达式。默认情况下你可以在界面上选择字段、操作符、值,比如“status equals 'closed'”“amount greater than 100”。但真正灵活的方式是用高级模式,直接写表达式。我给大家一个我自己常用的写法:
isNotNull(email) && (amount >= 100 || priority == 'high')这个表达式的意思是:email 不能为空,并且(金额大于等于 100,或者优先级是 high)。注意括号的用法,在 DSS 的过滤表达式里,逻辑优先级有时候跟你想的不一样,建议不确定的时候都加括号。
第三,预过滤对性能的影响非常明显。如果你的数据量是千万级别,预过滤能砍掉一半的数据,那么后续所有步骤——不管是 Join、Group 还是窗口计算——都会快上一倍不止。反过来,如果你把所有过滤都放在后过滤,那计算引擎就得先把所有数据算完再筛,性能差距可能达到数倍。
我有一个经验:能前置的过滤尽量前置。但这里有个度的问题——前置过滤是有限制的,它只能基于原始字段。如果你需要基于衍生字段(比如计算列的结果)来过滤,那只能在后过滤里做。这个问题会在后面详细展开。
2.2 后过滤:在大门关闭之前做最后的甄别
后过滤的界面和预过滤几乎一模一样,只是位置不同,因此在概念上很容易被混淆。但它们的能力边界完全不同。
后过滤的最大价值在于:它可以引用整个 Recipe 生命周期内产生的所有字段,包括计算列、聚合结果、窗口函数结果。举个例子,你在 Prepare Recipe 里用计算列算出了“订单金额 - 退款金额 = 净收入”,然后你想只保留净收入为负的异常订单——这个条件在预过滤里铁定写不了,但在后过滤里轻轻松松:
net_revenue < 0另一个典型场景是 Group Recipe。你在 Group Recipe 里按用户分组,然后算出每个用户的总消费额、订单数、平均客单价。后过滤就可以直接写:
total_spend >= 1000 && order_count >= 5把所有高价值用户筛出来。这个逻辑如果用预过滤来做,得先 Join 回原始表,再用 Join 后的结果去过滤,麻烦不说,还容易出错。
还有一个细节:后过滤不只是用来筛行,它还能帮你做数据质量检查。比如你算完净收入后,发现有一批记录净收入是 null,可能是因为源数据里退款金额是 null。你可以在后过滤里写:
net_revenue != null把这些脏数据直接挡在输出之外。这种做法是保证下游数据质量的一个非常实用的招数。
2.3 计算列:Recipe 内部最强大的字段加工工具
计算列是视觉化 Recipe 里最灵活、但也是最容易写错的部分。在 Prepare Recipe 里叫 Computed Columns,在 Group Recipe 里叫 Aggregated Columns(本质上也是计算列,只不过用的是聚合函数),在 Join Recipe 里则可以通过“Add new columns”来生成基于两侧字段的新列。
计算列的核心是用表达式语言(Formula Language)来生成新的字段值。这个表达式语言看着像 SQL 和 Excel 公式的混合体,但有不少自己的脾气。
首先,最基本的写法是用=号开头:
= abs(amount) + 10其次,如果你要处理字符串,可以用各种字符串函数。比如把 customer_name 转成大写:
= upper(customer_name)或者从 email 里提取域名:
= substring(email, position(email, '@') + 1)再比如处理时间字段。时间字段在 DSS 里有三种类型:Date、Timestamp 和 string 形式的日期。如果你直接拿一个 string 形式的日期去跟另一个 Timestamp 比较,大概率会得到错误结果,或者直接被当字符串处理了。所以我一直强调:写计算列之前,先确认字段类型。你可以用dataType()函数检查类型,也可以用parseDate()把字符串转成日期再运算。
这里我要重点说一个函数:if条件。它的语法是:
if(条件, 真值, 假值)举例:
= if(revenue > 0, '盈利', '亏损')这个函数写起来很简单,但嵌套多了就很容易乱。我自己一般会拆成多步,先在一步里算出一个中间结果,再在下一步里基于中间结果做分类。这样逻辑清楚,出错了也好排查。
还有一个很多人不知道的小技巧:在计算列里可以直接引用前面步骤已经创建的计算列。这意味着计算列可以链式依赖,一层层叠加。比如:
- 第 1 步:
= quantity * unit_price,生成gross_amount - 第 2 步:
= gross_amount - discount,生成net_amount - 第 3 步:
= if(net_amount < 0, 0, net_amount),生成final_amount
这种链式写法比一步写出一个巨大的嵌套表达式要清晰得多,后期维护的时候也省心。
2.4 三种操作的执行顺序和潜在误区
打个简单的比方:预过滤像是进考场前的安检,计算列像是考场里做题,后过滤像是交卷时的检查。安检阶段你只能检查身上带的东西(原始数据集里的字段),做题阶段你可以使用草稿纸上的所有东西(前面算出来的所有中间结果),交卷检查阶段你可以决定哪些题目算数(哪些行留到最终输出)。
这个比喻看起来很顺,但实操中有一个很容易翻车的细节:预过滤虽然看不到计算列,但它会影响到计算列的输入。什么意思呢?假设你有 100 行数据,预过滤筛掉了 20 行,剩下的 80 行参与计算列的计算。那么计算列的结果是基于这 80 行算出来的。如果你在预过滤前就想好要用某个计算列的均值来做归一化,那么实际上这个均值是基于过滤后的 80 行算出来的,而不是全量 100 行的均值。
这个逻辑有时候是有意为之,比如你想只看已支付订单的均值;但有时候是无心之失,比如你本来想用全量数据的均值做归一化,却忘了预过滤已经改变了输入范围。我建议大家在设计 Recipe 的时候,强制自己在心里过一遍执行顺序:预过滤 → 计算列 →(聚合/Join/窗口)→ 后过滤 →输出。每一步都明确知道自己面对的是哪些数据。
另一个常见误区是:在同一个 Recipe 里反复切换预过滤和后过滤,却不清楚自己到底想筛什么。比如有人先是预过滤status == 'closed',然后计算列算出days_to_close,又后过滤days_to_close <= 30,结果发现输出的行数很少,就开始怀疑是不是计算列算错了。其实没算错,只是两个过滤条件叠加之后,符合条件的数据本来就少。这时候要用到的排查技巧,我会在第 4 节详细讲。
3. 实操过程与核心环节实现
3.1 场景设定与数据准备
讲完了理论,我们用一个具体的例子把整个流程串一遍。假设我有一份电商订单数据(模拟数据),包含以下字段:
| 字段名 | 类型 | 说明 |
|---|---|---|
| order_id | string | 订单 ID |
| customer_id | string | 客户 ID |
| order_date | date | 下单日期 |
| status | string | 订单状态(closed / pending / cancelled) |
| quantity | int | 商品数量 |
| unit_price | double | 单价 |
| discount | double | 折扣金额 |
| refund_amount | double | 退款金额 |
| string | 客户邮箱 |
我的业务需求是:统计每个客户的净消费金额(商品总价 - 折扣 - 退款),然后找出净消费金额 >= 500 且订单数 >= 3 的活跃高价值客户。最后只要这些客户的订单记录。
这个需求如果不用预过滤、计算列、后过滤,直接硬写,Recipe 会乱成一锅粥。我们按部就班来。
3.2 预过滤:先把无效订单挡住
打开 Prepare Recipe,第一步就是加预过滤条件。
我这里的原始数据有 100 万行,其中包含大量status == 'cancelled'的订单和 email 为空的匿名订单。这些记录在后续计算里都是噪音,应该直接剔除。
预过滤表达式:
status != 'cancelled' && isNotNull(email)注意到没有,我没有直接把status == 'closed'作为预过滤条件,因为业务上pending状态的订单虽然还没完成,但后续可能变成closed,目前阶段先保留它们,等后过滤的时候再根据计算列结果来筛选。
这一步的效果:100 万行 → 85 万行。跑数时间直接少了 15%。
提示:预过滤里如果写
isNotNull(email),效率会比email != null更高,写法也更标准。在 DSS 的表达式里,判断空值要用isNull()/isNotNull(),用== null有时候会被解析成字符串比较,结果永远为 false。
3.3 计算列:分步构建净消费金额
有了干净的 85 万行数据之后,我创建三个计算列。
第 1 列:gross_amount,计算原始金额
= quantity * unit_price第 2 列:net_amount,扣除折扣和退款
= gross_amount - discount - refund_amount第 3 列:customer_status,打标客户类型
= if(net_amount >= 500, 'high_value', if(net_amount >= 100, 'medium_value', 'low_value'))注意第三列我用了嵌套if。这里有个经验:嵌套 if 的括号非常容易写错,所以我个人更建议大家拆成两步——先算net_amount,再基于net_amount写个简单的if,如果还要细分就再算一列。宁可多建一列,不要用一个巨型嵌套表达式。
创建完这三列之后,你的数据集中就有了新的可用字段。这时候你可以先点一下 Run,看看结果是否如预期。我习惯每加一个关键计算列就跑一次,不攒到最后才验证,这样问题能尽早暴露。
3.4 后过滤:等所有计算都完成后再拍板
计算列跑完后,我要做的核心筛选就是基于net_amount来过滤。先临时加一个后过滤条件看看行数:
net_amount >= 500跑完之后我发现,符合这个条件的记录有 18 万行。但业务需求还要求“订单数 >= 3”,这个条件是针对同一个客户维度来统计的,在一个行级别的 Prepare Recipe 里没法直接做——因为每行代表的是一个订单,不是客户。所以我需要把数据先按客户聚合,再判断订单数。
这里是实操中一个重要的分岔口:在 Prepare Recipe 里做完行级计算后,应该接一个 Group Recipe 来做客户维度的聚合。具体步骤:
- Prepare Recipe 输出包含
customer_id、net_amount、订单数(可以用一个恒等计数列,或者在 Group 里直接 count)。 - 新建 Group Recipe,Group by
customer_id。 - 聚合指标:
total_net_amount = SUM(net_amount)order_count = COUNT(order_id)avg_discount = AVG(discount)
- 在 Group Recipe 的后过滤里写:
total_net_amount >= 500 && order_count >= 3- 输出高价值客户列表,再把这个列表 Join 回原始的订单明细,拿到这些客户的完整订单记录。
这个流程的好处是:每一步都只做一件事,边界清晰,出问题的时候很容易定位。而如果你试图在一个 Recipe 里把所有逻辑都做完,往往会陷入“这个过滤条件到底是在哪个阶段生效”的混乱中。
3.5 完整流程的 Recipe 串联
我这里用一个简单的图示来描述一下 Recipe 的串联关系(跟 DSS 界面的实际流向一致):
原始数据集 → Prepare Recipe(预过滤状态与 email → 计算 gross_amount → 计算 net_amount → 计算 customer_status → 后过滤 net_amount >= 0)→ Group Recipe(按 customer_id 聚合 → 计算 total_net_amount、order_count → 后过滤 high-value 条件)→ Join Recipe(拿高价值客户列表关联回订单明细)→ 最终数据集
这个串联方式我实测下来非常稳。它不仅满足了业务需求,而且中途任何一步的结果都可以单独查看、验证,比一个巨大的 Recipe 硬算到底要容易排查得多。
注意:这里需要强调一下,在上述第二个 Recipe(Group Recipe)里的后过滤,用到的
total_net_amount和order_count是在同一个 Recipe 里由聚合计算产生的字段——这正是后过滤最擅长的场景。预过滤做不到这一点,因为在聚合之前根本没有这两个字段。
4. 常见问题与排查技巧实录
在这个部分,我把自己平时被问得最多、以及自己踩过的坑整理成一份速查表,每一个问题都对应的有排查思路和解决办法。
4.1 为什么我的过滤条件一跑就报错?
最常见的原因是字段类型不匹配。比如unit_price在源表里是字符串类型,你直接写unit_price >= 100,DSS 不会像 SQL 那样帮你隐式转换,而是直接报类型比较错误。
解决办法:先看字段类型,如果是 string 类型且内容确实是数字,先用parseDouble(unit_price)转成 double 再比较:
parseDouble(unit_price) >= 100又或者,如果你那个字段的值里混着货币符号或空格,比如"$100.00",直接用parseDouble会失败,需要先清洗。我在实操中用得比较多的写法是:
parseDouble(trim(replaceAll(unit_price, '$', ''))) >= 1004.2 为什么我写了计算列,但结果全部是 null?
这个问题的原因大概率是数据类型不匹配,或者函数名写错。在 DSS 的 Formula 语言里,字符串拼接用的是+而不是concat();字符串取长度用的是len()而不是length();判断是否包含用的是contains()而不是includes()。这些细节跟很多编程语言的习惯不一样,很容易写错。
另一个常见原因是你要引用的字段名字里包含了特殊字符,比如空格、中划线。DSS 在表达式里引用字段名,需要用反引号或者方括号包裹。比如字段名是unit price,你应该写:
`unit price` * quantity如果字段名里带有中划线(在 DSS 内部生成的新列含-很常见),一定要用反引号包裹,否则表达式的减法语义会被误解。
排查方法是:在计算列编辑器里输入字段名的时候,看编辑器是否自动弹出字段名提示。如果没有弹出,说明这个字段名还没被正确识别,检查一下拼写和特殊字符。
4.3 预过滤和后过滤的筛选结果对不上?
很多人发现自己把相同的条件从预过滤挪到后过滤,输出行数却不一样。这是正常的,因为两个阶段的执行位置不同。预过滤发生在所有计算之前,所以它的输入是原始数据;后过滤发生在所有计算之后,所以它的输入包含了计算列的结果,而计算列本身可能会改变行的数量吗?不会改变数量,但计算列可能计算出 null 值,如果你后过滤里有类似column >= 0的条件,null 值会被过滤掉,导致行数变少。
举一个具体的例子:我在预过滤里写refund_amount >= 0,因为我想排除退款为负值的异常数据。但计算结果出来后,我发现有些记录 net_amount 是负数——因为 discount 比 gross_amount 还大。然后在后过滤我写net_amount >= 0,这样就把那些“打折打到亏本”的订单也排除了,行数自然比预过滤后还要少。这不是 bug,是业务逻辑的叠加。
排查技巧:当你发现行数对不上的时候,不要慌,先在后过滤前加一个临时步骤,把当前的行数打出来,再逐步加后过滤条件,看是哪一步筛掉的。这个“二分定位法”在 DSS 里很好用。
4.4 如何在不改变 Recipe 结构的情况下查看中间数据?
DSS 有一个很方便的辅助功能:你可以临时禁用某个 Recipe 输出的下游依赖,或者直接在 Recipe 结果面板里查看当前步骤的中间数据。在 Prepare Recipe 里,每一步的右侧都有该步执行后的数据预览。很多人没注意到的是,你可以在“步”级别点击右键,选择 disable,这样 Recipe 会临时跳过这一步运行,非常方便做对比排查。
另外,在 Recipe 输出面板的顶部有个“Add new step”和“Filter”快捷入口,你可以快速加一个临时的后过滤来看看数据分布,确认之后再决定最终要不要保留。这个习惯能省掉很多事后的返工。
4.5 性能问题:Recipe 越跑越慢,怎么优化?
在数据量很大的场景下,预过滤是性价比最高的优化手段。少读了数据,后面每一步都快。其次,计算列里的函数也有性能差异——用简单的四则运算比调用复杂的文本解析快得多。如果某个计算列只是用来筛选,用完后其实可以只在输出时保留必要的列,不需要把中间列全部输出到下游数据集,这样可以减少后面 Recipe 的 IO 压力。
我有一次跑一个包含 5000 万行日志数据的 Recipe,用户在每个计算列里都调用了parseDate把字符串时间转成时间戳,结果跑了 40 分钟没跑完。后来我把时间解析提前到数据导入时的数据类型定义阶段,改成在 Dataset 的 schema 层面就把该列定义为 timestamp,结果整个 Recipe 从 40 分钟压缩到了 6 分钟。这个经验告诉我:能在大阶段(比如数据集 schema)解决的转换,就不要放到小阶段(Recipe 计算列)里做。提前在源头把数据类型定义好,比在每一步里去兼容各种脏数据要高效得多。
4.6 后过滤里能不能用多个条件混合?
完全可以,逻辑跟预过滤一样。DSS 的过滤表达式支持&&(AND)、||(OR)、!(NOT)以及小括号控制优先级。
给一个综合的例子:
(status == 'closed' || status == 'pending') && total_net_amount >= 500 && !(customer_id in ('C001', 'C002'))其中in操作符用于判断字段值是否在给定集合内,非常实用。注意括号的使用,如果条件太多,建议分行写,保持可读性。
5. 案例实战:完整 Recipe 的配置过程
为了让大家看得更具体,我把第 3 节中的完整流程细化成一份可以直接照着点击的配置清单。
5.1 步骤一:创建 Prepare Recipe
- 选中原始订单数据集,点击右侧的“Prepare”按钮,创建 Prepare Recipe。
- 在 Step 1(原始数据)上点击加号,选择“Filter”,添加预过滤条件:
- 高级模式中输入:
status != 'cancelled' && isNotNull(email)
- 高级模式中输入:
- 继续在 Filters 下方添加“Formula”步骤(计算列)。
- 输出列名填
gross_amount - 公式填:
quantity * unit_price
- 输出列名填
- 再添加一个“Formula”步骤。
- 输出列名填
net_amount - 公式填:
gross_amount - discount - refund_amount
- 输出列名填
- 再添加一个“Formula”步骤。
- 输出列名填
customer_status - 公式填:
if(net_amount >= 500, 'high_value', if(net_amount >= 100, 'medium_value', 'low_value'))
- 输出列名填
- 切换到 Recipe 输出面板,在 Post-filter 区域添加条件:
net_amount >= 0 - 点击 Run,保存输出数据集。
这个输出的数据集里每个订单行都带上了净金额和客户价值标签,完全可以作为后续分析的基础宽表。
5.2 步骤二:创建 Group Recipe 做客户聚合
- 在刚才输出的数据集上,选择“Group”按钮。
- Group by 选择
customer_id和customer_status。 - 新增聚合列:
total_net_amount,聚合方式选SUM,来源选net_amountorder_count,聚合方式选COUNT,来源选order_idavg_quantity,聚合方式选AVERAGE,来源选quantity
- 在 Group Recipe 的输出面板中,添加后过滤条件:
total_net_amount >= 500 && order_count >= 3
- Run,输出高价值客户聚合表。
5.3 步骤三:Join 回去拿完整订单明细
- 在聚合表上新建一个 Join Recipe。
- 右数据集选择原始订单明细。
- Join 键选择
customer_id。 - 输出中保留原始订单的所有字段,加上聚合表的
total_net_amount和customer_status。 - Run,得到最终数据集。
这样一套流程跑下来,你的分析表里每一行都是净消费达标、订单量达标的高价值客户的每一笔订单,并且还带了客户的总消费额和订单数。后续做 RFM 分析、客户分层、流失预警,这张表都能直接打底。
6. 常见问题速查表
| 问题 | 原因 | 解决办法 |
|---|---|---|
| 过滤条件报错 | 字段类型与比较值不匹配 | 先用parseDouble()、parseDate()转类型再比较 |
| 计算列结果全为 null | 函数名写错、字段名含特殊字符 | 检查字段名、确认函数写法、用反引号包裹特殊名字段 |
| 预过滤行数和后过滤行数不一致 | 两个阶段输入范围不同 | 明确每个阶段基于哪些字段、哪些行在做判断 |
Formula 里写字段 == null无效 | DSS 的判空要用 isNull() | 改为isNull(field)或isNotNull(field) |
| 字段名含空格导致表达式报错 | 字段名需要转义 | 使用反引号包裹:`unit price` |
| 聚合 Recipe 里后过滤引用新聚合列失败 | 聚合字段尚未创建 | 确认聚合列已经在 output 中定义,且拼写正确 |
| 性能越来越慢 | 计算列里做了过多复杂解析 | 尽量在 Dataset schema 阶段定义好类型,避免在 Formula 里反复 parseDate、parseDouble |
这张表基本覆盖了我日常被问到的高频问题。当然,DSS 的版本迭代很快,某些界面的名称和位置可能略有不同,但核心的执行逻辑和函数语义是相对稳定的。你在用的时候,如果发现界面跟我描述的有差异,优先观察面板上的字段类型和执行顺序提示,思路对了就不会走偏。
7. 我的一些实操心得
最后再分享几个实战中沉淀下来的经验,这些都不太会写在官方文档里,但确实能帮你省不少事。
第一,养成“小步快跑”的习惯。很多人喜欢把 Recipe 写到一半再运行,结果一出错就要从头排查。我更建议大家每写完一个关键步骤就点一次 Run,看看这个步骤的输出是否符合预期。损失几分钟的运行时间,换来的是调试时候的大把节省,非常划算。
第二,在 Recipe 里给计算列起名字的时候,一定要用“业务可读 + 技术规范”并重的命名方式。比如net_amount比col4好一万倍。因为你后过滤、Join 的时候都要引用这些名字,名字混乱会让你自己也看不清。我见过有的人算了几列都是col1、col2,结果后过滤条件写出来是一长串数字字母组合,根本没法检查逻辑对不对。
第三,不要迷信一步到位的“大长公式”。DSS 的计算列支持链式引用,你可以把复杂的逻辑拆成多个简单步骤,每步都能验证结果。这比一次性写一个四层嵌套的if要可靠得多。在团队协作中,步骤分的越细,别人 review 你的 Recipe 的时候也越容易看懂。
第四,如果数据量大,一定要注意输出列的数量。很多人做 Recipe 的时候,原始表有多少列就输出多少列,导致下游数据集体积膨胀好几倍。在做完所有计算以后,可以在输出面板里把不必要的列删掉,只保留后续需要的字段。这个习惯对整体性能的提升非常可观,尤其在数据管道有多个 Recipe 串联的时候。
第五,善用样本模式。在 Recipe 开发阶段,可以把运行模式调成“Sample”,先跑一小部分数据验证逻辑。等逻辑没问题了,再切回全量运行。这样既保证了正确性,又不会因为全量数据运行时间太长而影响开发效率。
我在实际使用中发现,真正把 Pre-filter、Post-filter、Computed columns 用熟练之后,写 Recipe 的感觉会变得非常顺畅。你不再会被一堆条件绕晕,而是清楚地知道每一层在干什么、为什么在这里、数据流经过它之后变成了什么样子。这套思维方式才是 Visual Recipe 能带给你的最大价值——不只是点鼠标,而是对数据加工流程本身有清晰的掌控感。
如果你是刚接触 Dataiku DSS,我特别建议你现在就打开一个自己的数据集,把这三个功能挨个试一遍。先不追求复杂的业务逻辑,就单纯感受一下预过滤、计算列、后过滤的执行顺序和相互影响。这个基本功打好了,后面处理再多再复杂的数据场景,你都不会慌。