تمرين - تنفيذ Azure Cosmos DB لخدمة NoSQL

مكتمل

تدير خدمة Azure Cosmos DB (CosmosDbService) الاستعلام عن الجلسات والرسائل وإنشائه وحذفه وتحديثه في تطبيق مساعد الذكاء الاصطناعي. لإدارة جميع هذه العمليات، تكون الخدمة مطلوبة لتنفيذ أساليب متعددة لكل عملية محتملة باستخدام ميزات مختلفة من .NET SDK.

هناك متطلبات رئيسية متعددة يجب معالجتها في هذا التمرين:

  • تنفيذ العمليات لإنشاء جلسة عمل أو رسالة
  • تنفيذ الاستعلامات لاسترداد جلسات عمل أو رسائل متعددة
  • تنفيذ عملية لتحديث جلسة عمل واحدة أو تحديث دفعة رسائل متعددة
  • تنفيذ عملية للاستعلام عن العديد من الجلسات والرسائل ذات الصلة وحذفها

إنشاء جلسة عمل أو رسالة

يخزن Azure Cosmos DB for NoSQL البيانات بتنسيق JSON مما يسمح لنا بتخزين العديد من أنواع البيانات في حاوية واحدة. يخزن هذا التطبيق كلا من "جلسة" الدردشة مع مساعد الذكاء الاصطناعي و"الرسائل" الفردية داخل كل جلسة عمل. باستخدام واجهة برمجة التطبيقات ل NoSQL، يمكن للتطبيق تخزين كلا النوعين من البيانات في نفس الحاوية ثم التمييز بين هذه الأنواع باستخدام حقل بسيط type .

  1. افتح ملف Services/CosmosDbService.cs .

  2. InsertSessionAsync ضمن الأسلوب ، قم بإزالة أي رمز نائب موجود.

    public async Task<Session> InsertSessionAsync(Session session)
    {
    }
    
  3. إنشاء متغير جديد يسمى partitionKey من النوع PartitionKey باستخدام خاصية جلسة العمل SessionId الحالية كمعلمة.

    PartitionKey partitionKey = new(session.SessionId);
    
  4. CreateItemAsync استدعاء أسلوب الحاوية التي تمر في المعلمة session والمتغيرpartitionKey. إرجاع الاستجابة كنتيجة للأسلوب InsertSessionAsync .

    return await _container.CreateItemAsync<Session>(
        item: session,
        partitionKey: partitionKey
    ); 
    
  5. InsertMessageAsync ضمن الأسلوب ، قم بإزالة أي رمز نائب موجود.

    public async Task<Message> InsertMessageAsync(Message message)
    {
    }
    
  6. PartitionKey إنشاء متغير باستخدام session.SessionId كقيمة لمفتاح القسم.

    PartitionKey partitionKey = new(message.SessionId);
    
  7. قم بإنشاء متغير رسالة جديد باسم newMessage مع Timestamp خاصية محدثة إلى الطابع الزمني الحالي UTC.

    Message newMessage = message with { TimeStamp = DateTime.UtcNow };
    
  8. CreateItemAsync استدعاء تمرير في كل من متغيرات مفتاح التقسيم والرسالة الجديدة. إرجاع الاستجابة كنتيجة ل InsertMessageAsync.

    return await _container.CreateItemAsync<Message>(
        item: newMessage,
        partitionKey: partitionKey
    );
    
  9. احفظ ملف Services/CosmosDbService.cs.

استرداد جلسات عمل أو رسائل متعددة

