ADF(Azure Data Factory)里的Filter活动,是我在做数据管道时用得最频繁的控制流活动之一。这个活动在官方文档里就几页纸,功能简单到只有两个参数——Items和Condition,但它在实际项目里解决的却是最磨人的问题:面对一堆文件,怎么按条件只处理该处理的那些。我见过太多管道,Get Metadata一拿到文件列表就直接全量塞给ForEach,结果要么把历史文件重复处理一遍,要么把不该动的文件也搬了一遍。其实就是少了Filter这一层过滤。
这篇就围绕ADF中Filter活动条件过滤文件展开,把它的工作原理、实战场景、完整配置步骤和常见坑位一次讲清楚。适合正在用ADF做文件迁移、增量同步、批处理管道的开发者和数据工程师,也适合准备入门ADF控制流的新手。看完你可以直接照着搭建一条“先过滤、再处理”的标准管道。
1. ADF与Filter活动的基础认知
1.1 ADF在数据管道中的定位
ADF是微软Azure上的云数据集成服务,通俗点说,它是一个可视化编排ETL/ELT流程的平台。你不需要自己写一堆调度脚本,用鼠标拖几个活动,再配上表达式,就能把“从A处拉数据、经过清洗、写到B处”整套流程跑起来。它擅长的事情分两类:一类是数据移动,把数据从各种各样的源搬到目标,比如本地文件、数据库、API、云存储;另一类是流程编排,把一系列操作按顺序、按条件执行,支持循环、分支、等待、失败处理这些控制逻辑。
Filter活动归属于第二类,也就是控制流活动。它的作用是,在一个输入数组里,根据你给定的条件表达式,筛选出符合条件的子集,输出给下一个活动。你可以把它想象成水管中间加了一个带筛网的接头——水流过去的时候,只有满足要求的颗粒才通过,其他全拦在外面。ADF管道里常见的数据流是:Get Metadata拿到文件列表 → Filter筛选列表 → ForEach遍历 → Copy拷贝。Filter就是中间那道闸门,决定了后面ForEach会处理哪些文件。
很多人会忽略Filter的价值,觉得直接写个通配符路径也能搞定筛选。但在复杂的业务场景里,文件筛选往往不是“一个文件名前缀”能解决的,它可能是“最近24小时修改过、且非空、且名字匹配某个模式、且不是临时文件”的组合条件。这种时候,通配符就力不从心了,而Filter活动正是为这种场景设计的。
1.2 Filter活动的核心参数与工作方式
配置Filter活动时,核心就看两个属性。
第一个是Items。这个是要过滤的数组,最常见的情况是上游Get Metadata活动的输出,也可以是一个手动指定的数组常量,或者来自管道参数。第二个是Condition。这个是过滤条件,一个布尔表达式,返回true的项会被保留。表达式里通过item()来引用当前遍历到的数组元素。
举个例子,你用Get Metadata拿到了一个容器下所有子项的列表,结构大概是JSON数组,每一项有name、type、lastModified、size等字段。Filter的Condition里就可以写:
json复制@greater(item().lastModified, '2024-01-01T00:00:00Z')
这个表达式的意思是,只保留最后修改时间在2024年1月1日之后的文件。ADF运行时,Filter会遍历Items中的每个元素,逐个代入Condition判断,为true的进入输出结果,为false的直接丢弃。
这个“逐个遍历”的机制很关键,它意味着Filter适合作为一条管道的“中间件”,而不是终点。它的输出可以直接进入ForEach循环,也可以再被其他表达式引用。你可以在Filter之后接一个Set Variable活动,把过滤结果的数量记录下来,方便后续做监控和日志。
1.3 不同技术栈里的Filter对照
可能有读者会问,我明明会JavaScript的filter、会Elasticsearch的filter、会Spring Security的Filter,为什么还要学ADF这个Filter?其实它们思想相通,但作用域完全不同。
| 技术栈 | 过滤对象 | 核心语义 | 典型用途 |
|---|---|---|---|
| ADF Filter活动 | 管道中的数据数组 | 按表达式保留元素 | 文件列表筛选后进入下游活动 |
| JavaScript Array.filter | 内存中的对象数组 | 回调函数返回true保留 | 前端数据局部筛选 |
| Elasticsearch filter context | 文档集合 | 是否匹配,不参与相关度评分 | 精确过滤,结果可缓存 |
| Spring Security Filter | HTTP请求 | 链式拦截,逐层横切 | 鉴权、日志、编码等前置处理 |
JavaScript的Array.prototype.filter是纯内存操作,一个回调函数遍历数组,返回true就留下,比如arr.filter(x => x.age > 18)。它解决的是前端数据处理问题。Elasticsearch里的filter context则是在查询层面做文章,query context会计算相关度评分,而filter context只回答“是否匹配”,不参与评分,所以通常更快、更容易利用缓存。ES里must和should默认参与评分,如果你不需要评分,把它们放进filter子句,语义更清晰,性能也更好。Spring Security的Filter链是基于Servlet规范的责任链模式,请求按顺序经过
