dot Redis 8 已发布——并且它是开源的

了解更多

.NET 向量搜索简化

Redis OM .NET 的向量搜索和语义缓存功能详解

Redis OM .NET 现在支持 Redis 向量搜索,并集成了使用 OpenAI、Azure OpenAI、Hugging Face 和 ML.NET 的嵌入生成 API。

向量数据库技术正在重塑我们思考数据的方式。文本段落、图像和音频都可以编码并索引为向量,从而进行语义搜索。我们正在迅速迈向一个数据的机器可读语义蕴含在其内容而非其结构中的世界。

然而,向量数据库可能不太直观。你需要知道如何正确构建向量索引,如何将非结构化数据转换为可用的向量,如何将数据添加到数据源,以及如何构建查询。实际上,这意味着从非结构化数据创建向量表示,然后使用这些表示来查询存储的向量。所以,这与传统的 SELECT/FROM/WHERE 查询不太一样。

两年前,我们发布了 Redis OM 库,以便在 Redis 的搜索和查询功能之上构建直观的抽象。现在,我们正在扩展该抽象,使其更容易为您的 AI 应用执行向量搜索。让我们详细了解一下 Redis OM .NET 的这些新增强功能,以实现 Redis 向量搜索

Redis OM .NET API 的最新添加功能使得存储和查询向量数据变得更加容易,即使您以前从未接触过向量。事实上,Redis OM .NET 现在包含用于向量搜索和语义缓存的直观接口。具体来说,我们构建了

  1. Redis 向量索引、数据建模和查询功能
  2. 一套易于使用的向量化器(又称嵌入生成器),可与 OpenAI、Azure OpenAI、Hugging Face 和 ML.NET 框架集成
  3. 一个与任何向量化器配合使用并减少昂贵 LLM 调用的语义缓存实现

所有这些功能结合在一起,将一个可能难以理解和实现的过程简化为几行简单的代码。

建模和索引创建

假设我们有一个包含一系列商品的产品目录,我们希望能够查找具有相似库存图片或相似产品描述的商品。我们还希望能够根据一系列方面进一步优化查询。现在我们只需要这个模型

[Document(StorageType = StorageType.Json)]
public class Product
{
    [RedisIdField] [Indexed] public int Id { get; set; }

    [Indexed(Algorithm = VectorAlgorithm.HNSW, DistanceMetric = DistanceMetric.COSINE)] 
    [ImageVectorizer]
    public Vector<string> ImageUrl { get; set; }    

    [Indexed(Algorithm = VectorAlgorithm.FLAT, DistanceMetric = DistanceMetric.COSINE)]
    [SentenceVectorizer] 
    public Vector<string> ProductDisplayName { get; set; }
    
    public VectorScores? Scores { get; set; }

    [Indexed] public string Category { get; set; }

    [Indexed] public string ArticleType { get; set; }

    [Indexed] public string BaseColor { get; set; }

    [Indexed] public string Season { get; set; }

    // other facets 
}

定义模型后,我们可以通过调用 CreateIndex 方法在 Redis 中创建所需的索引

var provider = new RedisConnectionProvider("redis://localhost:6379");
provider.Connection.CreateIndex(typeof(Product))

插入

索引创建完成后,我们可以开始向 Redis 数据库中插入商品了

var collection = provider.RedisCollection<Product>();
var entry = new Product { 
    Id = id, 
    ImageUrl = Vector.Of(imageUrl), 
    ProductDisplayName = Vector.Of(productDisplayName),
    Category = category, 
    ArticleType = articleType, 
    BaseColor = baseColour, 
    Season = season
    // etc…
};
await collection.InsertAsync(entry);

请注意,在模型中,我们将 ImageUrl 和 ProductDisplayName 这两个字段定义为向量。当我们写入一个条目时,Redis OM 将使用提供的向量化器为您创建这些字段的向量表示。在本例中,我们使用了 Redis.OM.Vectorizers.ResNet18 包中的 ImageVectorizer 和 Redis.OM.Vectorizers.AllMiniLML6V2 包中的 sentence Vectorizer。

这些向量化器是 VectorizerAttribute<T> 的实现。这些属性告诉 Redis OM 使用哪个 IVectorizer<T>,以及生成向量的类型和形状。底层,这两个向量化器都使用 ML.NET 来创建向量。VectorizerAttribute<T>IVectorizer<T> 类型让您可以抽象向量创建逻辑,使您的向量化器选择具有可扩展性和可定制性。此外,Redis OM .NET 还包含用于直接双精度和浮点数组的向量化器,以及用于 OpenAI、Azure OpenAI 和 Hugging Face 的向量化器。要使用 OpenAI、Azure OpenAI 或 Hugging Face 生成向量,您只需提供 API 密钥,在某些情况下还需要模型 ID 或资源名称。

