Partilhar via


Usando o conector Redis (Visualização)

Aviso

A funcionalidade Semantic Kernel Vetor Store está em pré-visualização, e melhorias que exigem alterações de quebra ainda podem ocorrer em circunstâncias limitadas antes do lançamento.

Descrição geral

O conector Redis Vetor Store pode ser usado para acessar e gerenciar dados no Redis. O conector suporta os modos Hashes e JSON e qual modo você escolher determinará quais outros recursos são suportados.

O conector tem as seguintes características.

Área de funcionalidades Suporte
Mapas da coleção para Índice Redis com prefixo definido como <collectionname>:
Tipos de propriedade de chave suportados string
Tipos de propriedade de dados suportados Ao usar Hashes:
  • string
  • número inteiro
  • uint
  • long
  • Ulong
  • duplo
  • flutuante
  • booleano
Ao usar JSON:
Qualquer tipo serializável para JSON
Tipos de propriedade vetorial suportados
  • Float ReadOnlyMemory<>
  • ReadOnlyMemory<duplo>
Tipos de índice suportados
  • Hnsw
  • Apartamento
Funções de distância suportadas
  • CossenoSimilaridade
  • DotProductSimilarity
  • Distância Euclidiana
Suporta vários vetores em um registro Sim
IsFilterable suportado? Sim
IsFullTextSearchable suportado? Sim
StoragePropertyName suportado? Ao usar Hashes: Sim
Ao usar JSON: Não, use JsonSerializerOptions e JsonPropertyNameAttribute em vez disso. Veja aqui mais informações.

Introdução

Adicione o pacote nuget do conector Redis Vetor Store ao seu projeto.

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

Você pode adicionar o armazenamento vetorial ao contêiner de injeção de dependência disponível no KernelBuilder ou ao contêiner de IServiceCollection injeção de dependência usando métodos de extensão fornecidos pelo Semantic Kernel.

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");

Métodos de extensão que não usam parâmetros também são fornecidos. Isso requer que uma instância do Redis IDatabase seja registrada separadamente com o contêiner de injeção de dependência.

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();

Você pode construir uma instância do Redis Vetor Store diretamente.

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

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

É possível construir uma referência direta a uma coleção nomeada. Ao fazer isso, você tem que escolher entre a instância JSON ou Hashes, dependendo de como você deseja armazenar dados no 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");

Ao construir ou RedisVectorStore registrá-lo com o contêiner de injeção de dependência, é possível passar uma RedisVectorStoreOptions instância que configura o tipo/modo de armazenamento preferencial usado: Hashes ou JSON. Se não for especificado, o padrão será JSON.

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

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

Introdução

Instale o kernel semântico com os extras do redis, que inclui o cliente redis.

pip install semantic-kernel[redis]

Você pode então criar uma instância de armazenamento de vetores usando a RedisStore classe, isso usará as variáveis REDIS_CONNECTION_STRING de ambiente para se conectar a uma instância do Redis, esses valores também podem ser fornecidos diretamente.


from semantic_kernel.connectors.memory.redis import RedisStore

vector_store = RedisStore()

Você também pode criar o repositório de vetores com sua própria instância do cliente de banco de dados 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)

Você também pode criar uma coleção diretamente, mas há dois tipos de coleções, uma para Hashes e outra para 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)

Ao criar uma coleção a partir do repositório de vetores, você pode passar o tipo de coleção, como um enum: RedisCollectionTypes, o padrão é uma coleção de hash.

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,
)

Serialização

As coleções redis usam um ditado como o formato de dados ao atualizar, no entanto, a estrutura dos ditames é diferente entre eles.

Para coleções JSON, consulte redis docs para obter um exemplo.

Para coleções de Hashset, ele usa o comando hset com o campo de chave como name, campos de dados como mapping -> metadata e vetores como mapping -> [vector_field_name] , veja aqui para obter mais informações.

Para obter mais detalhes sobre esse conceito, consulte a documentação de serialização.

Introdução

Inclua a versão mais recente do conector de dados Redis do kernel semântico em seu projeto Maven adicionando a seguinte dependência ao seu pom.xml:

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

Em seguida, você pode criar uma instância de armazenamento de vetores usando a RedisVectorStore classe, tendo o cliente Redis (JedisPooled) como parâmetro.

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();
    }
}

Você também pode recuperar uma coleção diretamente.

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

Prefixos de índice

O Redis usa um sistema de prefixo de chave para associar um registro a um índice. Ao criar um índice, você pode especificar um ou mais prefixos para usar com esse índice. Se quiser associar um registo a esse índice, tem de adicionar o prefixo à chave desse registo.

Por exemplo, se você criar um índice chamado skhotelsjson com um prefixo de , ao definir um registro com chaveh1, a chave de registro precisará ser prefixada como esta skhotelsjson:h1 para ser adicionada skhotelsjson:ao índice.

Ao criar uma nova coleção usando o conector Redis, o conector criará um índice no Redis com um prefixo que consiste no nome da coleção e dois pontos, como este <collectionname>:. Por padrão, o conector também prefixará todas as chaves com o prefixo this ao fazer operações de registro como Get, Upsert e Delete.

Se você não quiser usar um prefixo que consiste no nome da coleção e dois pontos, é possível desativar o comportamento de prefixo e passar a chave totalmente prefixada para as operações de registro.

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();

Mapeamento de dados

O Redis suporta dois modos de armazenamento de dados: JSON e Hashes. O conector Redis suporta ambos os tipos de armazenamento e o mapeamento difere dependendo do tipo de armazenamento escolhido.

Mapeamento de dados ao usar o tipo de armazenamento JSON

Ao usar o tipo de armazenamento JSON, o conector Redis será usado System.Text.Json.JsonSerializer para fazer o mapeamento. Como o Redis armazena registros com uma chave e um valor separados, o mapeador serializará todas as propriedades, exceto a chave para um objeto JSON, e usará isso como o valor.

O uso do é suportado se for necessário um nome de armazenamento diferente para o nome da propriedade do modelo de JsonPropertyNameAttribute dados. Também é possível usar uma instância personalizada JsonSerializerOptions com uma política de nomenclatura de propriedade personalizada. Para permitir isso, o JsonSerializerOptions deve ser passado para a RedisJsonVectorStoreRecordCollection construção on.

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

Como uma política de nomenclatura de maiúsculas e minúsculas foi escolhida, aqui está um exemplo de como esse tipo de dados será definido no Redis. Observe também o uso de on the Description property para personalizar ainda mais a nomenclatura do JsonPropertyNameAttribute armazenamento.

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.CosineDistance, 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] }'

Mapeamento de dados ao usar o tipo de armazenamento Hashes

Ao usar o tipo de armazenamento Hashes, o conector Redis fornece seu próprio mapeador para fazer mapeamento. Esse mapeador mapeará cada propriedade para um par campo-valor, conforme suportado pelo comando Redis HSET .

Para propriedades de dados e propriedades de vetor, você pode fornecer nomes de campo de substituição para uso no armazenamento que sejam diferentes dos nomes de propriedade no modelo de dados. Isso não é suportado para chaves, uma vez que as chaves não podem ser nomeadas no Redis.

A substituição do nome da propriedade é feita definindo a StoragePropertyName opção por meio dos atributos do modelo de dados ou da definição do registro.

Aqui está um exemplo de um modelo de dados com StoragePropertyName atributos definidos e como eles são definidos no 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.CosineDistance, 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>