news 2026/8/25 6:00:43

Spring AI 11 · 元数据过滤 FilterExpression

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring AI 11 · 元数据过滤 FilterExpression

11 · 元数据过滤 FilterExpression

🎯 学完能做什么:用字符串表达式和 FilterExpressionBuilder 两种方式,按 metadata 精确圈定检索范围,实现多租户、分类、时间过滤。
⏱️ 预计耗时:40 分钟(含动手)
🔗 依赖前置:第 09、10 章 + pgvector 文档14(带过滤的向量检索)
🧩 难度:🟡

一句话:向量检索负责「找最像的」,元数据过滤负责「限定在哪些里面找」;两者结合才能做出多租户、分权限、按分类的生产级检索。

1. 为什么需要过滤

只靠相似度会检索到「全库最像的」,但业务上你往往只想在特定范围内找:

只查 租户 1001 的资料 只查 分类=售后 的资料 只查 2025 年之后更新的资料

这些「范围」信息就存在灌库时写的metadata(第 09 章)里,过滤就是对 metadata 下条件。

2. 方式一:字符串表达式(直观)

List<Document>hits=vectorStore.similaritySearch(SearchRequest.builder().query("退货政策").topK(3).filterExpression("category == '售后' && tenantId == '1001'").build());

支持的运算符:

运算符含义示例
==!=等于 / 不等于category == '售后'
>>=<<=比较year >= 2025
innin在/不在集合category in ['售后','物流']
&&||与 / 或a == 1 && b == 2
NOT取反NOT (status == 'draft')

3. 方式二:FilterExpressionBuilder(类型安全)

代码里动态拼条件时更安全、不易写错:

FilterExpressionBuilderb=newFilterExpressionBuilder();Filter.Expressionexpr=b.and(b.eq("tenantId","1001"),b.in("category","售后","物流")).build();List<Document>hits=vectorStore.similaritySearch(SearchRequest.builder().query("退货").topK(3).filterExpression(expr).build());

常用构建方法:eq / ne / gt / gte / lt / lte / in / nin / and / or / not,与字符串运算符一一对应。

4. 典型场景

多租户隔离(SaaS 必备)

// 每个请求都强制带上当前租户,避免串数据StringtenantId=currentTenant();b.eq("tenantId",tenantId).build();

🔐 安全要点:多租户过滤应在服务端强制注入,绝不能让前端传、也不能漏——否则会跨租户泄露数据。

按分类 + 时间

b.and(b.eq("category","公告"),b.gte("year",2025)).build();

动态拼接(有就加,没有不加)

FilterExpressionBuilderb=newFilterExpressionBuilder();List<Filter.Expression>parts=newArrayList<>();parts.add(b.eq("tenantId",tenantId).build());if(category!=null)parts.add(b.eq("category",category).build());// 用 and 逐个合并 parts ...

5. 过滤 + 相似度的执行关系

similaritySearch: 1) 先按 filterExpression 圈定候选(metadata 命中的行) 2) 在候选里按向量相似度排序,取 topK / 过阈值

⚠️ 性能提醒:过滤条件很「窄」(命中极少)时,纯向量索引可能出现召回不足。这在 pgvector 文档21、22(带过滤检索的召回塌陷、迭代扫描)有系统讲解,生产必读。

6. 让过滤生效的前提:metadata 要灌对

过滤能不能用,取决于灌库时有没有写对应字段(回顾第 09 章):

// 灌库时写入可过滤字段vectorStore.add(List.of(newDocument(content,Map.of("tenantId","1001","category","售后","year",2026))));

🔑 「先想清楚要按什么筛,再决定 metadata 放什么」——过滤能力是灌库阶段就注定的。

7. 常见坑

现象原因
过滤后结果为空metadata 里根本没这个字段/值;或类型不符(数字写成字符串)
过滤没生效字段名拼错,或值大小写/类型不匹配
窄过滤召回很差命中太少 + ANN 索引特性,见 pgvector 21/22
跨租户看到别人数据服务端没强制注入租户过滤

8. 一句话总结

元数据过滤用filterExpression(字符串或 Builder),在相似检索前圈定范围,是多租户、分类、时间等生产场景的基础;能不能过滤取决于灌库时 metadata 写得对不对。


🎉第二阶段完成!你现在掌握了:生成向量、配置 pgvector、写入(含幂等)、相似检索、元数据过滤——RAG 的数据层已经打通。

➡️ 下一阶段(第 12–15 章)进入文档处理 ETL:把真实的 PDF/Markdown 读进来、分块、富化 metadata、批量灌库,让知识库有真正的内容。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/25 6:00:04

Spring Boot在线问诊系统设计:多语言、弱网与医疗协同的实战挑战

最近在梳理过往项目时&#xff0c;翻到了一个几年前参与设计的“少数民族地区在线问诊系统”。当时&#xff0c;团队接到这个需求&#xff0c;第一反应是&#xff1a;这不就是一个标准的在线问诊平台吗&#xff1f;无非是用户注册、医生入驻、图文/视频问诊、开方购药。然而&am…

作者头像 李华
网站建设 2026/8/25 5:59:42

Godot 4 实战:从零构建像素风农场模拟游戏核心系统

最近在尝试用 Godot 4 复刻《星露谷物语》的核心玩法时&#xff0c;发现网上资料要么是零散的片段&#xff0c;要么停留在 Godot 3 版本&#xff0c;对于想系统学习 2D 像素风农场模拟游戏开发的开发者来说&#xff0c;很难找到一个从零到一的完整闭环教程。本文将基于 Godot 4…

作者头像 李华
网站建设 2026/8/25 5:59:17

LangChain Agent集成MCP协议:实现AI工具即插即用的标准化方案

如果你正在开发AI Agent&#xff0c;可能已经遇到了这样的瓶颈&#xff1a;Agent能理解你的指令&#xff0c;也能调用几个基础工具&#xff0c;但一旦需要连接数据库、读取文件、调用第三方API&#xff0c;就得写大量胶水代码。更头疼的是&#xff0c;每个新工具都得重新集成、…

作者头像 李华
网站建设 2026/8/25 5:55:48

拼多多算法团队招聘:推荐、搜索与广告算法核心技术解析

1. 项目背景与团队定位拼多多作为国内电商领域的头部平台&#xff0c;其核心算法团队承载着平台最关键的智能决策系统研发工作。这个团队直接负责商品推荐、搜索排序、广告投放、用户画像等核心业务场景的算法优化&#xff0c;日均处理超百亿级数据请求。2026届春招和2027届实习…

作者头像 李华
网站建设 2026/8/25 5:54:23

MLLM引导语义校正:用大模型优化AI视频生成逻辑

最近在尝试用AI生成视频时&#xff0c;你是不是也遇到过这样的困惑&#xff1a;明明输入的文本描述是“一只猫在草地上追逐蝴蝶”&#xff0c;但生成的视频里&#xff0c;猫的动作僵硬&#xff0c;背景的草地和蝴蝶也常常“各玩各的”&#xff0c;画面元素之间缺乏逻辑关联&…

作者头像 李华
网站建设 2026/8/25 5:54:21

2026年采购智能鞋头后跟定型机,选哪家工厂性价比更高?

最近不少鞋厂老板都在为明年的设备采购做规划&#xff1a;国内扩产建新厂要算产能匹配&#xff0c;越南、柬埔寨的外资厂要考虑本地售后&#xff0c;大家问得最多的就是“智能鞋头后跟定型机选哪家不踩坑&#xff1f;” 毕竟定型机的温控精度、运行稳定性直接决定鞋款成型合格率…

作者头像 李华