使用 Redis 连接器 (预览版)

警告

语义内核向量存储功能目前处于预览阶段,在发布前仍可能在有限情况下进行需要重大变更的改进。

概述

Redis 矢量存储连接器可用于访问和管理 Redis 中的数据。 连接器同时支持哈希和 JSON 模式,选择的模式将确定支持哪些其他功能。

连接器具有以下特征。

功能区域 支持
集合映射到 前缀设置为 <collectionname>: 的 Redis 索引
支持的键属性类型 字符串
支持的数据属性类型 使用哈希时:
  • 字符串
  • int
  • uint
  • ulong
  • double
  • 漂浮
  • 布尔
使用 JSON 时:
任何可序列化为 JSON 的类型
支持的向量属性类型
  • ReadOnlyMemory<float>
  • ReadOnlyMemory<double>
支持的索引类型
  • Hnsw
  • 平面
支持的距离函数
  • 余弦相似度
  • DotProductSimilarity
  • 欧几里得平方距离
支持的过滤条件
  • AnyTagEqualTo
  • EqualTo
支持记录中的多个向量
是否支持Filterable?
是否支持FullTextSearchable?
StoragePropertyName 支持吗? 使用哈希时:
使用 JSON 时:不要,用JsonSerializerOptionsJsonPropertyNameAttribute替代。 有关详细信息,请参阅此处。
支持 HybridSearch?

入门

将 Redis Vector Store 连接器 nuget 包添加到项目。

dotnet add package Microsoft.SemanticKernel.Connectors.Redis --prerelease

可以通过语义内核提供的扩展方法,将向量存储添加到 KernelBuilder 的依赖项注入容器或 IServiceCollection 的依赖项注入容器中。

using Microsoft.SemanticKernel;

// Using Kernel Builder.
var kernelBuilder = Kernel
    .CreateBuilder()
    .AddRedisVectorStore("localhost:6379");
using Microsoft.SemanticKernel;

// Using IServiceCollection with ASP.NET Core.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRedisVectorStore("localhost:6379");

还提供不带参数的扩展方法。 这些要求将 Redis IDatabase 的实例单独注册到依赖项注入容器。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using StackExchange.Redis;

// Using Kernel Builder.
var kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.Services.AddSingleton<IDatabase>(sp => ConnectionMultiplexer.Connect("localhost:6379").GetDatabase());
kernelBuilder.AddRedisVectorStore();
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using StackExchange.Redis;

// Using IServiceCollection with ASP.NET Core.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IDatabase>(sp => ConnectionMultiplexer.Connect("localhost:6379").GetDatabase());
builder.Services.AddRedisVectorStore();

可以直接构造 Redis 矢量存储实例。

using Microsoft.SemanticKernel.Connectors.Redis;
using StackExchange.Redis;

var vectorStore = new RedisVectorStore(ConnectionMultiplexer.Connect("localhost:6379").GetDatabase());

可以构造对命名集合的直接引用。 执行此操作时,必须在 JSON 或哈希实例之间进行选择,具体取决于要在 Redis 中存储数据的方式。

using Microsoft.SemanticKernel.Connectors.Redis;
using StackExchange.Redis;

// Using Hashes.
var hashesCollection = new RedisHashSetVectorStoreRecordCollection<Hotel>(
    ConnectionMultiplexer.Connect("localhost:6379").GetDatabase(),
    "skhotelshashes");
using Microsoft.SemanticKernel.Connectors.Redis;
using StackExchange.Redis;

// Using JSON.
var jsonCollection = new RedisJsonVectorStoreRecordCollection<Hotel>(
    ConnectionMultiplexer.Connect("localhost:6379").GetDatabase(),
    "skhotelsjson");

构造 RedisVectorStore 或注册依赖项注入容器时,可以传递配置 RedisVectorStoreOptions 使用的首选存储类型/模式的实例:哈希或 JSON。 如果未指定,则默认值为 JSON。

using Microsoft.SemanticKernel.Connectors.Redis;
using StackExchange.Redis;

var vectorStore = new RedisVectorStore(
    ConnectionMultiplexer.Connect("localhost:6379").GetDatabase(),
    new() { StorageType = RedisStorageType.HashSet });

入门

使用 redis 附加组件安装语义内核,其中包括 redis 客户端。

pip install semantic-kernel[redis]

