最新资讯
computerworld.com Box 发布 Architect:用自然语言构建业务流程工作流 the-decoder.com METR 称 Anthropic 或已在 7 月越过自身 AI 加速预警阈值 towardsdatascience.com 用 Ollama 和 Python 构建你的第一个多工具 AI Agent the-decoder.com Thinking Machines 的 Inkling 2 Small 称霸西方开放权重模型 dev.to 为 CI/CD 构建 AI 质量门禁 dev.to Kakao 发布面向 AI Agent 的决策模型 Kanana-2-v-decide computerworld.com Microsoft 对 Copilot Chat 企业用户扩大未公开的使用限制 pub.towardsai.net Google 发布 Gemini 4 Carbon:主打网络安全能力的前沿模型 gradientflow.com METR 研究:AI 正在加速构建 AI 的团队本身 www.infoq.com GitLab 19.5 将 Agentic 开发纳入 DevOps 平台的治理体系 aiacceleratorinstitute.com 研究:AI Agent 的复杂流程编排可能反而是问题所在 pub.towardsai.net MongoDB 推出 Vercel AI SDK 集成:为 AI 应用提供持久记忆
多元动态
登录 注册
行业动态 dev.to · @Thiago Silva

SetrixDB:Go 实现的集合引擎——基于 ID 的精确集合交集(以及它在何处落败)

原文 我的收藏

文章介绍一个针对 uint64 ID 的精确集合引擎,用于电商多条件过滤、权限与 RAG 候选预过滤等需要微秒级响应的场景。作者称提供可复现的测量数据,并单列一节说明该实现在哪些方面不如一个成熟库,同时强调它并非要替代数据库。

AI推荐理由 作者介绍了一个用 Go 实现的 uint64 ID 精确集合引擎,声称给出可复现的测量数据,并专门讨论其在何处不如成熟库;对 RAG 候选预过滤、权限校验等场景有参考价值。但正文片段未给出具体基准数字,也未说明与哪个库对比,实际效果仍需看原文验证。

62

正文

