Cvičení – implementace služby Azure Cosmos DB for NoSQL

Dokončeno

SlužbaCosmosDbService Azure Cosmos DB spravuje dotazování, vytváření, odstraňování a aktualizaci relací a zpráv v aplikaci pomocníka s AI. Ke správě všech těchto operací je služba nutná k implementaci více metod pro každou potenciální operaci pomocí různých funkcí sady .NET SDK.

V tomto cvičení je potřeba splnit několik klíčových požadavků:

  • Implementace operací pro vytvoření relace nebo zprávy
  • Implementace dotazů pro načtení více relací nebo zpráv
  • Implementace operace pro aktualizaci jedné relace nebo dávkové aktualizace více zpráv
  • Implementace operace pro dotazování a odstranění více souvisejících relací a zpráv

Vytvoření relace nebo zprávy

Azure Cosmos DB for NoSQL ukládá data ve formátu JSON, což nám umožňuje ukládat mnoho typů dat do jednoho kontejneru. Tato aplikace ukládá chat "session" s asistentem AI i jednotlivými "zprávami" v rámci každé relace. S rozhraním API pro NoSQL může aplikace ukládat oba typy dat do stejného kontejneru a pak rozlišovat mezi těmito typy pomocí jednoduchého type pole.

  1. Otevřete soubor Services/CosmosDbService.cs.

  2. V rámci InsertSessionAsync této metody odeberte veškerý existující zástupný kód.

    public async Task<Session> InsertSessionAsync(Session session)
    {
    }
    
  3. Vytvořte novou proměnnou s názvem partitionKey typu PartitionKey pomocí vlastnosti aktuální relace SessionId jako parametru.

    PartitionKey partitionKey = new(session.SessionId);
    
  4. CreateItemAsync Vyvolá metodu kontejneru předávajícího session parametr a partitionKey proměnnou. Vrátí odpověď jako výsledek InsertSessionAsync metody.

    return await _container.CreateItemAsync<Session>(
        item: session,
        partitionKey: partitionKey
    ); 
    
  5. V rámci InsertMessageAsync této metody odeberte veškerý existující zástupný kód.

    public async Task<Message> InsertMessageAsync(Message message)
    {
    }
    
  6. Vytvořte proměnnou PartitionKey jako session.SessionId hodnotu klíče oddílu.

    PartitionKey partitionKey = new(message.SessionId);
    
  7. Vytvořte novou proměnnou zprávy s názvem newMessage Timestamp vlastnosti aktualizovanou na aktuální časové razítko UTC.

    Message newMessage = message with { TimeStamp = DateTime.UtcNow };
    
  8. Vyvolání předávání CreateItemAsync proměnných nové zprávy i klíče oddílu. Vrátí odpověď jako výsledek funkce InsertMessageAsync.

    return await _container.CreateItemAsync<Message>(
        item: newMessage,
        partitionKey: partitionKey
    );
    
  9. Uložte soubor Služby/CosmosDbService.cs.

Načtení více relací nebo zpráv