查询

定义模型、创建索引并插入数据后,我们可以发出向量查询。为此,我们使用 IRedisCollection.NearestNeighborsVector<T>.VectorRange 方法,并结合我们用于任何其他 LINQ 查询的布尔表达式。

最近邻

每个查询支持一次最近邻搜索。它是 k-最近邻还是近似最近邻取决于您在模型的 IndexAttribute 中声明的算法。要运行最近邻搜索,只需在 RedisCollection 上调用 NearestNeighbor

var response = collection.NearestNeighbors(x => x.ImageUrl, 15, url).ToList();

向量范围

要执行向量范围搜索(筛选与您的向量在一定距离内的向量),请在您的表达式中使用 VectorRange 方法作用于您的向量字段

var item = collection.First(x => x.ImageUrl.VectorRange(url, .15, "distance"));

混合查询

混合查询结合了传统搜索过滤器和向量搜索。要在 Redis OM .NET 中实现这一点,请将您常用的布尔表达式与向量范围和/或最近邻查询结合使用。以下查询检索所有秋季服装产品,这些产品的图片与提供的图片距离在 0.15 以内,并选择最近邻。

var item = collection
    .NearestNeighbors(x => x.ImageUrl, 1, url)
    .First(x=>x.ImageUrl.VectorRange(url, .15, "distance") && x.Season == "Fall" && x.Category == "Apparel")

在这种情况下,Redis OM .NET 会自动构建查询并发出。

语义缓存

语义缓存是一种新的缓存技术,得益于嵌入生成和向量搜索的最新进展而成为可能。传统上,我们认为 Redis 缓存是在某个精确的键存储某个精确的值。您需要完整的键才能恢复缓存项。当然,当您存储分布式会话状态或昂贵的 API 调用或查询结果时,这很有意义。

然而,当您缓存来自 LLM 的提示/响应对时,要求精确的键值匹配就成了问题。这是因为语义缓存允许您按意义(即语义上)存储和检索提示,而不仅仅是按键/值对。这意味着两个相关的查询,如“世界上最高的建筑是什么?”和“世界上最高的建筑是哪个?”,它们的意义足够接近,当其中任何一个问题被存储时,它们都应该返回相同的 LLM 响应。在 Redis OM .NET 中,语义缓存使用与向量搜索相同的向量化器。要使用语义缓存,您可以直接初始化一个 SemanticCache,或者使用 Redis.OM.Vectorizers 包提供的缓存之一

var provider = new RedisConnectionProvider("redis://localhost:6379");
var cache = provider.OpenAISemanticCache(apiKey, threshold: .15, ttl: 3600000);
cache.Store("What is the capital of France?", "Paris");
var res = cache.GetSimilar("What really is the capital of France?").First();

在这种情况下,我们使用 OpenAI REST API 来构建我们的向量。实现这一功能所需的只是一个 OpenAI API 密钥。我们已将语义缓存配置为将项目存储一小时。当我们检索项目时,我们获取距离小于 0.15 的项目(余弦相似度的距离被归一化到 0 到 1 之间)。

自定义向量生成

如果 Redis OM .NET 尚未提供您项目所需的向量化器,您可以自行实现。您只需要一个 IVectorizer<T> 来执行实际的向量化操作,并且需要一个 VectorizerAttribute<T> 来装饰模型中的 Vector<T> 字段。VectorizerAttribute<T> 负责告诉 Redis OM .NET 如何构建索引以及如何在插入或查询时创建向量。

总结

向量数据库正在迅速普及。借助 Redis OM .NET,您不再需要成为将数据转换为向量的专家即可使用向量数据库。Redis OM .NET 的新向量化器、向量搜索和语义缓存功能消除了构建向量索引、将数据转换为向量以及构建向量查询的麻烦。换句话说,它是一个直观、强大的工具,让您可以更轻松地使用 Redis 闪电般的向量搜索功能。

相关资源

  • 向量搜索示例来自 GitHub 上的产品目录 Redis OM .NET 演示仓库。
  • 要了解如何配置不同的向量化器,请参阅 Redis OM .NET 的 README
  • 要了解有关 Redis 向量搜索 API 的更多信息,请查阅 Redis 向量文档