Condividi tramite


Uso del connettore Redis (anteprima)

Avviso

La funzionalità Archivio vettori Redis è disponibile in anteprima e i miglioramenti che richiedono modifiche di rilievo possono verificarsi in circostanze limitate prima del rilascio.

Avviso

La funzionalità di archiviazione vettoriale del kernel semantico è in anteprima e i miglioramenti che richiedono modifiche significative possono ancora verificarsi in circostanze limitate prima del rilascio.

Avviso

La funzionalità di archiviazione vettoriale del kernel semantico è in anteprima e i miglioramenti che richiedono modifiche significative possono ancora verificarsi in circostanze limitate prima del rilascio.

Panoramica

Il connettore Redis Vector Store può essere usato per accedere e gestire i dati in Redis. Il connettore supporta le modalità Hash e JSON e la modalità selezionata determinerà quali altre funzionalità sono supportate.

Il connettore presenta le caratteristiche seguenti.

Area delle funzionalità Supporto tecnico
Mappa delle raccolte Indice Redis con prefisso impostato su <collectionname>:
Tipi di proprietà chiave supportati corda
Tipi di proprietà dati supportati Quando si usano hash:
  • corda
  • Int
  • uint
  • lungo
  • ulong
  • doppio
  • galleggiante
  • Bool
Tipi di proprietà vettoriali supportati
  • ReadOnlyMemory<float>
  • Incorporamento<float>
  • float[]
  • ReadOnlyMemory<double>
  • Incorporamento<doppio>
  • double[]
Tipi di indice supportati
  • Hnsw
  • Piatto / Appartamento
Funzioni di distanza supportate
  • CosenoSimilarità
  • DotProductSimilarity
  • Distanza Euclidea Quadrata
Clausole di filtro supportate
  • AnyTagEqualTo
  • EqualTo
Supporta più vettori in un record
Il supporto di IsIndexed è presente?
È supportato IsFullTextIndexed?
"StorageName è supportato?" Quando si usano hash:
Quando si usa JSON: No, usare JsonSerializerOptions e JsonPropertyNameAttribute . Per altre informazioni, vedi qui.
"HybridSearch è supportato?" NO

Per iniziare

Aggiungere il pacchetto NuGet del connettore Redis Vector Store al proprio progetto.

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

È possibile aggiungere l'archivio vettoriale al contenitore di inserimento delle dipendenze disponibile in KernelBuilder o al IServiceCollection contenitore di inserimento delle dipendenze usando i metodi di estensione forniti dal kernel semantico.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;

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

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

Vengono forniti anche metodi di estensione che non accettano parametri. Questi richiedono che un'istanza di Redis IDatabase venga registrata separatamente con il contenitore di inserimento delle dipendenze.

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

È possibile costruire direttamente un'istanza dell'archivio vettoriale Redis.

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

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

È possibile costruire un riferimento diretto a una raccolta denominata. In questo caso, è necessario scegliere tra l'istanza JSON o hash a seconda di come archiviare i dati in Redis.

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

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

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

Quando si crea un RedisVectorStore oggetto o lo si registra con il contenitore di inserimento delle dipendenze, è possibile passare un'istanza RedisVectorStoreOptions che configura il tipo di archiviazione/modalità preferito usato: hash o JSON. Se non specificato, il valore predefinito è JSON.

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

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

Per iniziare

Installare il kernel semantico con gli extra di Redis, che include il client Redis.

pip install semantic-kernel[redis]

È quindi possibile creare un'istanza dell'archivio vettoriale usando la RedisStore classe , che userà le variabili REDIS_CONNECTION_STRING di ambiente per connettersi a un'istanza di Redis. Tali valori possono essere forniti direttamente.


from semantic_kernel.connectors.redis import RedisStore

vector_store = RedisStore()

È anche possibile creare l'archivio vettoriale con la propria istanza del client di database Redis.

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

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

È anche possibile creare direttamente una raccolta, ma esistono due tipi di raccolte, una per gli hash e una per JSON.

from semantic_kernel.connectors.redis import RedisHashsetCollection, RedisJsonCollection

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

Quando si crea una raccolta dall'archivio vettoriale, è possibile passare il tipo di raccolta, come enumerazione: RedisCollectionTypes, l'impostazione predefinita è una raccolta hash.

from semantic_kernel.connectors.redis import RedisStore, RedisCollectionTypes

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

Serializzazione

Le raccolte Redis usano entrambe un dict come formato di dati durante l'upserting, ma la struttura dei dict è diversa tra loro.

Per le raccolte JSON, vedere la documentazione di Redis per un esempio.

Per le raccolte hashset, usa il comando hset con il campo chiave come name, i campi dati come mapping -> metadata e i vettori come mapping -> [vector_field_name] , vedere qui per altre informazioni.