Existují dva hlavní případy použití, kdy aplikace potřebuje načíst více položek z našeho kontejneru. Nejprve aplikace načte všechny relace pro aktuálního uživatele filtrováním položek na ty, kde type = Session. Za druhé, aplikace načte všechny zprávy pro relaci provedením podobného filtru, kde type = Session & sessionId = <current-session-id>. Tady implementujte oba dotazy pomocí sady .NET SDK a iterátoru informačního kanálu.

  1. V rámci GetSessionsAsync této metody odeberte veškerý existující zástupný kód.

    public async Task<List<Session>> GetSessionsAsync()
    {
    }
    
  2. Vytvořte novou proměnnou s názvem query typu QueryDefinition pomocí dotazu SELECT DISTINCT * FROM c WHERE c.type = @typeSQL . Pomocí fluent WithParameter metody přiřaďte název Session třídy jako hodnotu parametru.

    QueryDefinition query = new QueryDefinition("SELECT DISTINCT * FROM c WHERE c.type = @type")
        .WithParameter("@type", nameof(Session));
    
  3. Vyvolá obecnou metodu GetItemQueryIterator<> _container pro proměnnou, která předává obecný typ Session a query proměnnou jako parametr. Uložte výsledek do proměnné typu FeedIterator<Session> s názvem response.

    FeedIterator<Session> response = _container.GetItemQueryIterator<Session>(query);
    
  4. Vytvořte novou obecnou proměnnou seznamu s názvem output.

    List<Session> output = new();
    
  5. Vytvořte smyčku While, která se spustí, dokud response.HasMoreResults nebude splněna.

    while (response.HasMoreResults)
    {
    }
    

    Poznámka:

    Použití smyčky While zde efektivně prochází všechny stránky vaší odpovědi, dokud nezůstane žádné stránky.

  6. Ve smyčce While asynchronně získejte další stránku výsledků vyvoláním ReadNextAsync response proměnné a následným přidáním těchto výsledků do proměnné seznamu s názvem output.

    FeedResponse<Session> results = await response.ReadNextAsync();
    output.AddRange(results);
    
  7. Mimo smyčku While vraťte output proměnnou se seznamem relací jako výsledek GetSessionsAsync metody.

    return output;
    
  8. V rámci GetSessionMessagesAsync této metody odeberte veškerý existující zástupný kód.

    public async Task<List<Message>> GetSessionMessagesAsync(string sessionId)
    {
    }
    
  9. Vytvořte proměnnou query typu QueryDefinition. Použijte dotaz SELECT * FROM c WHERE c.sessionId = @sessionId AND c.type = @typeSQL . Pomocí fluent WithParameter metody přiřaďte @sessionId parametr identifikátoru relace předaného jako parametr a @type parametr názvu Message třídy.

    QueryDefinition query = new QueryDefinition("SELECT * FROM c WHERE c.sessionId = @sessionId AND c.type = @type")
        .WithParameter("@sessionId", sessionId)
        .WithParameter("@type", nameof(Message));
    
  10. Vytvořte FeedIterator<Message> pomocí query proměnné a GetItemQueryIterator<> metody.

    FeedIterator<Message> response = _container.GetItemQueryIterator<Message>(query);
    
  11. K iteraci všech stránek výsledků použijte smyčku While a výsledky uložte do jedné List<Message> proměnné s názvem output.

    List<Message> output = new();
    while (response.HasMoreResults)
    {
        FeedResponse<Message> results = await response.ReadNextAsync();
        output.AddRange(results);
    }
    
  12. Vrátí proměnnou output jako výsledek GetSessionMessagesAsync metody.

    return output;
    
  13. Uložte soubor Služby/CosmosDbService.cs.

Aktualizace jedné nebo více relací nebo zpráv

Existují scénáře, kdy jedna relace vyžaduje aktualizaci nebo více než jedna zpráva vyžaduje aktualizaci. V prvním scénáři použijte ReplaceItemAsync metodu sady SDK k nahrazení existující položky upravenou verzí. Pro druhý scénář použijte transakční dávkovou funkci sady SDK k úpravě více zpráv v jedné dávce.

  1. V rámci UpdateSessionAsync této metody odeberte veškerý existující zástupný kód.

    public async Task<Session> UpdateSessionAsync(Session session)
    {
    }
    
  2. Vytvořte proměnnou PartitionKey jako session.SessionId hodnotu klíče oddílu.

    PartitionKey partitionKey = new(session.SessionId);
    
  3. Vyvolání předání ReplaceItemAsync jedinečného identifikátoru a klíče oddílu nové zprávy. Vrátí odpověď jako výsledek funkce UpdateSessionAsync.

    return await _container.ReplaceItemAsync(
        item: session,
        id: session.Id,
        partitionKey: partitionKey
    );
    
  4. V rámci UpsertSessionBatchAsync této metody odeberte veškerý existující zástupný kód.

    public async Task UpsertSessionBatchAsync(params dynamic[] messages)
    {
    }
    
  5. pomocí jazyka integrovaného dotazu (LINQ) ověřte, že všechny zprávy obsahují jeden identifikátor relace (SessionIdLINQ). Pokud některá ze zpráv obsahuje jinou hodnotu, vyvoláte výjimku ArgumentException.

    if (messages.Select(m => m.SessionId).Distinct().Count() > 1)
    {
        throw new ArgumentException("All items must have the same partition key.");
    }
    
  6. Vytvořte novou PartitionKey proměnnou pomocí SessionId vlastnosti první zprávy.

    PartitionKey partitionKey = new(messages.First().SessionId);
    

    Poznámka:

    Nezapomeňte, že můžete bezpečně předpokládat, že všechny zprávy mají stejný identifikátor relace, pokud se aplikace přesunula do tohoto bodu v kódu metody.

  7. Vytvořte novou proměnnou s názvem batch typu TransactionalBatch vyvoláním CreateTransactionalBatch metody _container proměnné. Pro dávkové operace použijte aktuální proměnnou klíče oddílu.

    TransactionalBatch batch = _container.CreateTransactionalBatch(partitionKey);
    

    Důležité

    Nezapomeňte, že všechny transakce v této dávce by měly být ve stejném logickém oddílu.

  8. Iterujte přes každou zprávu v messages poli pomocí smyčky foreach.

    foreach (var message in messages)
    {
    }
    
  9. Ve smyčce foreach přidejte každou zprávu jako operaci upsertu do dávky.

    batch.UpsertItem(
        item: message
    );
    

    Poznámka:

    Upsert informuje službu Azure Cosmos DB, aby určila, zda má být položka nahrazena nebo aktualizována na straně serveru. Azure Cosmos DB toto rozhodnutí určí pomocí klíče oddílu id každé položky.

  10. Mimo smyčku foreach asynchronně vyvolat ExecuteAsync metodu dávky ke spuštění všech operací v dávce.

    await batch.ExecuteAsync();
    
  11. Uložte soubor Služby/CosmosDbService.cs.