“Given an ID, is it in this list?” and “which IDs are in both lists at the same time?” These look like textbook exercises. But when those lists hold millions or billions of elements and must answer in microseconds — in a faceted filter, a permission check, a pre-filter of candidates for an LLM — the answer stops being trivial. This article is about one specific primitive: an exact set engine over uint64 IDs, with measured, reproducible numbers — and a dedicated section on where it loses to an established library. It is not about replacing databases; it is about an operation that usually gets left open. The problem: set algebra over IDs A lot of modern software spends its time crossing lists of identifiers: E-commerce / search: "products this color AND this size AND this brand AND in stock" — an intersection of four sets. Permissions / RAG: "which documents can this user see AND match the query?" — intersect a permission list with a candidate list. Anti-fraud / access: "is this ID on any blocklist?" — pure membership. Text: every term or phrase becomes a key; combined queries are intersections. In all of these, what matters is exact presence and exact intersection over IDs — not payloads. Generic structures (map, joins, sorted scans) solve it — just not optimally: they carry pointers, indirections and comparisons you don't need when the data is the number. The core choice: always work with uint64 IDs. A set is a pile of uint64; an intersection is an AND. Everything is arithmetic. The mistake that made the project: 78% collisions Before a set can exist, I need dense, collision-free identifiers. My first keygen was a positional hash — a simple arithmetic formula. It collided badly: on 200k short alphanumeric tokens, 78% collided, and "Oa" and "0b" landed on the same ID. The fix was implementing a Minimal Perfect Hash Function (CHD v2, from scratch): 0 collisions on a base of 50 million keys; 4.03 bits/key (~24 MiB for 50M keys) — 3.4× less memory than v1 (13.68 bits/key); lookup in ~118 ns, and membership stays exact. If this article has one takeaway, it is this: measure the collision rate on the real corpus is the step almost everyone skips — and it changes the whole architecture. How it works (from term to result) Keygen (MPHF): term → deterministic, collision-free uint64 ID. Representation: ID i becomes bit i of a bitset; there is also a sparse set (sorted list) and a hybrid (hot ranges in a bitset + cold tail sparse). Kernel: the bitset AND runs in AVX-512 (vpandq + vpopcntq) via cgo, with runtime dispatch (__builtin_cpu_supports) and a scalar fallback — the same binary runs anywhere. Scale: the universe is split into shards (parallelizes compute); in the cluster, each node serves a shard, the coordinator broadcasts and sums, and a consistent hash ring decides ownership (adding/removing a node remaps only ~1/(N+1) of the IDs). The real numbers Environment (all measurements): reference server — 2 vCPU AMD EPYC (Zen4, AVX-512), 3.8 GB RAM, Go 1.22 (+ gcc for cgo). Date: 09/2026. Membership (n = 1M) Structure memory speed exact? map[uint64] (Go) 22.3 B/key 133.3M ops/s yes SetrixDB (MPHF CHD v2) 0.5 B/key (structure) ~118 ns/lookup yes Bloom filter (1% false positive) 1.2 B/key 23.6M ops/s no Speed parity with map, at 2.2× less memory — and exact, unlike a probabilistic filter. Intersection (A = B = 1M) Strategy dense IDs (denso32) random 64-bit IDs (aleat64) Sorted merge (SetrixDB) 9.2 ms 11.3 ms Roaring (compressed bitmap) 148 µs 523 ms Hash join (map) 91.6 ms 94.9 ms Bitset AND (pure Go) 29 µs — Bitset AND (AVX-512) 6 µs — Where it loses (and why that matters) Let me be explicit, because a comparison without context is misleading: Sparse, huge universe: when the universe does not fit in RAM, the dense bitset is out (it always takes universe/8). That's where Roaring wins — that's what it's for. Measured: universe 2²⁶, Roaring64 used ~2 MB against 8.2 MB for my bitset (slower in time, cheaper in memory). Random 64-bit IDs: in the aleat64 case, Roaring took 523 ms — but that's because it was designed for a different regime. The point is not "I always win"; it's which regime each one shines in. Range queries, similarity, joins: SetrixDB doesn't do them. It's pure equality. Frequent updates: an MPHF is built for a set; adding/removing new keys requires a rebuild. For mutable workloads, it is not the tool. So where does it win? In the opposite regime: a dense universe that fits in RAM, large sets, exact intersection on the hot path. That's exactly what a real-data test showed ↓ Real data (not just synthetic) I ran three public datasets and checked every result externally (sort + comm). Retail — Online Retail II (UCI) 1,067,371 real sale lines (UK, 2009–2011). Query "United Kingdom AND Q4/2011 AND price ≥ 5" → 22,701 rows in 823 µs. Independent check: 22,701. Identical. Text — Wikipedia titles (19.3 million terms) enwiki-latest-all-titles-in-ns0: 19,264,252 titles. "multi-word AND starts with s" → 1,408,399 in 9.5 ms; "multi-word AND United" → 38,602 in 8.0 ms. Verified: identical. Scale — MovieLens 25M (25 million interactions) 25,000,095 real ratings; derived facets (genre, decade, score). Sets with 10.9M and 12.4M members. Three queries, all externally verified: Query Result Drama AND 2000s AND rating ≥ 4 1,634,027 Drama AND rating ≥ 4 6,096,563 Comedy AND rating ≥ 4 AND 2000s 965,677 And here is the number I like most — because it is about picking the right representation. On the same 25M-ID universe, with sets of tens of millions: Path memory/set latency (A∩B) Sorted list merge 87.7 MB 80.4 ms Dense bitset (AVX-512) 2 MB 227 µs Same exact result, ~350× faster and ~43× smaller. When the universe is dense and fits in memory, the bitset isn't just the fastest — it's the most economical too. What SetrixDB IS — and what it is NOT It IS an embeddable set engine, in Go, that answers exact presence and exact intersection over uint64 IDs, with a SIMD kernel, sharding and a cluster mode. It coexists with your current database: your data stays where it is; SetrixDB sits beside it as an index/pre-filter. It is NOT a relational, columnar, NoSQL or vector database. It doesn't do SQL, joins or similarity. And — importantly — it stores sets of IDs, not payloads. Honest limitations Alpha (v0.1.0). Tested on loopback and between two machines; the 3-node cluster ran in the cloud, but not yet in multi-datacenter production. Bitset memory is linear in the universe (universe/8); the hybrid mitigates it (2³⁶ IDs: 8.59 GB dense → 1.73 MB hybrid), but it's a trade-off with a cost. NPU backend and compact UDP protocol: roadmap, not implemented. Energy benchmarks (J/search): planned, not yet measured. If any number here doesn't reproduce on your machine, that's a bug — and I want to know. Hard questions (and answers) "Why not just use CRoaring/Roaring?" Because Roaring is excellent — and it is the right answer when the universe doesn't fit in RAM or is very sparse. SetrixDB targets another point: native Go, embeddable, dense universe that fits in RAM, with MPHF in the keygen and sharding/cluster built in. If your case is Roaring's case, use Roaring. "Why not a map/Bloom filter?" A map stores pointers and is ~44× fatter per key (22.3 vs 0.5 B/key here). Bloom is smaller but it errs (1% false positive) — in permissions, erring toward "can see" is unacceptable. "Does MPHF handle insert/delete?" No. It's built for a set. Mutable loads require a rebuild (or the sparse mode). It's a conscious trade for O(1) lookup at ~4 bits/key. "What about Go's GC on the hot path?" The bitsets are contiguous []uint64, allocated once; the hot loop doesn't allocate. For DMA (NPU) there's UnsafePtr + pinning — with the caveat of keeping the buffer alive. "Isn't this just 'bitset with AVX-512'?" Partly, yes — and that's fine: bitset + SIMD is a solid, well-known base. What the project adds is the package: a collision-free keygen, adaptive representation (dense/sparse/hybrid), sharding/cluster, and the "stored sets" mode (only the name travels over the network). The invitation SetrixDB is open source (Apache-2.0). If the next wave isn't about storing more, but about deciding faster — and if set operations deserve a dedicated, exact, vectorized engine beside what you already use — come test it. Code, reproducible benchmarks and a quickstart: https://github.com/setrixdb/setrixdb Run the benchmarks, open an issue, and tell me where the numbers don't add up. SetrixDB — the arithmetic set engine. Sets. In microseconds. On any chip. Beside your database. License: Apache-2.0 · Copyright 2026 SetrixDB.

来源报道 · 1 篇 · 以下链接均前往原始媒体

← 返回精选动态 原文

更多内容