Vektör deposuna veri nasıl alınır?

Bu makalede, aşağıdakiler için bir uygulamanın nasıl oluşturulacağı gösterilmektedir:

  1. Microsoft Word belgesindeki her paragraftan metin alma.
  2. Her paragraf için bir ekleme oluşturun.
  3. Metni, eklemeyi ve özgün konuma başvuruyu Redis örneğine ekleyin.

Önkoşullar

Bu örnek için ihtiyacınız olan:

  • Azure'da veya seçtiğiniz başka bir sağlayıcıda barındırılan bir ekleme oluşturma modeli.
  • Redis'i yerel olarak çalıştırabilmeniz için Redis veya Docker Desktop örneği.
  • Ayrıştırmak ve yüklemek için bir Word belgesi.

Redis'i ayarlama

Zaten bir Redis örneğiniz varsa bunu kullanabilirsiniz. Projenizi yerel olarak test etmek isterseniz Docker kullanarak kolayca bir Redis kapsayıcısı başlatabilirsiniz:

docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latest

Başarıyla çalıştığını doğrulamak için tarayıcınızda adresine http://localhost:8001/redis-stack/browser gidin.

Bu yönergelerin geri kalanında, bu ayarlarla bir kapsayıcı kullandığınız varsayılır.

Projenizi oluşturma

Yeni bir proje oluşturun ve Redis sağlayıcısı için NuGet paket başvuruları, Word belgesini okumak için OpenXml paketi ve ekleme oluşturmak için Azure OpenAI paketleri ekleyin.

dotnet new console --framework net8.0 --name VectorIngest
cd VectorIngest
dotnet package add Azure.AI.OpenAI
dotnet package add Microsoft.Extensions.AI.OpenAI
dotnet package add Microsoft.SemanticKernel.Connectors.Redis --prerelease
dotnet package add DocumentFormat.OpenXml

Veri modeli ekleme

Verileri karşıya yüklemek için önce verilerin veritabanında hangi biçime sahip olması gerektiğini açıklamanız gerekir. Her özelliğin işlevini açıklayan özniteliklere sahip bir veri modeli oluşturarak bunu yapabilirsiniz.

Projeye adlı TextParagraph.cs yeni bir dosya ekleyin ve aşağıdaki modeli ekleyin.

internal class TextParagraph
{
    /// <summary>A unique key for the text paragraph.</summary>
    [VectorStoreKey]
    public required string Key { get; init; }

    /// <summary>A URI that points at the original location of the document containing the text.</summary>
    [VectorStoreData]
    public required string DocumentUri { get; init; }

    /// <summary>The ID of the paragraph from the document containing the text.</summary>
    [VectorStoreData]
    public required string ParagraphId { get; init; }

    /// <summary>The text of the paragraph.</summary>
    [VectorStoreData]
    public required string Text { get; init; }

    /// <summary>The embedding generated from the text.</summary>
    [VectorStoreVector(1536)]
    public ReadOnlyMemory<float> TextEmbedding { get; set; }
}

vektörün boyutu olan 1536 değeri, VectorStoreVectorAttribute aktarılır. Bu değer, seçtiğiniz ekleme oluşturucusunun ürettiği vektör boyutuyla eşleşmelidir.

Tip

Veri modelinize açıklama ekleme ve her öznitelik için hangi ek seçeneklerin kullanılabildiğini hakkında daha fazla bilgi için bkz. Veri modelinizi tanımlama.

Belgedeki paragrafları okuma

Ardından, Word belgesini okumak ve içindeki her paragrafın metnini bulmak için kodu eklersiniz.

Adlı DocumentReader.cs projeye yeni bir dosya ekleyin ve bir belgedeki paragrafları okumak için aşağıdaki sınıfı ekleyin.

internal class DocumentReader
{
    public static IEnumerable<TextParagraph> ReadParagraphs(Stream documentContents, string documentUri)
    {
        // Open the document.
        using WordprocessingDocument wordDoc = WordprocessingDocument.Open(documentContents, false);
        if (wordDoc.MainDocumentPart == null)
        {
            yield break;
        }

        // Create an XmlDocument to hold the document contents
        // and load the document contents into the XmlDocument.
        XmlDocument xmlDoc = new();
        XmlNamespaceManager nsManager = new(xmlDoc.NameTable);
        nsManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
        nsManager.AddNamespace("w14", "http://schemas.microsoft.com/office/word/2010/wordml");

        xmlDoc.Load(wordDoc.MainDocumentPart.GetStream());

        // Select all paragraphs in the document and break if none found.
        XmlNodeList? paragraphs = xmlDoc.SelectNodes("//w:p", nsManager);
        if (paragraphs == null)
        {
            yield break;
        }

        // Iterate over each paragraph.
        foreach (XmlNode paragraph in paragraphs)
        {
            // Select all text nodes in the paragraph and continue if none found.
            XmlNodeList? texts = paragraph.SelectNodes(".//w:t", nsManager);
            if (texts == null)
            {
                continue;
            }

            // Combine all non-empty text nodes into a single string.
            var textBuilder = new StringBuilder();
            foreach (XmlNode text in texts)
            {
                if (!string.IsNullOrWhiteSpace(text.InnerText))
                {
                    textBuilder.Append(text.InnerText);
                }
            }

            // Yield a new TextParagraph if the combined text is not empty.
            string combinedText = textBuilder.ToString();
            if (!string.IsNullOrWhiteSpace(combinedText))
            {
                Console.WriteLine("Found paragraph:");
                Console.WriteLine(combinedText);
                Console.WriteLine();

                yield return new TextParagraph
                {
                    Key = Guid.NewGuid().ToString(),
                    DocumentUri = documentUri,
                    ParagraphId = paragraph.Attributes?["w14:paraId"]?.Value ?? string.Empty,
                    Text = combinedText
                };
            }
        }
    }
}

