你的 AI 分析师能保守秘密吗?桥水与 turbopuffer 谈权限检索
原题Can Your AI Analyst Keep a Secret? - Aaron Linsky, Bridgewater & Nikhil Benesch, turbopuffer
看前速览
桥水与 turbopuffer 解释,感知权限的聚类向量搜索,如何避开简单前置过滤和后置过滤带来的召回率与延迟问题。
文档访问必须遵循查询用户的权限。
内部研究资料不能按公开网页语料处理。信息进入分析师系统前,每次检索都必须反映用户与群组权限。
过滤顺序带来不同的失效方式。
先搜索后过滤可能严重损害召回率,先过滤后搜索则可能被迫扫描庞大的可访问集合。两种简单策略都无法同时满足要求。
将权限条件与向量簇结合。
所述索引先找出含有授权文档的簇,再搜索最近的合格簇,从而将顺序扫描限制在小得多的集合中。
存储成本设计与查询规划相互配合。
冷数据留在对象存储中,活跃数据则进入缓存。所报告的延迟属于文中生产工作负载,并非普遍适用的基准成绩。
权限只是隔离需求中的一层。
嵌套群组成员关系仍是难题。区域部署、私有网络与客户控制的密钥,解决的是文档权限之外的其他限制。
完整摘要
Aaron Linsky 说明,桥水的 AI 分析师需要带权限的研究资料库,不能只依赖公开网络搜索。Vault 汇集外部研究、内部文章与会议记录,访问权限随文档、用户和群组而变化。Nikhil Benesch 解释,在这一规模下,暴力搜索成本过高,普通近邻索引也不够用。先搜索再过滤,会不断丢弃最近的结果,最终剩下的可访问文档过少;先过滤再搜索,则可能仍需扫描数千万份允许访问的文档。他们的原生过滤方案结合过滤索引与聚类向量索引:先找出至少包含一份授权文档的簇,再检索距离较近的合格簇,最后评估簇内文档。权限因此成为查询规划的一部分,而非事后补上的处理。讲者还介绍对象存储的成本优势、热数据缓存,并报告 Vault 工作负载下约 120 毫秒的 P90 搜索延迟。他们区分了文档级权限与区域存储、客户控制的加密及私有网络等更广泛的隔离需求。架构机制解释充分,但延迟为厂商报告的结果,字幕对向量总数也存在不一致表述。
章节
文字稿
简要说明Brief Description
Aaron Linsky 和 Nikhil Benesch 解释了 Bridgewater 如何检索其受权限控制的研究资料库、为什么预过滤和后过滤在规模扩大时都会失效,以及集群原生过滤如何将权限控制与快速向量搜索结合起来。Aaron Linsky and Nikhil Benesch explain how Bridgewater searches its permissioned research collection, why pre-filtering and post-filtering each fail at scale, and how clustered native filtering combines permissions with fast vector search.
目录Table of Contents
- 引言:为什么权限对 AI 分析师很重要Intro: why permissions matter for AI analysts
- 桥水的研究流程Bridgewater's research process
- 保险库:1 亿份文档,权限众多The Vault: 100M documents, many permissions
- 权限建模,以及它出问题的地方Modeling permissions, and where it broke
- 什么是 turbopufferWhat turbopuffer is
- 粗略估算:为什么暴力破解在规模扩大时会失败Napkin math: why brute force fails at scale
- 向量索引的工作原理How vector indexes work
- 权限会破坏索引Permissions break the index
- 后过滤与预过滤Post-filtering vs pre-filtering
- 原生筛选:两全其美Native filtering: the best of both
- 结果:在 1 亿份文档中耗时 120 毫秒Results: 120ms across 100M documents
- 实践中编写写入权限过滤器Writing permission filters in practice
- 超越权限:为隔离而生的搜索Beyond permissions: isolation-native search
简介:为什么权限对 AI 分析师至关重要Intro: why permissions matter for AI analysts
Nikhil Benesch:好的,大家好。感谢各位到场。我是 Nikhil Benesch,turbopuffer 的首席技术官。Nikhil Benesch: All right. Hello, everyone. Thank you all for coming. I'm Nikhil Benesch, CTO of turbopuffer.
Aaron Linsky:我是 Aaron Linsky,Bridgewater Associates 的产品工程负责人。Aaron Linsky: And I'm Aaron Linsky, the head of product engineering at Bridgewater Associates.
Nikhil Benesch:今天我们来和大家聊聊,如何构建一个能够保守秘密的 AI 分析师。我会进一步解释这意味着什么。现在,这是构建 AI 分析师的一种极度简化的示意图,但它旨在体现权限方面的一个重要维度。Nikhil Benesch: And we're here to talk to you today about how you build an AI analyst that can keep a secret. And I'll explain a bit more about what that means. Here. Now, this is a very oversimplified view of how you would go about building an AI analyst, but it is meant to capture an important dimension around permissions.
所以,在这张图中,你是与这个 AI 智能体交互的用户。你先提出一个问题,比如:“为什么过去一个月代币价格下降了这么多?”然后将这个问题输入大语言模型(LLM),它会开始思考这个问题,进行调查和研究。在调查过程中,它会搜索事实来佐证信息,并引导调查方向。其中一些事实可能来自公开网络,但另一些可能来自你所在组织的私有文档。从某种意义上说,公开网络比组织内部的私有信息更容易搜索。So, in this diagram, you're user interacting with this AI agent, you start with a question, maybe something like, "Why have token prices come down so much in the last month?" And you feed that question into an LLM, which will begin thinking about that question, investigating, researching. And as it does that investigation, it's going to search for facts to ground its information, to lead its investigation. Some of those facts might come from the public web, but other facts might come from private documents in your organization. Now, the public web is on one dimension much easier to search than the information that's private to your organization.
从定义上来说,公共网络是公开的。组织中的每个人都能看到完全相同的文档。因此,这里不存在权限问题。无论是谁提出问题,任何公共网络文档都可以立即输入给 AI 分析器。By definition, the public web is public. Everyone in your organization can see exactly the same documents. So, there's no permission issue there. Every public web document can be immediately fed into the AI analyst, no matter who's asking the question.
但你所在组织内部的信息看起来截然不同。每封电子邮件、每份会议记录、每份报告都可能附带一套完全不同的权限,归属于不同的群组,甚至可能对这些文档单独分配权限。你可以在这里看到,不同的颜色反映出这个私有数据集中每份文档的权限各不相同。这是信息检索领域的经典难题,而 turbopuffer 正是我们专门为解决这个问题而设计的。But the information internal to your organization looks very different. Every email, every meeting note, every report might have a completely different set of permissions attached to it, belonging to different groups, maybe individual permissions assignments on those docs. And you can see here, we've got different colors here reflecting the fact that every document in that private data set has a different set of permissions. And this is a classically hard problem in information retrieval, and it's something we explicitly designed turbopuffer to solve.
不过在深入讨论之前,我先把话筒交给 Aaron,请他谈谈为什么这些私人信息对 Bridgewater 的 AI 分析师如此重要。But before I get into that, I'm going to hand it over to Aaron to talk about why this private information is so important to Bridgewater's AI analyst.
桥水基金的研究流程Bridgewater's research process
Aaron Linsky:太好了。谢谢。哦,这就对了。Aaron Linsky: Great. Thank you. Oh. There we go.
首先,我想先简单介绍一下 Bridgewater 是一家什么样的机构、我们做什么,然后再谈谈我们如何使用 turbopuffer,以及这方面的需求。过去 50 年来,我们 Bridgewater 一直致力于深入理解市场和经济的运作方式。随后,我们会用逻辑将这种理解系统地编码到一个系统中,并随着时间推移对其进行压力测试。你们在这里看到的,左边那张黄色法律便笺纸上的内容,就是我们 1980 年的债券系统。So, first I'm going to go talk a little bit about what who Bridgewater is, what we do, and then we get into how how we're using turbopuffer and the needs there. So, for the past 50 years, we at Bridgewater have pursued the best understanding of how markets and economies work. We then encode that systematically with logic into a system that we can then stress test over time. What you see here are on the on the left with the yellow legal pad, that is our bond system from 1980.
那是一组“如果……那么……”的语句,我们当年用它来交易债券。在接下来的几十年里,我们不断改进这一流程,从黄色法律便笺纸,到 Excel,再到后来使用 Scala 和现在的 Python,嗯,最终转向一种以人为核心的不同学习流程。这个五——我们称之为“研究循环”的流程,分为五个步骤。感知,就是观察外部世界正在发生什么。It's a set of if-then statements that we used to trade bonds back then. Over the next few decades, we've evolved that process from a yellow legal pad to Excel to eventually Scala and now Python um to a different learning process with humans at the center. This five This research circle, as what we call it, has five steps. Perception, that's seeing what's going on the outside world.
假设阶段,就是提出一些想法,思考为什么那可能是真的。调查阶段,则是通过研究来确认那件事是否属实。如果属实,我们就将其系统化并整合进我们的系统,然后将其工业化,每天运行,并据此进行交易。这就是我们的学习过程。Hypothesis, which is coming up with ideas of why that might be true. Investigation, which is the research of seeing is that thing true. If it is true, we then systematize and integrate it with our system and industrialize and run that every day and trade on that. That's been our learning process.
我在桥水已经待了大约20年了。过去20年来,我们一直以人为核心开展工作。现在,我们正朝着以机器为核心、并由机器运行这一流程的方向迈进。I've been at Bridgewater for about 20 years. That's been what we've been doing doing for 20 years with humans at the center. We're now moving towards putting machines at the center and running that process.
保险库:1 亿份文档,权限繁多The Vault: 100M documents, many permissions
为了让——你知道——无论是人还是机器,都能很好地运行,我们需要获取高质量的数据。我们既需要时间序列数据,也需要非结构化数据。我们花了几十年时间,呃,几十年时间,打造了一个出色的双时态时间宏观时间序列数据库,我们称之为 Delorean。最近,我们还在打造一个非结构化数据库,我们称之为 Vault。那么,Vault 是什么?In order for even you know, for both humans and machines, in order for that to work well, we need access to high-quality data. We need both time series data, which we spent decades uh decades creating a great bi-temporal time macro time series database, which we call Delorean. And more recently, we've been creating a unstructured database, which we call the Vault. And so, what is the Vault?
嗯,今天我们有大约 1 亿份文档,我们会对这些文档进行索引、整理和保护。我们认为,这些文档代表了最优质的第三方及其他第三方外部研究,以及我们的内部研究。我们的资料来自 135 个不同的外部来源。对法务团队和数据团队来说,这是一件大事,因为他们需要实际去协商——谈判,把这些来源引进来。而且,所有这些来源都有某种权限限制,因此在 Bridgewater 并不是所有人都能访问。当然,我们也有自己的内部非结构化数据来源。Um today, it's about 100 million documents, which we index, organize, and secure that we think represents some of the best third-party and extra third-party external research, and also our internal research. So, we've sourced with 135 different external sources, which is a huge deal for both legal and our data team to actually nego- negotiate and get them in. And all of all of those sources have um some sorts of permissions around it where it might not be open to everyone at Bridgewater. And then, of course, we also have our inter- internal sources of unstructured data.
那也包括我们自己撰写的内容、会议录音,以及内部报告。这些都会进入 Vault,然后人类投资者和我们的 AI 代理都会从 Vault 中读取内容。我这里没有展示的是,实际上它会形成一个闭环。投资者和代理会创建新的新内容,再把它放回 Vault。That's our own writing, our meeting recordings, and our internal reports, as well. And both that those all go into the Vault, and then both humans investors and our AI agents read out of the Vault. What I haven't shown here is actually it circles back. So, the investors and the agents will create new new content that goes back into the Vault.
所以,它一直在不断改进。So, it's constantly improving.
权限建模及其失效之处Modeling permissions, and where it broke
那么,这里是 Vault 中权限情况的一个非常高层次的概览。假设有一个用户,我们就称其 ID 为 user one。该用户属于 B 组和 C 组。遗憾的是,这个例子极其——非常简化。And so, here's a very high-level view of what permissions in the Vault look like. So, I have a user we'll just say their ID is user one. They're in groups B and C. This is incre- incredibly simplified, unfortunately.
嗯,我们有一组所有文档的集合,访问权限可以通过群组授予,也可以直接授予用户。然后,这里是我们实际的代码:我们创建一个查询,尝试用查询向量查找与查看者和群组相匹配的数据。从某种意义上说,这很简单。实际上,我们最初在没有使用 turbopuffer 的情况下实现这一功能时,还以为它运行得挺好。Um and there's a set of all of our documents where it could be either um uh permission to them via groups or directly. And then, here we have the actual code of us going ahead and creating a query to try to look for some data with whatever that query vector was that matches the viewers and groups. And so, this is simple in one way. And actually, when we first implemented this without turbopuffer, we thought it worked fine.
嗯,不过后来,随着我们开始往这个知识库里添加越来越多的文档,它很快就彻底崩溃了。所以我接下来做的就是寻找其他可能的服务提供商。我们找到了 turbopuffer,测试了一下,他们提供了一个解决方案,Nikhil 现在会为大家介绍。Um but then, pretty quickly, as we started to add more and more documents to the vault, it fell over um tremendously. And so, what I did then was I looked for other possible providers. We found turbopuffer, tested them out, and they had a solution which Nikhil is going to go over right now.
turbopuffer 是什么What turbopuffer is
Nikhil Benesch:太棒了。谢谢你,Aaron。我来快速介绍一下 turbopuffer。我们是一款速度极快、可扩展性极强、成本极低的搜索引擎,完全构建在对象存储之上。Nikhil Benesch: Awesome. Thank you, Aaron. Let me very quickly talk about what turbopuffer is. We are an extremely fast, extremely scalable, extremely cheap search engine built entirely on top of object storage.
这意味着我们直接将数据写入 S3、GCS 或 Azure Blob 存储,也就是你的云超大规模服务商所提供的存储。这样我们就能享受到 S3 的成本优势。默认情况下,你的数据静静地存放在 S3 的冷存储中。只有当你开始查询数据时,我们才会将其调入成本更高的存储介质,例如 SSD 或内存。And what that means is we write directly to S3 or GCS or Azure Blob storage, whatever your hyperscaler provides. And that gives us S3 economics. So, by default, your data is inert, cold on S3. Only when you start querying it do we pull it into more expensive storage mediums, like SSD or memory.
这确实非常强大,因为一旦某个查询变得热门,查询所访问的数据进入缓存,速度就会很快。但如果你没有访问某个特定的命名空间,或命名空间中的某个特定区域,那些数据就可以继续存放在对象存储中,而你为此支付的费用极低。因此,这种架构让 turbopuffer 能以很低的成本扩展到数 TB 的数据规模;在其他系统中,这样做可能要花费数千万美元,而我们通常只需十分之一的成本,就能实现与传统基于磁盘的搜索系统相当的性能——前提是数据已经进入缓存。我们支持所有类型的搜索。And this is really powerful because once a query is hot, once the data query is accessing is in the cache, it's fast. But if you're not accessing a particular namespace or a particular region of a namespace, that data can just hang out on object storage where you pay rock-bottom prices for it. So, this architecture allows turbopuffer to scale cheaply to terabytes of data, which would cost tens of millions of dollars in other systems, and we can often do it at a tenth of the cost at performance that's comparable once you get the data hot uh to what you get with traditional disk-based search systems. And we support all types of search.
我们支持关键词搜索、正则表达式搜索,还有 Aaron 之前展示的向量搜索。嗯,所以对于你如何在 turbopuffer 中搜索数据,我们并没有特别的主张。We support keyword search. We support regex search. And what Aaron was showing earlier, vector search. Um so we're really not uh opinionated about how you search your data in turbopuffer.
我们希望以通用的方式进行搜索。不过在本次演讲接下来的部分,我会重点讲向量搜索,因为深入探讨某一种特定类型的搜索会比较好。We want to do search generically. But for the rest of this talk, I'm going to focus on vector search because uh it's it's good to zoom in and go deep on one particular type of search.
粗略估算:为什么暴力破解无法扩展到大规模Napkin math: why brute force fails at scale
我们来做一点粗略估算。这是我们在 turbopuffer 很喜欢做的事。它能帮助我们立足于尽可能简单的解决方案。我们绝不想给 turbopuffer 引入没有充分理由的复杂性。Let's do a little bit of napkin math. That's something we love to do at turbopuffer. It helps us anchor in the simplest possible solution. We never want to introduce complexity to turbopuffer that's not justified.
采用复杂方案的理由之一,是你需要它来提升性能。实现搜索最简单的方式,就是把所有内容都放进一个列表里;每次有人来告诉你:“我想要匹配这个条件的查询。我想要匹配这个查询的文档。”你就检查每一条数据。保守地说,存储在 turbopuffer 中的每个文档都是 1 KB。One of the justifications for taking on complexity is if you need it for performance. The absolute simplest way to do search is to put everything in a list and every time somebody shows up saying, "I want queries that match this. I want documents that match this query." You look at every single piece of data. Let's conservatively say that every document that you store in turbopuffer is 1 kilobyte.
这已经算是非常保守的估算了。一个向量嵌入通常有 1,024 个维度。所以,如果每个维度只用一个字节,那光这部分就有 1 KB。嗯,实际上,文档通常比这更大。This is incredibly conservative. A vector embedding is often 1,024 dimensions. So if you're using just a byte per dimension, that's a kilobyte right there. Uh in practice, documents are often larger than this.
不过,为了举例,我们假设每份文档占 1 KB。即使所有数据都驻留在内存中,而且你以尽可能快的速度处理——在现代硬件上大约是每秒 20 GB——当文档数量达到 1 亿份时,也需要 5 秒。对于大多数搜索工作负载来说,这太慢了。But for the sake of example, let's say it's a kilobyte per doc. Even if you had all of that data resident in memory and you were ripping through it as fast as you possibly could, which on modern hardware is about 20 gigabytes a second. Once you get up to 100 million docs, that's going to take 5 seconds. And for most search workloads, that's way too slow.
实际情况是,大多数人希望搜索结果能在大约 100 毫秒内返回。所以这里的简单方案行不通。如果你只有 1 万份文档,那没问题,只需要半毫秒。What we see in practice is most people want their search results to be about 100 milliseconds. So the naive solution here does not work. If you've only got 10K docs, great. That's going to take half a millisecond.
turbopuffer 几乎无所不能,而且速度足够快。但当规模增长到 1000 万或 1 亿时,你就真的需要开始考虑如何表示数据,才能避免对所有数据进行处理。当然,我这里给你的是内存方面的数字,而且这只是在缓存命中的情况下。turbopuffer can do literally anything and it will be fast enough. But as you get to scale, once you're at 10 million or 100 million, you really need to start thinking about how you represent your data so that you're not crunching through all of that. And of course, I gave you the numbers for memory here. That's only if the cache is hot.
如果这些数据在 S3 上,把数据从 S3 拉取下来至少需要一分钟。因此,这种方式根本无法满足 Bridgewater 的运营规模。If that data's on S3, you're looking at a minute or more to pull that data off S3. So, this just isn't viable at the scale that Bridgewater operates.
向量索引的工作原理How vector indexes work
因此,turbopuffer 的第一步是构建向量索引。这部分我们会在后台为你处理。当你在 turbopuffer 中存储向量,并且数据量足以支持构建索引时,我们会自动在后台为你创建索引。如果你不熟悉向量嵌入,它们是在 LLM 空间中对概念进行内部数值表示的形式。So, step one in turbopuffer is to build a vector index. And this is something that we handle under the hood for you. When you store vectors in turbopuffer, we automatically build this index behind the scenes once you get enough data to justify it. Vector embeddings, if you're not familiar, are the internal numeric representation of concepts in LLM space.
我们喜欢用红鞋和栗色凉鞋这个例子。作为人类,你知道这两个概念非常相似,彼此之间的相似度远高于它们与混凝土砌块的相似度。你可能会想到形状、尺寸、质地和重量。LLM 可以将这些信息转换成这个数值向量。And we like to use this example of red shoes and maroon sandals. You as a human know that these are very similar concepts and much more similar to one another than concrete block is. And maybe you're thinking about shape and size and texture and weight. The LLM can translate that into this numeric vector.
这里,我只展示了两个维度,这样我们就可以用二维的方式来思考;但实际上,维度往往有成千上万个。1024 个维度是很常见的大小。像这样进行多维思考非常困难。所以,为了方便举例,我们就假设这里有两个维度。现在,我们其实并不知道这些维度代表什么,不过同样,你可以把它们想成大小和颜色。Here, I've only got two dimensions shown so that we can think two-dimensionally, but in practice, there's often thousands of dimension. 1024 dimensions is a very common size. Thinking multi-dimensionally like that is very hard. So, for the sake of example, we're just going to imagine that there are two dimensions here. Now, we don't actually know what those dimensions represent, but again, you can think of it as like size and color.
然后你可以把它绘制在坐标系中。比如,红色鞋子可能位于左上方,和栗色凉鞋在一起,而混凝土砌块则会位于右下方。And then you can plot that on a coordinate system. So, red shoes might be at the top left along with maroon sandals, and then concrete block is going to be down at the bottom right.
我在这里做一个极度简化的解释:一种非常实用的二维向量索引,就是把数据点绘制在图表上。然后你可以放大查看。如果你在找红鞋,那就是这张图里的 Q。你可以把它绘制到这个二维图表上,然后放大,查找它周围的向量。由于这些向量是由 LLM 创建的,彼此相近的向量代表相似的概念,也代表适合作为搜索结果返回的内容。And I'm going to simplify wildly here, but a very workable vector index in two dimensions is just to plot things on a graph. And then you can zoom in. If you're looking for red shoes, that's the Q on this diagram, you plot that on this two-dimensional graph, and you zoom in, and you look for the vectors around it. And because of the way these vectors are created by the LLM, vectors that are near each other represent similar concepts, represent good search results to return.
所以,如果我们只是做相似度搜索,那就很棒。我们在二维坐标网格中查找,找到一些附近的向量并返回它们,这样就万事大吉了。而且这为我们节省了大量时间。我们不必搜索整个向量空间。So, if we were just doing similarity search, great. We look in our two-dimensional coordinate grid, we find some nearby vectors, we return them, and life is good. And this saves us a lot of time. We don't have to search the whole vector space.
我们可以直接聚焦于与查询相关的文档。所以,前面那些粗略估算我们可以不用考虑。这里我们可能只需要查看 10,000 个向量,而且我们知道,这只需要一两毫秒。We can zoom right in to the documents that are going to be relevant to the query. So, that napkin math from earlier, we can we can ignore. We're maybe only looking at 10,000 vectors here, and we know we can do that in a millisecond or two.
权限会破坏索引Permissions break the index
问题在于,添加这些权限后,并非所有与特定查询最相关的文档都符合这些权限。你可以从这里的图表中看到,减号表示不符合权限,加号则表示符合权限。因此,向量索引无法立即为我们提供帮助。我们在 turbopuffer 投入了大量时间和精力来解决这个问题。The problem is when you add in these permissions, not all of the documents that are most relevant for a given query are going to match those permissions. And you can see in this diagram here, the minuses don't match the permissions, while the pluses do match the permissions. So, our vector index is not immediately helpful to us. And we've invested a lot of time and energy at turbopuffer into solving this problem.
后过滤与预过滤Post-filtering vs pre-filtering
直观地说,你可能会尝试采用后过滤策略。其工作方式是:查询发出后,系统找出最接近的 10,000 个向量,然后丢弃所有不匹配的向量。这种方法效果不太好,因为它无法提供你想要的结果。如果我是一个只能访问右下角那些数据的用户,并且我搜索 Q,那么我仍然希望看到从我的视角来看最接近 Q 的文档,也就是我有权查看的那些结果。Naively, you might try a post-filtering strategy. And the way that works is the query comes in, you get maybe the 10,000 closest vectors, and then you throw away all the ones that don't match. This does not work very well because it doesn't provide the results that you're looking for. If I'm the user that only has access to that data in the bottom right, and I search for Q, I still want to see the documents that were closest to Q from my perspective, that include the results that I can see.
但如果你做后置过滤,就会不断向外扩展搜索范围,最后不得不放弃,因为已经过了几秒钟,你仍然没找到任何匹配的文档,或者没找到排名前 100 的匹配文档。也许你只找到了 40 篇。这会让用户很不满意,因为他们可能知道有一篇文档提到了栗红色凉鞋,而他们搜索的是红鞋,但你的搜索结果里却没有这篇文档。所以,你的召回率会很低。But when you do post-filtering, you kind of spiral outwards, and then at some point you have to give up because it's been a couple seconds and you haven't found any docs that match, or you haven't found the top 100 docs that match. Maybe you were only able to find 40. And this makes users unhappy because they might know that a doc exists with maroon sandals, and they were searching for red shoes, and you don't turn it up. So, you have very poor recall.
那么,与其从向量索引入手,不如从过滤条件开始?turbopuffer 会为所有符合过滤条件的文档建立索引。这样,Aaron 就可以出现并说:“嘿,给我看看所有我有权访问的文档。”然后,turbopuffer 就可以扫描所有这些文档,看看哪些文档与查询向量最接近。但如果 Aaron 有权访问保险库中 1 亿份文档里的 5000 万份呢?So, instead of starting with the vector index, what if we start with the filters? turbopuffer builds an index of all of the documents that match the filters. So, Aaron can show up and say, "Hey, show me all of the documents that I have access to." And then turbopuffer can scan over all of those documents and see which of them are closest to the query vector. But what if Aaron has access to 50 million out of the 100 million documents in the vault?
现在我们又回到了原点。我们又回到了那个简单估算就能看出的问题:处理完所有这些数据需要好几秒,甚至几分钟。实际上,我们并没有使用向量索引。看这里就能发现,我们只是找出所有符合筛选条件的文档,然后依次扫描它们。Now we're back to square one. We're back in that napkin math problem where it's going to take multiple seconds, if not minutes, to get through all of that data. We're not actually using the vector index. If you look here, you can see we're just finding all the docs that match the filters and then scanning through them sequentially.
所以,这也不太好用。So, this also doesn't work very well.
原生过滤:兼得两者之长Native filtering: the best of both
要妥善解决这个问题,诀窍就是两者兼顾。turbopuffer 的向量索引会自动将相似的向量聚类。你可以看到,这里有一组相似的文档,标记为 5;另一组标记为 0,还有一组标记为 1。构建这些权限索引时,我们会说:“Aaron 可以访问簇 5 中的文档,也许还能访问簇 2 中的文档,但他无法访问簇 3 或簇 0 中的任何文档。”这样,我们就可以直接排除这些簇。And the trick to doing well on this problem is to do both. So, turbopuffer's vector index automatically clusters similar vectors. So, you can see there's a group of documents here that are similar labeled five and another group labeled zero and another group labeled one. And when we build these permissions indexes, we say, "Well, Aaron has access to documents in cluster five and maybe cluster two, but he doesn't have access to any documents in cluster three or any documents in cluster zero." So, we can just throw those clusters out.
我们完全不必考虑它们。所以,首先我们找出 Aaron 有权访问的所有簇,也就是说,他至少能访问这些簇中的一篇文档;然后搜索最近的簇,接着只在这些簇中按顺序扫描。目前在 turbopuffer 中,每个簇大约有 200 篇文档。这是我们一直在调整的参数。We don't have to consider them at all. So, first we find all of the clusters that Aaron has access to, uh i.e. he has access to at least one doc in those clusters, and then we search the closest clusters, and then we just scan sequentially inside those clusters. And in turbopuffer right now, the clusters have about 200 documents. This is something we're always tuning.
随着时间推移,我们可能会增加这个数量,以最大限度地提高吞吐量。但这种基本策略从根本上让大规模权限搜索成为可能。诀窍是将预过滤和后过滤结合起来,形成我们所说的原生过滤。Over time, we'll probably increase that number to maximize throughput. But this basic strategy fundamentally makes search at scale with permissions possible. And the trick is to combine pre- and post-filtering into what we native filtering.
结果:1 亿份文档耗时 120 毫秒Results: 120ms across 100M documents
结果如下:在 4.5 亿个向量中,这 1 亿份文档转化为 4 亿个向量,turbopuffer 能够实现 120 毫秒的搜索耗时。这是所有这些命名空间的 P90 延迟,得益于这种复杂的原生过滤策略。And this is the result. Across 450 million vectors, those 100 million documents turn into 400 million vectors, turbopuffer is able to get 120 millisecond searches. That's the P90 latency across all of those namespaces. By employing this sophisticated native filtering strategy.
实践中的写入权限过滤器Writing permission filters in practice
所以,使用 turbopuffer 时,你只需带上自己的权限逻辑和概念模型,然后把这些权限转换成 turbopuffer 的过滤器语言——我认为这一步非常简单。希望你能看懂这里的代码示例:viewers contains ones、viewers contains one、groups contains any BC。也希望你能看出如何将它映射到贵组织自己的权限结构上。这背后实际上会变成一项非常复杂的系统工程挑战,但 turbopuffer 会把这一切都隐藏起来。So, with turbopuffer, you show up with your permissions logic and your conceptual model, and you do what I think is a very simple translation of those permissions into turbopuffer filter language. And hopefully, you can directly map this code sample here, viewers contains ones viewers contains one groups contains any BC. Hopefully, you can see how you would project that onto your organization's own permission structure. And that turns into this very complicated systems engineering challenge under the hood, but turbopuffer hides that all away from you.
这样你就不必为此费心了。你只需直接表达代表权限的逻辑过滤条件即可。至于复杂的查询规划,我们会在底层处理,确保即使在 1 亿份文档的规模下,搜索也能在 1 到 200 毫秒内返回结果。不过,我们是 turbopuffer 的工程师,所以这里也存在一些限制。So that you don't have to think about it. You can just express the logical filters that represent your permissions in a fairly direct way. And we handle the complicated query planning under the hood to make that search come back in 1 to 200 milliseconds even at 100 million documents scale. Now, we're engineers at turbopuffer, so there are some limitations here.
尤其是在有嵌套组的情况下,事情就会变得棘手。我没时间详细讲解这一点,但如果你遇到类似的问题,请来找我们聊聊。我们在处理这类问题方面经验丰富,也一直在寻找改进产品的方法,让这些事情能够得到更自动化的处理。In particular, when you have nested groups, things get tricky. I'm not going to have time to go into that in too much detail, but if you have problems that look like that, please come talk to us. Uh we have a lot of experience working through these, and we're always looking for ways to improve the product so that stuff is handled more automatically.
超越权限:为隔离而生的搜索Beyond permissions: isolation-native search
因此,权限过滤实际上只是 turbopuffer 冰山一角。我们正在打造一款原生支持隔离的搜索引擎。这意味着,无论你需要在命名空间内设置细粒度权限,还是需要满足安全和监管合规义务,从而将数据限制在特定区域、将数据保存在自己的 VPC 中,或对数据进行加密——而且加密密钥不仅可以由你控制,也可以由你自己的客户控制——turbopuffer 都能提供相应的隔离方案。So, permission filters are really just the tip of the iceberg in turbopuffer. We're trying to build an isolation native search engine. That means whether you have fine-grained permissions within namespaces, whether you have security, regulatory compliance obligations that force you to regionally lock data, keep that data in your own VPC, encrypt that data potentially not just with an encryption key you control, but that your own customers control. turbopuffer has solutions for all of those levels of isolation.
因此,权限过滤只是构建支持隔离感知搜索的 turbopuffer 的诸多环节之一。以上就是全部内容。这就是 turbopuffer 和 Bridgewater 如何协同工作,在 1 亿规模下实现快速、原生支持隔离的搜索。谢谢大家。So, permission filtering is just one piece of the puzzle in building isolation-aware search in turbopuffer. So, that's all we got. That's how turbopuffer and Bridgewater work together to do fast isolation-native search at 100 million scale. Thank you, everyone.