Macro全文搜索管道深度解析:从Block到OpenSearch的索引与检索
2026/9/16 15:51:30 网站建设 项目流程

Macro全文搜索管道深度解析:从Block到OpenSearch的索引与检索

【免费下载链接】macroMacro is a unified workspace for teams: email, chat, docs, tasks, agents, calls, and CRM — @-linked together with shared AI memory.项目地址: https://gitcode.com/GitHub_Trending/macro3/macro

Macro 是一款集邮箱、聊天、文档、任务、通话和 CRM 于一体的团队工作区,而它"50ms 内搜到一切"的全文搜索能力正是这套体验的核心。本文带你拆解 Macro 的搜索管道:每一条数据变化如何被索引进OpenSearch,以及搜索框如何一次检索邮件、文档、频道消息、通话纪要等所有类型的内容。整条管道可以概括为两句话:事件驱动写入索引,统一入口完成检索

一、什么是 Block?全文搜索的统一起点 🧱

在 Macro 中,一切都是一个 Block(块):文档(md)、邮件、频道消息、Agent 会话、任务(project)、通话记录、CRM 公司……每种内容都被抽象成同一种数据结构,通过 @mention 互相引用。

这一设计对搜索的意义非常直接:一个索引就能覆盖所有类型,不需要为邮件、文档、聊天各建一套搜索。

块与块的引用、预览机制详见官方文档 blocks.mdx。

二、索引管道:把 Block 的变化推进 OpenSearch 🔍

1. 事件驱动的实时索引

负责"写入"的是 services/search_processing_service/(下称 SPS)。它订阅Kafka主题(如通话生命周期的macro.calls、Agent 会话的macro.agent_session_lifecycle)以及遗留的 SQS 队列,监听各实体数据的增删改事件。

这里有一个关键设计:Kafka 事件只是"失效提示",不是数据本身。每收到一条事件,SPS 都会回读主数据库中的最新状态,然后对整个文档做一次全量覆盖式 upsert(通话、Agent 会话等场景均是如此)。好处是:

  • 重复投递天然安全(upsert 幂等)
  • 改名、删除等变更最终收敛到当前持久化状态
  • 删除操作则是幂等的 delete-by-query

架构与事件映射表的完整说明见 search_processing_service/README.md。

2. 文本提取:先让文件"可被搜索"

PDF、DOCX、Markdown 等二进制或带格式内容不能直接进索引。services/document_text_extractor/ 服务负责把文件解析成纯文本(并保留引用位置),供后续索引使用。SPS 内部同样内置了 parsers/(docx、markdown、pdf)解析器,保证索引内容与文档实际内容一致。

3. 回填与索引修复:索引"丢了"怎么办?

每个可索引实体都有一个内部回填接口,例如POST /internal/backfill/callsPOST /internal/backfill/emails,返回job_id后可轮询进度。空请求体即重灌全量,也可以只传指定 ID 修复单条记录。索引的映射(schema)统一由 create_indices.ts 管理,部署新映射前会先重建对应索引,避免旧文档残留。

三、检索管道:搜索框背后的 50ms ⚡

1. 统一入口:一个接口搜所有类型

负责"读取"的是 crates/search_service/。它对外只暴露一个统一搜索接口(POST /search),调用方可以按名称或正文检索,并可选择是否包含 CRM 结果;服务端再按实体类型(邮件、文档、频道、通话、Agent 会话……)拆分结果,并并行完成权限校验与结果富化。入口实现在 unified.rs。

2. 查询构建与高亮

crates/opensearch_client/ 把搜索参数翻译成 OpenSearch 查询 JSON,例如 unified.rs 中注入 1000 字符的高亮片段长度,并剔除不必要的正文回传以压缩响应体积。更底层的 DSL 拼装(bool 查询、多字段匹配、游标分页)由 crates/opensearch_query_builder/ 完成。

3. 权限过滤与产品体验

每条结果都会按当前用户的访问权限过滤(CRM 更是按需换取"能力凭证",无权限则返回空切片而非报错)。产品层面,按/打开搜索、cmd+k按名称查找、用标签的 Any/All 匹配模式收窄结果、再叠加 @某人 过滤——这些体验背后的实现细节见 search.mdx。

四、值得借鉴的三个设计 ⭐

  1. 事件只是提示,数据回读主库:索引永远收敛于数据库的最新状态,重复消费无害,排障也更简单。
  2. 读写彻底分离:写入由 SPS 独占,读取由 search_service 独占,两边都可以独立扩缩容。
  3. 单一索引 + 单一入口:类型过滤下沉到查询构建层,新增一种可搜实体只需加一个查询构建器,前端零改动。

五、从哪些文件开始阅读 📚

模块路径
索引服务(Kafka 消费、回填)services/search_processing_service/
文本提取(PDF/DOCX/MD)services/document_text_extractor/
统一搜索 APIcrates/search_service/
OpenSearch 查询客户端crates/opensearch_client/
查询 DSL 构建器crates/opensearch_query_builder/
索引映射定义infra/stacks/opensearch/helpers/scripts/create_indices.ts
产品文档(搜索/Block)apps/docs/product/search.mdx · apps/docs/concepts/blocks.mdx

总结:Macro 的全文搜索并不神秘——"Block 统一数据模型 + 事件驱动幂等索引 + OpenSearch 单索引统一检索"三者组合,才换来了在邮件、文档、通话、Agent 会话之间"一框搜遍、50ms 出结果"的体验。如果你想在自己的产品里复刻类似能力,不妨直接从 SPS 的事件消费与回填接口这两个模块读起。

【免费下载链接】macroMacro is a unified workspace for teams: email, chat, docs, tasks, agents, calls, and CRM — @-linked together with shared AI memory.项目地址: https://gitcode.com/GitHub_Trending/macro3/macro

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询