Partager via


Utilisation du connecteur Redis (préversion)

Avertissement

La fonctionnalité de magasin de vecteurs du noyau sémantique est en préversion et des améliorations nécessitant des modifications cassants peuvent toujours se produire dans des circonstances limitées avant la mise en production.

Vue d’ensemble

Le connecteur Redis Vector Store peut être utilisé pour accéder aux données et les gérer dans Redis. Le connecteur prend en charge les modes hashes et JSON et le mode que vous choisissez déterminent les autres fonctionnalités prises en charge.

Le connecteur présente les caractéristiques suivantes.

Zone Fonctionnalités Support
Mappages de collection à Index Redis avec préfixe défini sur <collectionname>:
Types de propriétés de clé pris en charge string
Types de propriétés de données pris en charge Lors de l’utilisation de hachages :
  • string
  • int
  • uint
  • long
  • ulong
  • double
  • virgule flottante
  • bool
Lors de l’utilisation de JSON :
Tous les types sérialisables au format JSON
Types de propriétés vectorielles pris en charge
  • Float ReadOnlyMemory<>
  • ReadOnlyMemory<double>
Types d’index pris en charge
  • Hnsw
  • Plat
Fonctions de distance prises en charge
  • CosineSimilarity
  • DotProductSimilarity
  • EuclideanDistance
Prend en charge plusieurs vecteurs dans un enregistrement Oui
Est-il pris en charge ? Oui
IsFullTextSearchable pris en charge ? Oui
StoragePropertyName pris en charge ? Lors de l’utilisation de hachages : Oui
Lors de l’utilisation de JSON : Non, utilisez JsonSerializerOptions et JsonPropertyNameAttribute à la place. Pour plus d’informations, voir ici.

Mise en route

Ajoutez le package nuget du connecteur Redis Vector Store à votre projet.

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

Vous pouvez ajouter le magasin de vecteurs au conteneur d’injection de dépendances disponible sur le KernelBuilder conteneur ou au conteneur d’injection de dépendances à l’aide IServiceCollection de méthodes d’extension fournies par le noyau sémantique.

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

Les méthodes d’extension qui ne prennent aucun paramètre sont également fournies. Celles-ci nécessitent qu’une instance de Redis IDatabase soit inscrite séparément auprès du conteneur d’injection de dépendances.

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

Vous pouvez construire une instance redis Vector Store directement.

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

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

Il est possible de construire une référence directe à une collection nommée. Dans ce cas, vous devez choisir entre l’instance JSON ou Hashes en fonction de la façon dont vous souhaitez stocker des données dans 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");

Lors de RedisVectorStore la construction ou de l’inscription auprès du conteneur d’injection de dépendances, il est possible de transmettre une RedisVectorStoreOptions instance qui configure le type de stockage/le mode de stockage préféré utilisé : hachages ou JSON. S’il n’est pas spécifié, la valeur par défaut est JSON.

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

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

Mise en route

Installez le noyau sémantique avec les extras redis, qui inclut le client redis.

pip install semantic-kernel[redis]

Vous pouvez ensuite créer une instance de magasin de vecteurs à l’aide de la RedisStore classe, qui utilise les variables REDIS_CONNECTION_STRING d’environnement pour se connecter à une instance Redis, ces valeurs peuvent également être fournies directement.


from semantic_kernel.connectors.memory.redis import RedisStore

vector_store = RedisStore()

Vous pouvez également créer le magasin de vecteurs avec votre propre instance du client de base de données 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)

Vous pouvez également créer une collection directement, mais il existe deux types de collections, un pour hashes et un pour 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)

Lors de la création d’une collection à partir du magasin de vecteurs, vous pouvez passer le type de collection, sous la forme d’une énumération : RedisCollectionTypes, la valeur par défaut est une collection de hachage.

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

Sérialisation

Les collections redis utilisent toutes deux une dict comme format de données lors de l’upserting, mais la structure des dicts est différente entre elles.

Pour les collections JSON, consultez les documents redis pour obtenir un exemple.