هناك حالتان رئيسيتان للاستخدام حيث يحتاج التطبيق إلى استرداد عناصر متعددة من حاويتنا. أولا، يسترد التطبيق جميع جلسات العمل للمستخدم الحالي عن طريق تصفية العناصر إلى العناصر حيث type = Session. ثانيا، يسترد التطبيق جميع الرسائل لجلسة عمل عن طريق تنفيذ عامل تصفية مشابه حيث type = Session & sessionId = <current-session-id>. تنفيذ كلا الاستعلامين هنا باستخدام .NET SDK ومكرر الخلاصة.

  1. GetSessionsAsync ضمن الأسلوب ، قم بإزالة أي رمز نائب موجود.

    public async Task<List<Session>> GetSessionsAsync()
    {
    }
    
  2. إنشاء متغير جديد يسمى query من النوع QueryDefinition باستخدام استعلام SELECT DISTINCT * FROM c WHERE c.type = @typeSQL . استخدم الأسلوب بطلاقة WithParameter لتعيين اسم Session الفئة كقيمة للمعلمة .

    QueryDefinition query = new QueryDefinition("SELECT DISTINCT * FROM c WHERE c.type = @type")
        .WithParameter("@type", nameof(Session));
    
  3. استدعاء الأسلوب العام GetItemQueryIterator<> على المتغير الذي _container يمر في النوع Session العام والمتغير query كمعلمة. تخزين النتيجة في متغير من النوع FeedIterator<Session> المسمى response.

    FeedIterator<Session> response = _container.GetItemQueryIterator<Session>(query);
    
  4. إنشاء متغير قائمة عام جديد باسم output.

    List<Session> output = new();
    
  5. إنشاء تكرار حلقي لفترة زمنية يتم تشغيله حتى response.HasMoreResults لا يعود صحيحا.

    while (response.HasMoreResults)
    {
    }
    

    إشعار

    سيؤدي استخدام التكرار الحلقي في حين هنا إلى تكرار التكرار الحلقي بشكل فعال عبر جميع صفحات الاستجابة حتى لا تبقى صفحات.

  6. ضمن التكرار الحلقي while، احصل بشكل غير متزامن على الصفحة التالية من النتائج عن طريق استدعاء ReadNextAsync على response المتغير ثم أضف هذه النتائج إلى متغير القائمة المسمى output.

    FeedResponse<Session> results = await response.ReadNextAsync();
    output.AddRange(results);
    
  7. خارج التكرار الحلقي while، قم بإرجاع output المتغير بقائمة جلسات العمل كنتيجة للأسلوب GetSessionsAsync .

    return output;
    
  8. GetSessionMessagesAsync ضمن الأسلوب ، قم بإزالة أي رمز نائب موجود.

    public async Task<List<Message>> GetSessionMessagesAsync(string sessionId)
    {
    }
    
  9. query إنشاء متغير من النوع QueryDefinition. استخدم استعلام SELECT * FROM c WHERE c.sessionId = @sessionId AND c.type = @typeSQL . استخدم الأسلوب بطلاقة WithParameter لتعيين المعلمة @sessionId إلى معرف جلسة العمل الذي تم تمريره كمعلمة، والمعلمة @type إلى اسم Message الفئة.

    QueryDefinition query = new QueryDefinition("SELECT * FROM c WHERE c.sessionId = @sessionId AND c.type = @type")
        .WithParameter("@sessionId", sessionId)
        .WithParameter("@type", nameof(Message));
    
  10. FeedIterator<Message> إنشاء باستخدام query المتغير والأسلوب GetItemQueryIterator<> .

    FeedIterator<Message> response = _container.GetItemQueryIterator<Message>(query);
    
  11. استخدم حلقة while للتكرار عبر جميع صفحات النتائج وتخزين النتائج في متغير واحد List<Message> يسمى output.

    List<Message> output = new();
    while (response.HasMoreResults)
    {
        FeedResponse<Message> results = await response.ReadNextAsync();
        output.AddRange(results);
    }
    
  12. output إرجاع المتغير كنتيجة للأسلوب GetSessionMessagesAsync .

    return output;
    
  13. احفظ ملف Services/CosmosDbService.cs.

تحديث جلسة عمل أو رسالة واحدة أو أكثر