Gömüler oluştur ve verileri karşıya yükle

Ardından eklemeler oluşturmak ve paragrafları Redis'e yüklemek için yeni bir sınıf ekleyebilirsiniz.

Aşağıdaki içeriklere sahip adlı DataUploader.cs yeni bir dosya ekleyin:

internal class DataUploader(
    VectorStore vectorStore,
    IEmbeddingGenerator<string,
    Embedding<float>> embeddingGenerator)
{
    /// <summary>
    /// Generate an embedding for each text paragraph and upload it to the specified collection.
    /// </summary>
    /// <param name="collectionName">The name of the collection to upload the text paragraphs to.</param>
    /// <param name="textParagraphs">The text paragraphs to upload.</param>
    /// <returns>An async task.</returns>
    public async Task GenerateEmbeddingsAndUpload(string collectionName, IEnumerable<TextParagraph> textParagraphs)
    {
        VectorStoreCollection<string, TextParagraph> collection =
            vectorStore.GetCollection<string, TextParagraph>(collectionName);
        await collection.EnsureCollectionExistsAsync();

        foreach (TextParagraph paragraph in textParagraphs)
        {
            // Generate the text embedding.
            Console.WriteLine($"Generating embedding for paragraph: {paragraph.ParagraphId}");
            paragraph.TextEmbedding = (await embeddingGenerator.GenerateAsync(paragraph.Text)).Vector;

            // Upload the text paragraph.
            Console.WriteLine($"Upserting paragraph: {paragraph.ParagraphId}");
            await collection.UpsertAsync(paragraph);

            Console.WriteLine();
        }
    }
}

Hepsini bir araya getirin

Son olarak, farklı parçaları bir araya getirebilirsiniz. Bu örnekte, Redis vektör depoyu ve ekleme oluşturucuyu kaydetmek için standart .NET bağımlılık ekleme özelliğini kullanırsınız.

Kapsayıcıyı ayarlamak, Redis vektör deposunu kaydetmek ve ekleme hizmetini kaydetmek için dosyanıza Program.cs aşağıdaki kodu ekleyin. Metin ekleme oluşturma ayarlarını kendi değerlerinizle değiştirin.

// Replace with your values.
string deploymentName = "text-embedding-ada-002";
string endpoint = "https://someendpoint.openai.azure.com/";
string apiKey = "your-api-key";

// Register Azure OpenAI embedding generator and Redis vector store.
var services = new ServiceCollection();
services.AddSingleton<IEmbeddingGenerator<string, Embedding<float>>>(
    new AzureOpenAIClient(new Uri(endpoint), new AzureKeyCredential(apiKey))
        .GetEmbeddingClient(deploymentName)
        .AsIEmbeddingGenerator());

services.AddRedisVectorStore("localhost:6379");

// Register the data uploader.
services.AddSingleton<DataUploader>();

// Build the service provider and get the data uploader.
ServiceProvider serviceProvider = services.BuildServiceProvider();
DataUploader dataUploader = serviceProvider.GetRequiredService<DataUploader>();

Son olarak, Word belgesinden paragrafları okumak için kod ekleyin ve eklemeleri oluşturmak ve paragrafları karşıya yüklemek için veri yükleyicisini çağırın.

// Load the data.
IEnumerable<TextParagraph> textParagraphs = DocumentReader.ReadParagraphs(
    File.OpenRead("vector-store-data-ingestion-input.docx"),
    "file:///c:/vector-store-data-ingestion-input.docx");

await dataUploader.GenerateEmbeddingsAndUpload(
    "documentation",
    textParagraphs);

Verilerinizi Redis'te görme

Artık yüklediğiniz paragraflarınızı görebilmeniz gereken Redis stack tarayıcısına, örneğin http://localhost:8001/redis-stack/browser, gidin. Aşağıda, yüklenen paragraflardan biri için görmeniz gereken şeylerin bir örneği verilmiştir.

{
    "DocumentUri" : "file:///c:/vector-store-data-ingestion-input.docx",
    "ParagraphId" : "14CA7304",
    "Text" : "Version 1.0+ support across C#, Python, and Java means it’s reliable, committed to non breaking changes. Any existing chat-based APIs are easily expanded to support additional modalities like voice and video.",
    "TextEmbedding" : [...]
}