ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

StackExchange.Redis 中的 Redis Vector Sets 实战指南:从向量写入到相似度搜索的完整 API 解析

StackExchange.Redis 中的 Redis Vector Sets 实战指南:从向量写入到相似度搜索的完整 API 解析 后端缓存数据库客户端消息队列【免费下载链接】StackExchange.RedisThe Redis client for .NET项目地址https://gitcode.com/gh_mirrors/st/StackExchange.Redis点击查看免费下载Redis Vector Sets向量集合是 Redis 8.0 起提供的向量数据类型用于高效存储向量数据并执行相似度检索。本文以 StackExchange.Redis 官方文档 docs/VectorSets.md 为骨架结合仓库内 RedisDatabase.VectorSets.cs、VectorSetAddRequest.cs、VectorSetSimilaritySearchRequest.cs 等源码实现与 VectorSetIntegrationTests.cs 测试用例完整讲解 SE.Redis 强类型向量 API 的用法、底层命令映射、内存管理与性能优化策略。读完本文你将能够使用 StackExchange.Redis 完成向量写入、带 JSON 属性的过滤式相似度搜索、HNSW 索引调参、范围查询与语义搜索/推荐系统等实战方案。前置条件Redis 版本要求Vector Sets 依赖 Redis 8.0 或更高版本。在调用任何VectorSet*系列 API 之前请确认服务端版本满足要求否则命令将不被识别。客户端侧无需额外配置只要使用本文介绍的 API 即可向量集在首次执行VADD时自动创建其索引类型默认使用 HNSW 近似最近邻索引与参数可在写入时控制详见下文高级配置一节。快速上手与文档一致下文示例中的向量仅为便于演示而缩小4 维实际生产场景中通常使用高维向量如 128、384、768 维。API 的设计目标是高效处理大向量例如 VectorSetAddRequest.Member 接收ReadOnlyMemoryfloat而非数组这使得你可以直接基于ArrayPoolT池化缓冲区甚至内存映射文件memory-mapped files中的原始内存工作避免不必要的数组分配与拷贝。添加向量使用VectorSetAddAsync将成员及其向量写入向量集var db conn.GetDatabase(); var key product-embeddings; // 从 ML 模型产出的向量 var vector new[] { 0.1f, 0.2f, 0.3f, 0.4f }; // 添加带向量的成员 var request VectorSetAddRequest.Member(product-123, vector.AsMemory()); bool added await db.VectorSetAddAsync(key, request);返回值bool表示成员是否新增已存在成员的重复写入返回false。同步版本VectorSetAdd同样可用两者在 RedisDatabase.VectorSets.cs 中最终都会把request转换为VADD命令消息下发。添加带属性的向量可以为成员附加 JSON 元数据用于后续过滤搜索var vector new[] { 0.1f, 0.2f, 0.3f, 0.4f }; var request VectorSetAddRequest.Member( product-123, vector.AsMemory(), attributesJson: {category:electronics,price:299.99} ); await db.VectorSetAddAsync(key, request);从 VectorSetAddMessage.cs 的实现可见属性会以SETATTR {attributes}参数形式随VADD一并发送。此外源码还暴露了UseCheckAndSet对应CAS参数用于按需做检查-设置模式的部分线程安全写入详见 VectorSetAddRequest.cs。相似度搜索按已有成员搜索相似向量使用VectorSetSimilaritySearchAsync// 按已有成员搜索 var query VectorSetSimilaritySearchRequest.ByMember(product-123); query.Count 10; query.WithScores true; using var results await db.VectorSetSimilaritySearchAsync(key, query); if (results is not null) { foreach (var result in results.Value.Results) { Console.WriteLine($Member: {result.Member}, Score: {result.Score}); } }也可以直接用一个向量作为查询var queryVector new[] { 0.15f, 0.25f, 0.35f, 0.45f }; var query VectorSetSimilaritySearchRequest.ByVector(queryVector.AsMemory()); query.Count 10; query.WithScores true; using var results await db.VectorSetSimilaritySearchAsync(key, query);两种查询方式分别对应VSIM命令的ELE {member}与FP32 {vector}目标形态见 VectorSetSimilaritySearchMessage.cs。结果类型 VectorSetSimilaritySearchResult 提供Member、Score0~11 表示完全一致0 表示方向相反未请求WITHSCORES时为NaN与可选的AttributesJson。过滤搜索使用 JSONPath 表达式过滤结果var query VectorSetSimilaritySearchRequest.ByVector(queryVector.AsMemory()); query.Count 10; query.FilterExpression $.category electronics $.price 500; query.WithAttributes true; // 结果中包含属性 query.MaxFilteringEffort 100; // 可选限制过滤重试次数FILTER-EF 参数 using var results await db.VectorSetSimilaritySearchAsync(key, query);FilterExpression对应FILTER参数其完整语法如、、组合、嵌套路径等以 Redis 官方 Vector Sets 过滤搜索文档为准MaxFilteringEffortFILTER-EF则控制过滤时的最大尝试次数二者均由 VectorSetSimilaritySearchRequest.cs 公开并映射到 VectorSetSimilaritySearchMessage.cs 的写盘逻辑。Vector Set 常用操作以下 API 均提供同步与Async两种形态底层命令映射可从 RedisDatabase.VectorSets.cs 直接确认。获取向量集信息VINFO命令返回集合元数据由只读结构体 VectorSetInfo 承载var info await db.VectorSetInfoAsync(key); if (info is not null) { Console.WriteLine($Dimension: {info.Value.Dimension}); Console.WriteLine($Length: {info.Value.Length}); Console.WriteLine($Quantization: {info.Value.Quantization}); }除文档展示的Dimension向量维度与Length集合基数外VectorSetInfo还包含MaxLevelHNSW 图结构最高层、VectorSetUid集合唯一标识与HnswMaxNodeUidHNSW 图中最大节点 ID可用于观测索引规模。当服务端返回未知量化类型时Quantization为Unknown此时可通过QuantizationRaw读取原始字符串见 VectorSetQuantization.cs。检查成员是否存在bool exists await db.VectorSetContainsAsync(key, product-123);对应VISMEMBER命令RedisDatabase.VectorSets.cs。移除成员bool removed await db.VectorSetRemoveAsync(key, product-123);对应VREM命令返回是否确实移除了成员。获取随机成员// 获取单个随机成员 var member await db.VectorSetRandomMemberAsync(key); // 获取多个随机成员 var members await db.VectorSetRandomMembersAsync(key, count: 5);分别对应VRANDMEMBER与带count的VRANDMEMBERRedisDatabase.VectorSets.cs可服务于抽样、A/B 测试等场景。范围查询按字典序范围获取成员VRANGE命令支持按成员名的字典序做范围遍历返回LeaseRedisValue// 获取全部成员 using var allMembers await db.VectorSetRangeAsync(key); // ... 访问 allMembers.Span 等 // 获取指定范围内的成员 using var rangeMembers await db.VectorSetRangeAsync( key, start: product-100, end: product-200, count: 50 ); // 排除边界 using var members await db.VectorSetRangeAsync( key, start: product-100, end: product-200, exclude: Exclude.Both );参数细节可在 RedisDatabase.VectorSets.cs 中确认start/end为空时分别映射为-与正负无穷exclude通过(开区间与[闭区间前缀控制边界count默认-1表示不限制返回数量。枚举大结果集对于大型向量集应使用异步枚举按批处理结果避免客户端一次性缓冲全部数据await foreach (var member in db.VectorSetRangeEnumerateAsync(key, count: 100)) { Console.WriteLine($Processing: {member}); }从 RedisDatabase.VectorSets.cs 的实现可以看到其工作原理每次拉取一批默认count100将本批最后一个值作为下一批的排他起点继续向后翻页当返回批长度小于count或到达指定终点时停止。这意味着提前退出循环时客户端与服务端都会停止处理与发送剩余结果。枚举同样支持异步取消using var cts new CancellationTokenSource(); // 取消逻辑未展示 await foreach (var member in db.VectorSetRangeEnumerateAsync(key, count: 100) .WithCancellation(cts.Token)) { // ... }内部通过[EnumeratorCancellation]把取消令牌贯穿到每一批的VectorSetRangeAsync调用RedisDatabase.VectorSets.cs做到按批粒度的协作式取消。高级配置量化Quantization控制向量压缩方式降低内存占用并提升检索速度var request VectorSetAddRequest.Member(product-123, vector.AsMemory()); request.Quantization VectorSetQuantization.Int8; // 默认 // 或 VectorSetQuantization.None 对应 NOQUANT / f32 全精度 // 或 VectorSetQuantization.Binary对应 BIN 二进制量化 await db.VectorSetAddAsync(key, request);枚举定义见 VectorSetQuantization.csInt88 位整数量化默认值对应int8/Q8、None全精度 f32对应NOQUANT、Binary二进制量化对应BIN。量化类型通过AsciiHash特性与服务端返回的字符串做无分配快速解析并在 VectorSetAddMessage.cs 中按类型决定是否携带NOQUANT/BIN参数Int8为隐式默认不发送参数。维度缩减使用随机投影random projection降低向量维度var request VectorSetAddRequest.Member(product-123, vector.AsMemory()); request.ReducedDimensions 128; // 从原始维度降维 await db.VectorSetAddAsync(key, request);对应VADD的REDUCE {dim}参数VectorSetAddRequest.cs、VectorSetAddMessage.cs。适合对极高维向量在牺牲一定精度的前提下换取内存与计算开销。HNSW 索引参数在写入时微调 HNSW 图构建参数var request VectorSetAddRequest.Member(product-123, vector.AsMemory()); request.MaxConnections 32; // M 参数默认 16每个节点的最大连接数 request.BuildExplorationFactor 400; // EF 参数默认 200构建期的探索因子 await db.VectorSetAddAsync(key, request);MaxConnections与BuildExplorationFactor的默认值、语义M {numlinks}、EF {build-exploration-factor}均可在 VectorSetAddRequest.cs 的 XML 注释中确认。注意这些参数是在首次创建该向量集即对空 key 的首次VADD时生效的索引配置已建索引的后续写入不会改变图结构参数。搜索参数控制搜索阶段的行为var query VectorSetSimilaritySearchRequest.ByVector(queryVector.AsMemory()); query.SearchExplorationFactor 500; // EF 越大越精确但越慢 query.Epsilon 0.1; // 仅返回相似度 0.9 的结果 query.UseExactSearch true; // 使用线性扫描TRUTH替代 HNSW 近似搜索 await db.VectorSetSimilaritySearchAsync(key, query);SearchExplorationFactorEF搜索期探索因子越大召回率越高、耗时越长EpsilonEPSILON相似度阈值只返回相似度 1 - epsilon的结果如0.1对应阈值0.9UseExactSearchTRUTH强制线性精确扫描牺牲性能换取 100% 准确召回适用于小集合或对精度要求苛刻的场景。上述参数以及DisableThreadingNOTHREAD高级选项将搜索限制在主线程执行的完整映射见 VectorSetSimilaritySearchRequest.cs 与 VectorSetSimilaritySearchMessage.cs。向量数据处理获取近似向量按成员获取其近似向量注意若启用了量化或维度缩减返回的是重建后的近似向量而非原始值using var vectorLease await db.VectorSetGetApproximateVectorAsync(key, product-123); if (vectorLease ! null) { ReadOnlySpanfloat vector vectorLease.Value.Span; // 使用向量数据 }对应VEMB命令结果以Leasefloat返回见 RedisDatabase.VectorSets.cs务必用后即还详见内存管理一节。管理 JSON 属性// 获取属性 var json await db.VectorSetGetAttributesJsonAsync(key, product-123); // 设置属性 await db.VectorSetSetAttributesJsonAsync( key, product-123, {category:electronics,updated:2024-01-15} );分别对应VGETATTR与VSETATTR命令RedisDatabase.VectorSets.cs、RedisDatabase.VectorSets.cs。VSETATTR返回bool表示成员是否存在可用于校验。查看 HNSW 图链接检查 HNSW 图结构中的邻居连接// 获取链接的成员列表 using var links await db.VectorSetGetLinksAsync(key, product-123); if (links ! null) { foreach (var link in links.Value.Span) { Console.WriteLine($Linked to: {link}); } } // 获取带相似度分数的链接 using var linksWithScores await db.VectorSetGetLinksWithScoresAsync(key, product-123); if (linksWithScores ! null) { foreach (var link in linksWithScores.Value.Span) { Console.WriteLine($Linked to: {link.Member}, Score: {link.Score}); } }二者均对应VLINKS命令后者追加WITHSCORES参数结果元素类型为 VectorSetLink含Member与Score。该能力可用于诊断索引质量、可视化图结构或做基于图邻居的扩展检索。内存管理LeaseT向量相关操作相似度搜索、范围查询、近似向量、图链接返回LeaseT。LeaseT是一段由内存池默认ArrayPoolT.Shared也支持自定义MemoryPoolT支撑的连续内存必须在使用后释放以归还池中内存见 Lease.cs。// 推荐using 语句 using var results await db.VectorSetSimilaritySearchAsync(key, query); // 或显式释放 var results await db.VectorSetSimilaritySearchAsync(key, query); try { // 使用 results } finally { results?.Dispose(); }using声明式的隐式释放scope 结束时在大多数场景下足够安全显式finally释放则适合需要精确控制归还时机的长生命期代码。服务端返回null时如集合不存在或按成员搜索的成员缺失上述代码也能正确跳过释放。性能考量批量写入批量插入推荐使用管道pipelining一次往返提交多个VADDvar batch db.CreateBatch(); var tasks new ListTaskbool(); foreach (var (member, vector) in vectorData) { var request VectorSetAddRequest.Member(member, vector.AsMemory()); tasks.Add(batch.VectorSetAddAsync(key, request)); } batch.Execute(); await Task.WhenAll(tasks);管道批量提交把 N 次命令合并为更少的网络往返显著提升吞吐。若要控制单批规模可对vectorData分片后循环执行。搜索优化要点量化使用VectorSetQuantization.Int8默认或Binary降低内存占用并提升搜索速度代价是向量精度损失调优SearchExplorationFactor在召回率与延迟之间取平衡数值越大越精确、越慢使用过滤表达式缩小搜索空间减少无效候选考虑维度缩减对超高维向量使用ReducedDimensions投影换空间与算力小集合用精确搜索UseExactSearch trueTRUTH在集合规模较小时可避免 HNSW 近似误差。范围查询分页优先使用异步枚举分批处理避免一次性载入全部结果// 好按批加载、逐项处理 await foreach (var member in db.VectorSetRangeEnumerateAsync(key)) { await ProcessMemberAsync(member); } // 避免一次性加载全部结果 using var allMembers1 await db.VectorSetRangeAsync(key); // 避免虽然分批拉取但 ToArrayAsync 仍会把全部结果堆进内存 var allMembers2 await db.VectorSetRangeEnumerateAsync(key).ToArrayAsync();ToArrayAsync这类消费型收尾操作会抵消枚举的按批内存优势应避免在大集合上使用。常见模式语义搜索将文档嵌入向量存储后按查询向量检索// 1. 存储文档嵌入向量 var embedding await GetEmbeddingFromMLModel(document); var request VectorSetAddRequest.Member( documentId, embedding.AsMemory(), attributesJson: $${title:{{document.Title}},date:{{document.Date}}} ); await db.VectorSetAddAsync(documents, request); // 2. 按查询向量搜索相似文档 var queryEmbedding await GetEmbeddingFromMLModel(searchQuery); var query VectorSetSimilaritySearchRequest.ByVector(queryEmbedding.AsMemory()); query.Count 10; query.WithScores true; query.WithAttributes true; using var results await db.VectorSetSimilaritySearchAsync(documents, query);属性标题、日期等随结果返回可用于直接渲染或二次过滤。推荐系统基于用户已喜欢的商品做相似推荐并用属性过滤库存与价格// 以用户喜欢的商品为锚点查找相似商品 var query VectorSetSimilaritySearchRequest.ByMember(userLikedItemId); query.Count 20; query.FilterExpression $.inStock true $.price 100; query.WithScores true; using var recommendations await db.VectorSetSimilaritySearchAsync(products, query);附API 与 Redis 命令映射速查以上各 API 的底层命令映射可直接在 RedisDatabase.VectorSets.cs 中核对接口声明见 IDatabaseAsync.VectorSets.cs集成验证用例见 VectorSetIntegrationTests.csAPIAsync 形态Redis 命令用途VectorSetAddAsyncVADD添加成员与向量含SETATTR/REDUCE/CAS/量化/HNSW 参数VectorSetSimilaritySearchAsyncVSIM按成员ELE或向量FP32相似度搜索VectorSetLengthAsync/VectorSetDimensionAsyncVCARD/VDIM集合基数 / 向量维度VectorSetInfoAsyncVINFO集合元数据量化、维度、基数、HNSW 状态VectorSetContainsAsyncVISMEMBER成员存在性检查VectorSetRemoveAsyncVREM移除成员VectorSetRandomMember(s)AsyncVRANDMEMBER随机成员抽样VectorSetRangeAsync/VectorSetRangeEnumerateAsyncVRANGE字典序范围查询 / 分批枚举VectorSetGetApproximateVectorAsyncVEMB获取成员的近似向量VectorSetGetAttributesJsonAsync/VectorSetSetAttributesJsonAsyncVGETATTR/VSETATTR读写 JSON 属性VectorSetGetLinksAsync/VectorSetGetLinksWithScoresAsyncVLINKS可选WITHSCORES查看 HNSW 图链接结语StackExchange.Redis 对 Redis Vector Sets 提供了完整且强类型的客户端支持从VADD写入、VSIM相似度搜索、VRANGE范围枚举到 HNSW 索引调参、量化与维度缩减再到LeaseT池化内存管理均可通过统一的IDatabaseAPI 高效使用。建议在生产中遵循本文的性能要点——批量管道写入、按需量化、过滤缩小搜索空间、用异步枚举处理大结果集并在引入前确认 Redis 服务端为 8.0 及以上版本。赞分享后端缓存数据库客户端消息队列【免费下载链接】StackExchange.RedisThe Redis client for .NET项目地址https://gitcode.com/gh_mirrors/st/StackExchange.Redis点击查看免费下载相关推荐Redis搜索模块RediSearch使用Redis搜索模块RediSearch使用 Redis作为高性能的键值对数据库除了基础的数据结构支持外还通过模块系统扩展了更多高级功能。RediSearc数据库缓存KV存储消息队列不装任何客户端怎么拿到 8 大网盘的网盘直链地址不装任何客户端怎么拿到 8 大网盘的网盘直链地址 把资料从网盘搬到新设备时逐个安装各家的官方客户端是条弯路——很多平台连 Linux 版都没有。免费开源的油前端Redis Vector Sets 实战指南HNSW 向量检索与混合过滤搜索完全解析Redis Vector Sets 实战指南HNSW 向量检索与混合过滤搜索完全解析 导读 Redis Vector Sets 是 Redis 8 起内置的一数据库缓存KV存储消息队列上一篇使用 Quick 测试 iOS 与 OS X 应用UIViewController 生命周期、Storyboard 与异步等待完整实战指南下一篇D2DX3个步骤让经典暗黑破坏神2在现代PC上焕发新生创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进