然后,可以使用类创建矢量存储实例 RedisStore ,这将使用环境变量 REDIS_CONNECTION_STRING 连接到 Redis 实例,也可以直接提供这些值。


from semantic_kernel.connectors.memory.redis import RedisStore

vector_store = RedisStore()

还可以使用自己的 redis 数据库客户端实例创建矢量存储。

from redis.asyncio.client import Redis
from semantic_kernel.connectors.memory.redis import RedisStore

redis_database = Redis.from_url(url="https://<your-redis-service-name>")
vector_store = RedisStore(redis_database=redis_database)

也可以直接创建集合,但有两种类型的集合,一种用于哈希,一种用于 JSON。

from semantic_kernel.connectors.memory.redis import RedisHashsetCollection, RedisJsonCollection

hash_collection = RedisHashsetCollection(collection_name="skhotels", data_model_type=Hotel)
json_collection = RedisJsonCollection(collection_name="skhotels", data_model_type=Hotel)

从向量存储创建集合时,可以传入集合类型,作为枚举: RedisCollectionTypes,默认值为哈希集合。

from semantic_kernel.connectors.memory.redis import RedisStore, RedisCollectionTypes

vector_store = RedisStore()
collection = vector_store.get_collection(
    collection_name="skhotels", 
    data_model_type=Hotel, 
    collection_type=RedisCollectionTypes.JSON,
)

序列化

在 Redis 中,集合数据类型在进行更新插入时都使用字典作为数据格式,然而字典的结构在它们之间有所不同。

有关 JSON 集合,请参阅 redis 文档 以获取示例。

对于 Hashset 集合,使用 hset 命令,其中键字段为 name,数据字段为 mapping -> metadata,向量为 mapping -> [vector_field_name]。有关更多信息,请参阅 此处

有关此概念的更多详细信息,请参阅 序列化文档

入门

在 Maven 项目中添加以下依赖项 pom.xml,以包括最新版本的语义内核 Redis 数据连接器:

<dependency>
    <groupId>com.microsoft.semantic-kernel</groupId>
    <artifactId>semantickernel-data-redis</artifactId>
    <version>[LATEST]</version>
</dependency>

然后,可以使用类创建矢量存储实例 RedisVectorStore ,将 Redis 客户端(JedisPooled)作为参数。

import com.microsoft.semantickernel.data.redis.RedisJsonVectorStoreRecordCollectionOptions;
import com.microsoft.semantickernel.data.redis.RedisStorageType;
import com.microsoft.semantickernel.data.redis.RedisVectorStore;
import com.microsoft.semantickernel.data.redis.RedisVectorStoreOptions;
import redis.clients.jedis.JedisPooled;

public class Main {
    public static void main(String[] args) {
        JedisPooled jedis = new JedisPooled("<your-redis-url>");

        // Build a Redis Vector Store
        // Available storage types are JSON and HASHSET. Default is JSON.
        var vectorStore = RedisVectorStore.builder()
            .withClient(jedis)
            .withOptions(
                RedisVectorStoreOptions.builder()
                    .withStorageType(RedisStorageType.HASH_SET).build())
            .build();
    }
}

你还可以直接获取一个集合。

var collection = vectorStore.getCollection("skhotels",
    RedisJsonVectorStoreRecordCollectionOptions.<Hotel>builder()
        .withRecordClass(Hotel.class)
        .build());

索引前缀

Redis 使用键前缀系统将记录与索引相关联。 创建索引时,可以指定要用于该索引的一个或多个前缀。 如果您想将一条记录与该索引相关联,则必须将前缀添加到该记录的键上。

例如,如果创建一个名为skhotelsjson且前缀为skhotelsjson:的索引,当设置键为h1的记录时,记录键需要像skhotelsjson:h1这样加上前缀,以便添加到索引中。

使用 Redis 连接器创建新集合时,连接器将在 Redis 中创建索引,其前缀由集合名称和冒号组成,如下所示 <collectionname>:。 默认情况下,连接器在执行 Get、Upsert 和 Delete 等记录操作时,会在所有键前加上之前指定的前缀。

如果不想使用由集合名称和冒号组成的前缀,则可以关闭前缀行为,并将完全前缀键传递到记录操作。

using Microsoft.SemanticKernel.Connectors.Redis;
using StackExchange.Redis;

var collection = new RedisJsonVectorStoreRecordCollection<Hotel>(
    ConnectionMultiplexer.Connect("localhost:6379").GetDatabase(),
    "skhotelsjson",
    new() { PrefixCollectionNameToKeyNames = false });