Nakonec zkombinujte dotaz a transakční dávkové funkce, abyste odebrali více položek. V tomto příkladu získejte položku relace a všechny související zprávy dotazováním na všechny položky s konkrétním identifikátorem relace bez ohledu na typ. Pak vytvořte transakční dávku, která odstraní všechny odpovídající položky jako jednu transakci.

  1. V rámci DeleteSessionAndMessagesAsync této metody odeberte veškerý existující zástupný kód.

    public async Task DeleteSessionAndMessagesAsync(string sessionId)
    {
    }
    
  2. Vytvořte proměnnou s názvem partitionKey typu PartitionKey pomocí sesionId řetězcové hodnoty předané jako parametr této metody.

    PartitionKey partitionKey = new(sessionId);
    
  3. Pomocí stejného sessionId parametru metody vytvořte QueryDefinition objekt, který najde všechny položky, které odpovídají identifikátoru relace. Použijte parametr dotazu pro sessionId dotaz a ujistěte se, že dotaz nefiltrujete podle typu položky.

    QueryDefinition query = new QueryDefinition("SELECT VALUE c.id FROM c WHERE c.sessionId = @sessionId")
        .WithParameter("@sessionId", sessionId);
    

    Poznámka:

    Pokud v tomto dotazu použijete type filtr, můžete neúmyslně vynechat související zprávy nebo relace, které by se měly hromadně odebrat jako součást této operace.

  4. Vytvořte nový FeedIterator<string> příkaz pomocí GetItemQueryIterator a dotaz, který jste vytvořili.

    FeedIterator<string> response = _container.GetItemQueryIterator<string>(query);
    
  5. Vytvořte pojmenovanou batch proměnnou TransactionalBatch using CreateTransactionalBatch a klíč oddílu.

    TransactionalBatch batch = _container.CreateTransactionalBatch(partitionKey);
    
  6. Vytvořte smyčku While, která bude iterovat všemi stránkami výsledků. Ve smyčce While získejte další stránku výsledků a pomocí smyčky foreach iterujte všechny identifikátory položek na stránce. V rámci smyčky foreach přidejte dávkovou operaci pro odstranění položky pomocí batch.DeleteItem.

    while (response.HasMoreResults)
    {
        FeedResponse<string> results = await response.ReadNextAsync();
        foreach (var itemId in results)
        {
            batch.DeleteItem(
                id: itemId
            );
        }
    }
    
  7. Po smyčce while spusťte dávku pomocí batch.ExecuteAsync.

    await batch.ExecuteAsync();
    
  8. Uložte soubor Služby/CosmosDbService.cs.

Kontrola práce

Teď má vaše aplikace úplnou implementaci Azure OpenAI a Azure Cosmos DB. Kompletní testování aplikace můžete provést laděním řešení.

  1. Otevřete nový terminál.

  2. Spusťte aplikaci s povoleným opětovným načítáním za provozu pomocí dotnet watch.

    dotnet watch run --non-interactive
    
  3. Visual Studio Code znovu spustí jednoduchý prohlížeč v nástroji se spuštěnou webovou aplikací. Ve webové aplikaci vytvořte novou chatovací relaci a položte asistentovi AI otázku. Pak zavřete spuštěnou webovou aplikaci.

  4. Zavřete terminál. Teď otevřete nový terminál.

  5. Spusťte aplikaci ještě jednou s povoleným opětovným načítáním za provozu pomocí dotnet watch.

    dotnet watch run --non-interactive
    
  6. Visual Studio Code znovu spustí jednoduchý prohlížeč v nástroji se spuštěnou webovou aplikací. U této iterace sledujte, že relace chatu jsou trvalé mezi relacemi ladění.

    Screenshot of the application with both Azure Cosmos DB and Azure OpenAI services implemented.

  7. Zavřete terminál.