Per altri dettagli su questo concetto, vedere la documentazione sulla serializzazione.

Per iniziare

Includere la versione più recente del connettore dati Redis del kernel semantico nel progetto Maven aggiungendo la dipendenza seguente a pom.xml:

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

È quindi possibile creare un'istanza dell'archivio vettoriale usando la RedisVectorStore classe , con il client Redis (JedisPooled) come parametro.

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

È anche possibile recuperare direttamente una raccolta.

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

Prefissi di indice

Redis usa un sistema di prefisso della chiave per associare un record a un indice. Quando si crea un indice, è possibile specificare uno o più prefissi da usare con tale indice. Se si desidera associare un record a tale indice, è necessario aggiungere il prefisso alla chiave del record.

Ad esempio, se si crea un indice denominato skhotelsjson con un prefisso di skhotelsjson:, quando si imposta un record con chiave , la chiave h1del record deve essere preceduta da un prefisso simile a questo skhotelsjson:h1 per essere aggiunto all'indice.

Quando si crea una nuova raccolta usando il connettore Redis, il connettore creerà un indice in Redis con un prefisso costituito dal nome della raccolta e dai due punti, come nel seguente <collectionname>:. Per impostazione predefinita, il connettore prefissi anche tutte le chiavi con questo prefisso durante l'esecuzione di operazioni di record come Get, Upsert ed Delete.

Se non si vuole usare un prefisso costituito dal nome della raccolta e dai due punti, è possibile disattivare il comportamento di prefisso e passare la chiave con prefisso completo alle operazioni di record.

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

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

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

collection = RedisJsonCollection(collection_name="skhotels", record_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();

Mapping dei dati

Redis supporta due modalità per l'archiviazione dei dati: JSON e Hash. Il connettore Redis supporta entrambi i tipi di archiviazione e il mapping differisce a seconda del tipo di archiviazione scelto.

Mapping dei dati quando si usa il tipo di archiviazione JSON

Quando si usa il tipo di archiviazione JSON, il connettore Redis userà System.Text.Json.JsonSerializer per eseguire il mapping. Poiché Redis archivia i record con una chiave e un valore separati, il mapper serializzerà tutte le proprietà ad eccezione della chiave in un oggetto JSON e lo userà come valore.

L'utilizzo del JsonPropertyNameAttribute è supportato se è richiesto un nome di archiviazione diverso rispetto al nome della proprietà del modello di dati. È anche possibile usare un'istanza personalizzata JsonSerializerOptions con un criterio di denominazione delle proprietà personalizzato. A tale scopo, l'oggetto JsonSerializerOptions deve essere passato a RedisJsonCollection in fase di costruzione.

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

Poiché è stata scelta una convenzione di denominazione snake case maiuscolo, ecco un esempio di come questo tipo di dati verrà impostato in Redis. Si noti anche l'uso di JsonPropertyNameAttribute nella Description proprietà per personalizzare ulteriormente la denominazione di archiviazione.

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

public class Hotel
{
    [VectorStoreKey]
    public string HotelId { get; set; }

    [VectorStoreData(IsIndexed = true)]
    public string HotelName { get; set; }

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

    [VectorStoreVector(Dimensions: 4, DistanceFunction = DistanceFunction.CosineSimilarity, IndexKind = 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] }'

Mapping dei dati quando si usa il tipo di archiviazione hash

Quando si usa il tipo di archiviazione Hashs, il connettore Redis fornisce il proprio mapper per eseguire il mapping. Questo mapper eseguirà il mapping di ogni proprietà a una coppia di valori di campo come supportato dal comando Redis HSET .

Per le proprietà dei dati e le proprietà vettoriali, è possibile fornire nomi di campo di override da usare nell'archiviazione diversi dai nomi delle proprietà nel modello di dati. Questo non è supportato per le chiavi, perché alle chiavi non può essere attribuito un nome in Redis.

La sovrascrittura del nome della proprietà viene effettuata impostando l'opzione StorageName tramite gli attributi del modello di dati o la definizione del record.

Di seguito è riportato un esempio di modello di dati con StorageName impostato sui relativi attributi e su come vengono impostati in Redis.

using Microsoft.Extensions.VectorData;

public class Hotel
{
    [VectorStoreKey]
    public string HotelId { get; set; }

    [VectorStoreData(IsIndexed = true, StorageName = "hotel_name")]
    public string HotelName { get; set; }

    [VectorStoreData(IsFullTextIndexed = true, StorageName = "hotel_description")]
    public string Description { get; set; }

    [VectorStoreVector(Dimensions: 4, DistanceFunction = DistanceFunction.CosineSimilarity, IndexKind = IndexKind.Hnsw, StorageName = "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>