هناك سيناريوهات عندما تتطلب جلسة عمل واحدة تحديثا أو تتطلب أكثر من رسالة تحديثا. بالنسبة للسيناريو الأول، استخدم ReplaceItemAsync أسلوب SDK لاستبدال عنصر موجود بإصدار معدل. بالنسبة للسيناريو الثاني، استخدم إمكانية دفعة المعاملات ل SDK لتعديل رسائل متعددة في دفعة واحدة.

  1. UpdateSessionAsync ضمن الأسلوب ، قم بإزالة أي رمز نائب موجود.

    public async Task<Session> UpdateSessionAsync(Session session)
    {
    }
    
  2. PartitionKey إنشاء متغير باستخدام session.SessionId كقيمة لمفتاح القسم.

    PartitionKey partitionKey = new(session.SessionId);
    
  3. ReplaceItemAsync استدعاء التمرير في المعرف الفريد للرسالة الجديدة ومفتاح القسم. إرجاع الاستجابة كنتيجة ل UpdateSessionAsync.

    return await _container.ReplaceItemAsync(
        item: session,
        id: session.Id,
        partitionKey: partitionKey
    );
    
  4. UpsertSessionBatchAsync ضمن الأسلوب ، قم بإزالة أي رمز نائب موجود.

    public async Task UpsertSessionBatchAsync(params dynamic[] messages)
    {
    }
    
  5. تحقق من أن جميع الرسائل تحتوي على معرف جلسة عمل واحد (SessionId) باستخدام استعلام متكامل اللغة (LINQ). إذا كانت أي من الرسائل تحتوي على قيمة مختلفة، فقم بطرح ArgumentException.

    if (messages.Select(m => m.SessionId).Distinct().Count() > 1)
    {
        throw new ArgumentException("All items must have the same partition key.");
    }
    
  6. إنشاء متغير جديد PartitionKey باستخدام SessionId خاصية للرسالة الأولى.

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

    إشعار

    تذكر، يمكنك افتراض أن جميع الرسائل لها نفس معرف جلسة العمل إذا كان التطبيق قد انتقل إلى هذه النقطة في التعليمات البرمجية للأسلوب.

  7. إنشاء متغير جديد يسمى batch من النوع TransactionalBatch عن طريق استدعاء CreateTransactionalBatch أسلوب _container المتغير. استخدم متغير مفتاح القسم الحالي لعمليات الدفعة.

    TransactionalBatch batch = _container.CreateTransactionalBatch(partitionKey);
    

    هام

    تذكر أن جميع المعاملات داخل هذه الدفعة يجب أن تكون في نفس القسم المنطقي.

  8. التكرار فوق كل رسالة في messages الصفيف باستخدام حلقة foreach.

    foreach (var message in messages)
    {
    }
    
  9. ضمن حلقة foreach، أضف كل رسالة كلعملية upsert إلى الدفعة.

    batch.UpsertItem(
        item: message
    );
    

    إشعار

    يخبر Upsert Azure Cosmos DB بتحديد ما إذا كان يجب استبدال عنصر أو تحديثه، من جانب الخادم. سيقوم Azure Cosmos DB بإجراء هذا التحديد باستخدام id و مفتاح القسم لكل عنصر.

  10. خارج حلقة foreach، استدع ExecuteAsync أسلوب الدفعة بشكل غير متزامن لتنفيذ جميع العمليات داخل الدفعة.

    await batch.ExecuteAsync();
    
  11. احفظ ملف Services/CosmosDbService.cs.