Pour les collections hashset, il utilise la commande hset avec le champ clé en tant que namechamps de données et mapping -> metadata vecteurs comme mapping -> [vector_field_name] , voir ici pour plus d’informations.

Pour plus d’informations sur ce concept, consultez la documentation de sérialisation.

Mise en route

Incluez la dernière version du connecteur de données Redis du noyau sémantique dans votre projet Maven en ajoutant la dépendance suivante à votre pom.xml:

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

Vous pouvez ensuite créer une instance de magasin de vecteurs à l’aide de la RedisVectorStore classe, avec le client Redis (JedisPooled) en tant que paramètre.

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

Vous pouvez également récupérer une collection directement.

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

Préfixes d’index

Redis utilise un système de préfixe de clé pour associer un enregistrement à un index. Lors de la création d’un index, vous pouvez spécifier un ou plusieurs préfixes à utiliser avec cet index. Si vous souhaitez associer un enregistrement à cet index, vous devez ajouter le préfixe à la clé de cet enregistrement.

Par exemple, si vous créez un index appelé skhotelsjson avec un préfixe de , lors de skhotelsjson:la définition d’un enregistrement avec clé h1, la clé d’enregistrement doit être précédée comme suit skhotelsjson:h1 pour être ajoutée à l’index.

Lors de la création d’une collection à l’aide du connecteur Redis, le connecteur crée un index dans Redis avec un préfixe composé du nom de la collection et d’un signe deux-points, comme suit <collectionname>:. Par défaut, le connecteur préfixe également toutes les clés avec ce préfixe lors d’opérations d’enregistrement telles que Get, Upsert et Delete.

Si vous ne souhaitez pas utiliser de préfixe composé du nom de la collection et d’un signe deux-points, il est possible de désactiver le comportement de préfixe et de passer la clé entièrement préfixée aux opérations d’enregistrement.

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

Mappage de données

Redis prend en charge deux modes de stockage de données : JSON et Hachages. Le connecteur Redis prend en charge les deux types de stockage et le mappage diffère selon le type de stockage choisi.

Mappage des données lors de l’utilisation du type de stockage JSON

Lorsque vous utilisez le type de stockage JSON, le connecteur Redis utilise System.Text.Json.JsonSerializer pour effectuer le mappage. Étant donné que Redis stocke les enregistrements avec une clé et une valeur distinctes, le mappeur sérialise toutes les propriétés à l’exception de la clé vers un objet JSON et l’utilise comme valeur.

L’utilisation du fichier est prise en charge si un nom de stockage différent du nom de JsonPropertyNameAttribute propriété du modèle de données est requis. Il est également possible d’utiliser une instance personnalisée JsonSerializerOptions avec une stratégie d’affectation de noms de propriété personnalisée. Pour l’activer, le JsonSerializerOptions doit être transmis à la RedisJsonVectorStoreRecordCollection construction.

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

Étant donné qu’une stratégie de nommage du majuscule de cas de serpent a été choisie, voici un exemple de la façon dont ce type de données sera défini dans Redis. Notez également l’utilisation de JsonPropertyNameAttribute la Description propriété pour personnaliser davantage le nommage de stockage.

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] }'

Mappage des données lors de l’utilisation du type de stockage Hashes

Lorsque vous utilisez le type de stockage Hashes, le connecteur Redis fournit son propre mappeur pour effectuer le mappage. Ce mappeur mappe chaque propriété à une paire de valeurs de champ comme pris en charge par la commande Redis HSET .

Pour les propriétés de données et les propriétés vectorielles, vous pouvez fournir des noms de champs de remplacement à utiliser dans le stockage différent des noms de propriétés sur le modèle de données. Cela n’est pas pris en charge pour les clés, car les clés ne peuvent pas être nommées dans Redis.

La substitution du nom de propriété est effectuée en définissant l’option StoragePropertyName via les attributs du modèle de données ou la définition d’enregistrement.

Voici un exemple de modèle de données avec StoragePropertyName un ensemble sur ses attributs et la façon dont ceux-ci sont définis dans 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>