await collection.GetAsync("myprefix_h1");
from semantic_kernel.connectors.memory.redis import RedisJsonCollection

collection = RedisJsonCollection(collection_name="skhotels", data_model_type=hotel, prefix_collection_name_to_key_names=False)

await collection.get("myprefix_h1")
var collection = vectorStore.getCollection("skhotels",
    RedisJsonVectorStoreRecordCollectionOptions.<Hotel>builder()
        .withRecordClass(Hotel.class)
        .withPrefixCollectionName(false)
        .build());

collection.getAsync("myprefix_h1", null).block();

数据映射

Redis 支持两种存储数据的模式:JSON 和哈希。 Redis 连接器支持这两种存储类型,映射因所选存储类型而异。

使用 JSON 存储类型时的数据映射

使用 JSON 存储类型时,Redis 连接器将使用 System.Text.Json.JsonSerializer 进行映射。 由于 Redis 存储具有单独键和值的记录,因此映射器将序列化除 JSON 对象的键之外的所有属性,并将其用作值。

如果需要一个与数据模型属性名称不同的存储名称,则支持使用JsonPropertyNameAttribute。 还可以使用具有自定义属性命名策略的自定义 JsonSerializerOptions 实例。 若要启用此功能,必须将 JsonSerializerOptions 传递到 RedisJsonVectorStoreRecordCollection 构造函数中。

var jsonSerializerOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseUpper };
var collection = new RedisJsonVectorStoreRecordCollection<Hotel>(
    ConnectionMultiplexer.Connect("localhost:6379").GetDatabase(),
    "skhotelsjson",
    new() { JsonSerializerOptions = jsonSerializerOptions });

由于选择了大写蛇形命名法的命名规则,下面是如何在 Redis 中设置此数据类型的示例。 另请注意在 Description 属性上使用 JsonPropertyNameAttribute,以进一步自定义存储命名。

using System.Text.Json.Serialization;
using Microsoft.Extensions.VectorData;

public class Hotel
{
    [VectorStoreRecordKey]
    public ulong HotelId { get; set; }

    [VectorStoreRecordData(IsFilterable = true)]
    public string HotelName { get; set; }

    [JsonPropertyName("HOTEL_DESCRIPTION")]
    [VectorStoreRecordData(IsFullTextSearchable = true)]
    public string Description { get; set; }

    [VectorStoreRecordVector(Dimensions: 4, DistanceFunction.CosineSimilarity, IndexKind.Hnsw)]
    public ReadOnlyMemory<float>? DescriptionEmbedding { get; set; }
}
JSON.SET skhotelsjson:h1 $ '{ "HOTEL_NAME": "Hotel Happy", "HOTEL_DESCRIPTION": "A place where everyone can be happy.", "DESCRIPTION_EMBEDDING": [0.9, 0.1, 0.1, 0.1] }'

使用哈希存储类型时的数据映射

使用哈希存储类型时,Redis 连接器提供自己的映射器来执行映射。 此映射器将每个属性映射到 Redis HSET 命令支持的字段值对。

对于数据属性和向量属性,可以提供替代字段名称,以便在存储中使用的字段名称与数据模型中的属性名称不同。 密钥不支持此操作,因为无法在 Redis 中命名密钥。

属性名称的重写是通过在数据模型属性或记录定义中设置 StoragePropertyName 选项来完成的。

这是一个数据模型示例,其中 StoragePropertyName 被设置在其属性上,以及如何在 Redis 中设置这些模型。

using Microsoft.Extensions.VectorData;

public class Hotel
{
    [VectorStoreRecordKey]
    public ulong HotelId { get; set; }

    [VectorStoreRecordData(IsFilterable = true, StoragePropertyName = "hotel_name")]
    public string HotelName { get; set; }

    [VectorStoreRecordData(IsFullTextSearchable = true, StoragePropertyName = "hotel_description")]
    public string Description { get; set; }

    [VectorStoreRecordVector(Dimensions: 4, DistanceFunction.CosineSimilarity, IndexKind.Hnsw, StoragePropertyName = "hotel_description_embedding")]
    public ReadOnlyMemory<float>? DescriptionEmbedding { get; set; }
}
HSET skhotelshashes:h1 hotel_name "Hotel Happy" hotel_description 'A place where everyone can be happy.' hotel_description_embedding <vector_bytes>