وأخيرا، اجمع بين وظيفة الاستعلام ووظيفة دفعة المعاملات لإزالة عناصر متعددة. في هذا المثال، احصل على عنصر جلسة العمل وكافة الرسائل ذات الصلة عن طريق الاستعلام عن جميع العناصر باستخدام معرف جلسة عمل معين بغض النظر عن النوع. ثم قم بإنشاء دفعة معاملات لحذف جميع العناصر المتطابقة كمعاملة واحدة.

  1. DeleteSessionAndMessagesAsync ضمن الأسلوب ، قم بإزالة أي رمز نائب موجود.

    public async Task DeleteSessionAndMessagesAsync(string sessionId)
    {
    }
    
  2. إنشاء متغير يسمى partitionKey من النوع PartitionKey باستخدام قيمة السلسلة التي sesionId تم تمريرها كمعلمة إلى هذا الأسلوب.

    PartitionKey partitionKey = new(sessionId);
    
  3. باستخدام نفس sessionId معلمة الأسلوب، قم بإنشاء كائن QueryDefinition يعثر على كافة العناصر التي تطابق معرف جلسة العمل. استخدم معلمة استعلام ل sessionId وتأكد من عدم تصفية الاستعلام على نوع العنصر.

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

    إشعار

    إذا قمت بتطبيق عامل type تصفية في هذا الاستعلام، فقد تفوت عن غير قصد الرسائل أو الجلسات ذات الصلة التي يجب إزالتها بشكل مجمع كجزء من هذه العملية.

  4. إنشاء جديد FeedIterator<string> باستخدام GetItemQueryIterator والاستعلام الذي أنشأته.

    FeedIterator<string> response = _container.GetItemQueryIterator<string>(query);
    
  5. إنشاء مسمى TransactionalBatch batch باستخدام CreateTransactionalBatch ومتغير مفتاح القسم.

    TransactionalBatch batch = _container.CreateTransactionalBatch(partitionKey);
    
  6. إنشاء تكرار حلقي للتكرار عبر جميع صفحات النتائج. ضمن التكرار الحلقي while، احصل على الصفحة التالية من النتائج واستخدم حلقة foreach للتكرار من خلال جميع معرفات العناصر لكل صفحة. ضمن حلقة foreach، أضف عملية دفعة لحذف العنصر باستخدام batch.DeleteItem.

    while (response.HasMoreResults)
    {
        FeedResponse<string> results = await response.ReadNextAsync();
        foreach (var itemId in results)
        {
            batch.DeleteItem(
                id: itemId
            );
        }
    }
    
  7. بعد التكرار الحلقي أثناء، قم بتنفيذ الدفعة باستخدام batch.ExecuteAsync.

    await batch.ExecuteAsync();
    
  8. احفظ ملف Services/CosmosDbService.cs.

راجع عملك

الآن التطبيق الخاص بك لديه تنفيذ كامل من Azure OpenAI وAzure Cosmos DB. يمكنك اختبار التطبيق من طرف إلى طرف عن طريق تصحيح أخطاء الحل.

  1. افتح محطة طرفية جديدة.

  2. ابدأ تشغيل التطبيق مع تمكين عمليات إعادة التحميل السريع باستخدام dotnet watch.

    dotnet watch run --non-interactive
    
  3. يقوم Visual Studio Code بتشغيل المتصفح البسيط داخل الأداة مرة أخرى مع تشغيل تطبيق الويب. في تطبيق الويب، أنشئ جلسة دردشة جديدة واطرح سؤالا على مساعد الذكاء الاصطناعي. ثم أغلق تطبيق الويب قيد التشغيل.

  4. أغلق المحطة الطرفية. الآن، افتح محطة طرفية جديدة.

  5. ابدأ تشغيل التطبيق مرة أخرى مع تمكين عمليات إعادة التحميل الساخنة باستخدام dotnet watch.

    dotnet watch run --non-interactive
    
  6. يقوم Visual Studio Code بتشغيل المتصفح البسيط داخل الأداة مرة أخرى مع تشغيل تطبيق الويب. لهذا التكرار، لاحظ أن جلسات الدردشة الخاصة بك مستمرة بين جلسات تصحيح الأخطاء.

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

  7. أغلق المحطة الطرفية.