البرنامج التعليمي: استخدام ".NET" والذكاء الاصطناعي لإنشاء محتوى قابل للبحث من "Azure blobs"

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

في هذا البرنامج التعليمي C#، ستتعلم كيفية:

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

في حال لم تكن مشتركاً في "Azure"، افتح حساب مجاني قبل البدء.

نظرة عامة

يستخدم هذا البرنامج التعليمي لغة C#‎ Azure.Search.Documentsومكتبة عميللإنشاء مصدر بيانات وفهرس ومفهرس ومجموعة مهارات.

يتصل المفهرس بنموذج البيانات في حاوية كائن ثنائي كبير الحجم المحددة في كائن مصدر البيانات، ويرسل جميع المحتويات التي تم إثراؤها إلى فهرس بحث.

مجموعة المهارات مرفقة بالمفهرس. يستخدم مهارات مُضمَّنة من Microsoft للعثور على المعلومات واستخراجها. تشمل الخطوات قيد التنفيذ التعرف البصري على الحروف (OCR) على الصور، واكتشاف اللغة في النص، واستخراج العبارة الرئيسية، والتعرف على الكيانات (المؤسسات). تُخزَّن المعلومات الجديدة التي أنشأها التدفق في حقولٍ جديدةٍ في فهرس. بمجرد ملء الفهرس، يمكنك استخدام الحقول في الاستعلامات والوجهات وعوامل التصفية.

المتطلبات الأساسية

ملاحظة

يمكنك استخدام خدمة البحث المجانية لهذا البرنامج التعليمي. تقصرك خدمة البحث المجانية على ثلاثة فهارس وثلاثة مفهرسات وثلاثة مصادر بيانات. ينشئ هذا البرنامج التعليمي واحدًا من كلٍّ منها. قبل البدء، تأكد من أن لديك مساحة في خدمتك لقبول الموارد الجديدة.

تنزيل الملفات

تتكون بيانات العينة من 14 ملفاً من نوع المحتوى المختلط الذي ستحمله إلى Azure Blob Storage في خطوةٍ لاحقةٍ.

  1. احصل على الملفات من azure-search-sample-data/ai-enrichment-mixed-media/ وانسخها إلى الكمبيوتر المحلي.

  2. بعد ذلك، احصل على التعليمات البرمجية المصدر لهذا البرنامج التعليمي. التعليمة البرمجية المصدر موجودة في المجلد tutorial-ai-enrichment/v11 في المستودع azure-search-dotnet-samples.

1 - إنشاء الخدمات

هذا البرنامج التعليمي يستخدم Azure Cognitive Search للفهرسة والاستعلامات، وAzure Blob Storage لتوفير البيانات. يظل هذا البرنامج التعليمي خاضعًا للتخصيص المجاني لـ 20 معاملة لكل مفهرس يوميًّا على الخدمات المعرفية، ومن ثَم فإن الخدمات الوحيدة التي تحتاج إلى إنشائها هي البحث والتخزين.

إن أمكن، بادر بإنشائها في نفس المنطقة ومجموعة الموارد من أجل التقارب وسهولة الإدارة. من الناحية العملية، يمكن أن يكون حساب Azure Storage خاصتك في أي منطقة.

ابدأ بـ Azure Storage

  1. سجل في مدخل Azureثم انقر فوق + Create Resource.

  2. ابحث عن حساب التخزين وحدد عرض حساب التخزين من Microsoft.

    Create Storage account

  3. في علامة التبويب "Basics"، تعد العناصر التالية مطلوبة. اقبل الإعدادات الافتراضية لكل شيء آخر.

    • ⁦⁧⁩⁩مجموعة الموارد⁦⁧⁩⁩. حدد واحدة موجودة أو أنشئ واحدة جديدة، لكن استخدم نفس المجموعة لجميع الخدمات حتى تتمكن من إدارتها بشكلٍ جماعي.

    • ⁩اسم حساب التخزين⁧⁩. إذا كنت تعتقد أنه قد تكون لديك موارد متعددة من نفس النوع، فاستخدم الاسم لإزالة الغموض حسب النوع والمنطقة، على سبيل المثال blobstoragewestus.

    • Location. إذا أمكن، اختر نفس الموقع المستخدم لـ Azure Cognitive Search وCognitive Services. موقع واحد يفرغ رسوم النطاق الترددي.

    • نوع الحساب. اختر الإعداد الافتراضي، StorageV2 (الغرض العام v2) .

  4. حدد مراجعة + إنشاء لإنشاء الخدمة.

  5. بمجرد إنشائه، حدد الانتقال إلى المورد لفتح صفحة نظرة عامة.

  6. حدد خدمة Blobs .

  7. حدد + Container لإنشاء حاوية وسمها cog-search-demo.

  8. حدد cog-search-demo ثم حدد Upload لفتح المجلد حيث قمت بحفظ ملفات التنزيل. حدد كافة الملفات. حدد ⁧⁩تحميل⁧⁩.

    Screenshot of the files in File Explorer.

  9. قبل مغادرة Azure Storage، احصل على سلسلة اتصال حتى تتمكن من صياغة اتصال فيAzure Cognitive Search.

    1. استعرض مرةً أخرى صفحة "Overview" لحساب التخزين خاصتك (استخدمنا blobstoragewestus كمثال).

    2. في جزء التنقل الأيسر، حدد Access keys وانسخ إحدى سلاسل الاتصال.

    سلسلة الاتصال هي عنوان URL مشابه للمثال التالي:

    DefaultEndpointsProtocol=https;AccountName=cogsrchdemostorage;AccountKey=<your account key>;EndpointSuffix=core.windows.net
    
  10. حفظ سلسلة الاتصال إلى Notepad. ستحتاج إليه لاحقًا عند إعداد اتصال مصدر البيانات.

Cognitive Services

تدعم الخدمات المعرفية إثراء الذكاء الاصطناعي، بما في ذلك خدمة اللغة ورؤية الكمبيوتر للغة الطبيعية ومعالجة الصور. إذا كان هدفك هو إكمال نموذج أو مشروع فعلي، فيمكنك في هذه المرحلة توفيرCognitive Services (في نفس المنطقة مثل Azure Cognitive Search) بحيث يمكنك إرفاقها بعمليات الفهرسة.

ومع ذلك، بالنسبة لهذا التمرين، يمكنك تخطي توفير الموارد لأن Azure Cognitive Search يمكنه الاتصال بـ Cognitive Services خلف الكواليس ومنحك 20 معاملة مجانية لكل تشغيل مفهرس. نظراً لأن هذا البرنامج التعليمي يستخدم 14 معاملة، فإن التخصيص المجاني كافٍ. بالنسبة للمشاريع الأكبر حجماً، خطط لتوفير Cognitive Services على مستوى الدفع عند الاستخدام S0. لمزيد من المعلومات، يُرجى الاطلاع على Azure Cognitive Services.

المكون الثالث هو Azure Cognitive Search، الذي يمكنك إنشاؤه في المدخل أو البحث عن خدمة بحث موجودة في اشتراكك.

يمكنك استخدام المستوى المجاني لإكمال هذه المعاينة.

للتفاعل مع خدمة Azure Cognitive Search، ستحتاج إلى عنوان URL للخدمة ومفتاح وصول.

  1. سجل الدخول إلى مدخل Azure، وفي الصفحة Overviewعلى خدمة البحث لديك، احصل على اسم خدمة البحث الخاصة بك. يمكنك تأكيد اسم الخدمة الخاصة بك من خلال مراجعة عنوان URL لنقطة النهاية. إذا كان عنوان URL لنقطة النهاية هي https://mydemo.search.windows.net، فسيكون اسم الخدمة الخاصة بك هو mydemo.

  2. في Settings>Keys، احصل على مفتاح مسؤول للحصول على الحقوق الكاملة في الخدمة. يمكنك نسخ المفتاح الأساسي أو الثانوي.

Get the service name and admin key

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

2 - إعداد بيئتك

ابدأ بفتح Visual Studio وإنشاء مشروع Console App جديد يمكن تشغيله على .NET Core.

ثبت Azure.Search.Documents

يتكون Azure Cognitive Search .NET SDK من مكتبة عميل تتيح لك إدارة الفهارس ومصادر البيانات والمفهرسات ومجموعات المهارات، بالإضافة إلى تحميل المستندات وإدارتها وتنفيذ الاستعلامات، كل ذلك دون الحاجة إلى التعامل مع تفاصيل HTTP وJSON. مكتبة العميل هذه مُوزعة باعتبارها حزمة NuGet.

بالنسبة لهذا المشروع، بادر بتثبيت الإصدار 11 أو أحدث من Azure.Search.Documents والإصدار الأحدث من Microsoft.Extensions.Configuration.

  1. في Visual Studio، حدد Tools>NuGet Package Manager>Manage NuGet Packages for Solution...

  2. استعرض بحثاً عن Azure.Search.Document.

  3. حدد أحدث إصدار ثم انقر فوق Install.

  4. كرر الخطوات السابقة لتثبيت Microsoft.Extensions.Configuration و Microsoft.Extensions.Configuration.Json.

إضافة معلومات الاتصال بالخدمة

  1. انقر بزر الفأرة الأيمن فوق مشروعك في مستكشف الحلول، وحدد Add>New Item... .

  2. بادر بتسمية الملف appsettings.json وحدد Add.

  3. بادر بتضمين هذا الملف في دليل الإخراج خاصتك.

    1. انقر بزر الفأرة الأيمن فوق appsettings.json وحدد Properties.
    2. غيَّر القيمة Copy to Output Directory إلى Copy if newer.
  4. انسخ JSON أدناه إلى ملف JSON الجديد خاصتك.

    {
      "SearchServiceUri": "Put your search service URI here",
      "SearchServiceAdminApiKey": "Put your primary or secondary API key here",
      "SearchServiceQueryApiKey": "Put your query API key here",
      "AzureBlobConnectionString": "Put your Azure Blob connection string here",
    }
    

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

لـ SearchServiceUri، أدخِل عنوان URL الكامل.

أضِف مساحات الأسماء

داخل Program.cs أضِف مساحات الأسماء التالية.

using Azure;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;

namespace EnrichwithAI

أنشئ عميل

أنشئ مثيلاً لـ SearchIndexClient و SearchIndexerClient أسفل Main.

public static void Main(string[] args)
{
    // Create service client
    IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
    IConfigurationRoot configuration = builder.Build();

    string searchServiceUri = configuration["SearchServiceUri"];
    string adminApiKey = configuration["SearchServiceAdminApiKey"];
    string cognitiveServicesKey = configuration["CognitiveServicesKey"];

    SearchIndexClient indexClient = new SearchIndexClient(new Uri(searchServiceUri), new AzureKeyCredential(adminApiKey));
    SearchIndexerClient indexerClient = new SearchIndexerClient(new Uri(searchServiceUri), new AzureKeyCredential(adminApiKey));
}

ملاحظة

يتصل العملاء بخدمة البحث خاصتك. لتجنب فتح الكثير من الاتصالات، يجب أن تحاول مشاركة مثيل واحد في تطبيقك إن أمكن. الطرق هي قاسمٌ آمنٌ لتمكين مثل هذه المشاركة.

أضف دالة للخروج من البرنامج أثناء الفشل

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

أضِف ExitProgram إلى Main للتعامل مع السيناريوهات التي تتطلب إنهاء البرنامج.

private static void ExitProgram(string message)
{
    Console.WriteLine("{0}", message);
    Console.WriteLine("Press any key to exit the program...");
    Console.ReadKey();
    Environment.Exit(0);
}

3- إنشاء التدفق

في Azure Cognitive Search، تحدث معالجة الذكاء الاصطناعي أثناء الفهرسة (أو استيعاب البيانات). ينشئ هذا الجزء من الإرشادات أربعة كائنات: مصدر البيانات، وتعريف الفهرس، ومجموعة المهارات، والمفهرس.

الخطوة 1: إنشاء مصدر بيانات

SearchIndexerClient لديه خاصية DataSourceName يمكنك تعيينها لكائن SearchIndexerDataSourceConnection. يوفر هذا الكائن جميع الأساليب التي تحتاجها لإنشاء مصادر بيانات Azure Cognitive Search أو سردها أو تحديثها أو حذفها.

إنشاء مثيل SearchIndexerDataSourceConnection جديد عن طريق استدعاء indexerClient.CreateOrUpdateDataSourceConnection(dataSource). تُنشئ التعليمات البرمجية التالية مصدر بيانات من النوع AzureBlob.

private static SearchIndexerDataSourceConnection CreateOrUpdateDataSource(SearchIndexerClient indexerClient, IConfigurationRoot configuration)
{
    SearchIndexerDataSourceConnection dataSource = new SearchIndexerDataSourceConnection(
        name: "demodata",
        type: SearchIndexerDataSourceType.AzureBlob,
        connectionString: configuration["AzureBlobConnectionString"],
        container: new SearchIndexerDataContainer("cog-search-demo"))
    {
        Description = "Demo files to demonstrate cognitive search capabilities."
    };

    // The data source does not need to be deleted if it was already created
    // since we are using the CreateOrUpdate method
    try
    {
        indexerClient.CreateOrUpdateDataSourceConnection(dataSource);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Failed to create or update the data source\n Exception message: {0}\n", ex.Message);
        ExitProgram("Cannot continue without a data source");
    }

    return dataSource;
}

لطلبٍ ناجح، سيعيد الأسلوب مصدر البيانات الذي جرى إنشاؤه. إذا كانت هناك مشكلة في الطلب، مثل معلمة غير صالحة، فإن الطريقة ستطرح استثناءً.

أضف الآن سطراً في Main لاستدعاء الدالة CreateOrUpdateDataSource التي أضفتها للتو.

// Create or Update the data source
Console.WriteLine("Creating or updating the data source...");
SearchIndexerDataSourceConnection dataSource = CreateOrUpdateDataSource(indexerClient, configuration);

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

Data sources tile in the portal

الخطوة 2: إنشاء مجموعة مهارات

في هذا القسم، تحدد مجموعة من خطوات الإثراء التي تريد تطبيقها على بياناتك. تُسمى كل خطوة إثراء مهارة وتُسمى مجموعة خطوات الإثراء بـ مجموعة مهارة. يستخدم هذا البرنامج التعليمي المهارات المعرفية المُضمَّنة لمجموعة المهارات:

  • التعرف البصري على الحروف (OCR) للتعرف على النص المطبوع والمكتوب بخط اليد في ملفات الصور.

  • دمج النص لدمج النص من مجموعة من الحقول في حقل "محتوى مدمج" واحد.

  • الكشف عن اللغة لتعريف لغة المحتوى.

  • التعرف على الكيان لاستخراج أسماء المؤسسات من المحتوى الموجود في حاوية البيانات الثنائية كبيرة الحجم.

  • تقسيم النصوصلتقسيم المحتوى الكبير إلى أجزاء أصغر قبل استدعاء مهارة استخراج العبارة الرئيسية ومهارة التعرف على الكيان. يقبل استخراج العبارة الرئيسية والتعرف على الكيان إدخالات من 50000 حرفٍ أو أقل. يحتاج عددٌ قليلٌ من عينات الملفات إلى تقسيمها لتلائم هذا الحد.

  • استخراج العبارة الرئيسيةلسحب العبارات الرئيسية.

أثناء المعالجة الأولية، يِشق Azure Cognitive Search كل مستند لاستخراج المحتوى من تنسيقات ملفات مختلفة. يُوضع النص الذي أُنشئ في الملف المصدر في حقل content المُنشأ، واحدٌ لكل مستند. على هذا النحو، عيِّن الإدخال إلى "/document/content"لاستخدام هذا النص. يُوضع محتوى الصورة في حقل normalized_images المُنشأ، محدد في مجموعة مهارات مثل/document/normalized_images/*.

يمكن تعيين المخرجات إلى فهرس، أو استخدامها كمدخل لمهارة انتقال البيانات من الخادم، أو كليهما كما هو الحال مع تعليمة اللغة البرمجية. في الفهرس، يكون رمز اللغة مفيداً للتصفية. كمدخل، يُستخدم رمز اللغة بواسطة مهارات تحليل النص لإبلاغ القواعد اللغوية عن كسر الكلمات.

لمزيد من المعلومات عن أساسيات مجموعة المهارات، راجع كيف تعرف مجموعة مهارات.

مهارة التعرف البصري على الحروف (OCR)

OcrSkillيستخرج النص من صور. تفترض هذه المهارة وجود حقل "normalized_images". لإنشاء هذا الحقل، سنعين لاحقاً في البرنامج التعليمي التكوين "imageAction"في تعريف المفهرس إلى "generateNormalizedImages".

private static OcrSkill CreateOcrSkill()
{
    List<InputFieldMappingEntry> inputMappings = new List<InputFieldMappingEntry>();
    inputMappings.Add(new InputFieldMappingEntry("image")
    {
        Source = "/document/normalized_images/*"
    });

    List<OutputFieldMappingEntry> outputMappings = new List<OutputFieldMappingEntry>();
    outputMappings.Add(new OutputFieldMappingEntry("text")
    {
        TargetName = "text"
    });

    OcrSkill ocrSkill = new OcrSkill(inputMappings, outputMappings)
    {
        Description = "Extract text (plain and structured) from image",
        Context = "/document/normalized_images/*",
        DefaultLanguageCode = OcrSkillLanguage.En,
        ShouldDetectOrientation = true
    };

    return ocrSkill;
}

مهارة الدمج

في هذا القسم، ستنشئ حقلاً MergeSkill يدمج حقل محتوى المستند مع النص الذي أُنتِج بواسطة مهارة التعرف البصري على الحروف (OCR).

private static MergeSkill CreateMergeSkill()
{
    List<InputFieldMappingEntry> inputMappings = new List<InputFieldMappingEntry>();
    inputMappings.Add(new InputFieldMappingEntry("text")
    {
        Source = "/document/content"
    });
    inputMappings.Add(new InputFieldMappingEntry("itemsToInsert")
    {
        Source = "/document/normalized_images/*/text"
    });
    inputMappings.Add(new InputFieldMappingEntry("offsets")
    {
        Source = "/document/normalized_images/*/contentOffset"
    });

    List<OutputFieldMappingEntry> outputMappings = new List<OutputFieldMappingEntry>();
    outputMappings.Add(new OutputFieldMappingEntry("mergedText")
    {
        TargetName = "merged_text"
    });

    MergeSkill mergeSkill = new MergeSkill(inputMappings, outputMappings)
    {
        Description = "Create merged_text which includes all the textual representation of each image inserted at the right location in the content field.",
        Context = "/document",
        InsertPreTag = " ",
        InsertPostTag = " "
    };

    return mergeSkill;
}

مهارة الكشف عن اللغة

LanguageDetectionSkill يكتشف لغة نص الإدخال ويبلغ عن تعليمة لغة برمجية واحدة لكل مستند يُرسل عند الطلب. سنستخدم إخراج مهارة الكشف عن اللغة باعتباره جزءاً من إدخال مهارة تقسيم النصوص.

private static LanguageDetectionSkill CreateLanguageDetectionSkill()
{
    List<InputFieldMappingEntry> inputMappings = new List<InputFieldMappingEntry>();
    inputMappings.Add(new InputFieldMappingEntry("text")
    {
        Source = "/document/merged_text"
    });

    List<OutputFieldMappingEntry> outputMappings = new List<OutputFieldMappingEntry>();
    outputMappings.Add(new OutputFieldMappingEntry("languageCode")
    {
        TargetName = "languageCode"
    });

    LanguageDetectionSkill languageDetectionSkill = new LanguageDetectionSkill(inputMappings, outputMappings)
    {
        Description = "Detect the language used in the document",
        Context = "/document"
    };

    return languageDetectionSkill;
}

مهارة تقسيم النصوص

سيُقسَّم SplitSkill النص أدناه إلى صفحات ويحدد طول الصفحة إلى 4000 حرف حسبما يُقاس بواسطة String.Length. ستحاول الخوارزمية تقسيم النص إلى أجزاء ذات حجم maximumPageLength على الأكثر. في هذه الحالة، ستبذل الخوارزمية قصارى جهدها لتقسيم الجملة في حدود الجملة، وبالتالي قد يكون حجم القطعة أقل بقليل من maximumPageLength.

private static SplitSkill CreateSplitSkill()
{
    List<InputFieldMappingEntry> inputMappings = new List<InputFieldMappingEntry>();
    inputMappings.Add(new InputFieldMappingEntry("text")
    {
        Source = "/document/merged_text"
    });
    inputMappings.Add(new InputFieldMappingEntry("languageCode")
    {
        Source = "/document/languageCode"
    });

    List<OutputFieldMappingEntry> outputMappings = new List<OutputFieldMappingEntry>();
    outputMappings.Add(new OutputFieldMappingEntry("textItems")
    {
        TargetName = "pages",
    });

    SplitSkill splitSkill = new SplitSkill(inputMappings, outputMappings)
    {
        Description = "Split content into pages",
        Context = "/document",
        TextSplitMode = TextSplitMode.Pages,
        MaximumPageLength = 4000,
        DefaultLanguageCode = SplitSkillLanguage.En
    };

    return splitSkill;
}

مهارة التعرف على الكيان

هذا المثيل EntityRecognitionSkill مُعين للتعرف على نوع الفئة organization. EntityRecognitionSkill يمكنه التعرف على أنواع الفئات person و location.

لاحظ تعيين حقل "السياق" إلى "/document/pages/*" بعلامة النجمة، مما يُعني استدعاء خطوة الإثراء لكل صفحة تحتها "/document/pages".

private static EntityRecognitionSkill CreateEntityRecognitionSkill()
{
    List<InputFieldMappingEntry> inputMappings = new List<InputFieldMappingEntry>();
    inputMappings.Add(new InputFieldMappingEntry("text")
    {
        Source = "/document/pages/*"
    });

    List<OutputFieldMappingEntry> outputMappings = new List<OutputFieldMappingEntry>();
    outputMappings.Add(new OutputFieldMappingEntry("organizations")
    {
        TargetName = "organizations"
    });

    EntityRecognitionSkill entityRecognitionSkill = new EntityRecognitionSkill(inputMappings, outputMappings)
    {
        Description = "Recognize organizations",
        Context = "/document/pages/*",
        DefaultLanguageCode = EntityRecognitionSkillLanguage.En
    };
    entityRecognitionSkill.Categories.Add(EntityCategory.Organization);

    return entityRecognitionSkill;
}

مهارة استخراج العبارة الرئيسية

مثل المثيل EntityRecognitionSkill الذي أُنشئ للتو، يُستدعى KeyPhraseExtractionSkill لكل صفحة من المستند.

private static KeyPhraseExtractionSkill CreateKeyPhraseExtractionSkill()
{
    List<InputFieldMappingEntry> inputMappings = new List<InputFieldMappingEntry>();
    inputMappings.Add(new InputFieldMappingEntry("text")
    {
        Source = "/document/pages/*"
    });
    inputMappings.Add(new InputFieldMappingEntry("languageCode")
    {
        Source = "/document/languageCode"
    });

    List<OutputFieldMappingEntry> outputMappings = new List<OutputFieldMappingEntry>();
    outputMappings.Add(new OutputFieldMappingEntry("keyPhrases")
    {
        TargetName = "keyPhrases"
    });

    KeyPhraseExtractionSkill keyPhraseExtractionSkill = new KeyPhraseExtractionSkill(inputMappings, outputMappings)
    {
        Description = "Extract the key phrases",
        Context = "/document/pages/*",
        DefaultLanguageCode = KeyPhraseExtractionSkillLanguage.En
    };

    return keyPhraseExtractionSkill;
}

بناء وإنشاء مجموعة المهارات

بادر ببناء SearchIndexerSkillset باستخدام المهارات التي أنشأتها.

private static SearchIndexerSkillset CreateOrUpdateDemoSkillSet(SearchIndexerClient indexerClient, IList<SearchIndexerSkill> skills,string cognitiveServicesKey)
{
    SearchIndexerSkillset skillset = new SearchIndexerSkillset("demoskillset", skills)
    {
        Description = "Demo skillset",
        CognitiveServicesAccount = new CognitiveServicesAccountKey(cognitiveServicesKey)
    };

    // Create the skillset in your search service.
    // The skillset does not need to be deleted if it was already created
    // since we are using the CreateOrUpdate method
    try
    {
        indexerClient.CreateOrUpdateSkillset(skillset);
    }
    catch (RequestFailedException ex)
    {
        Console.WriteLine("Failed to create the skillset\n Exception message: {0}\n", ex.Message);
        ExitProgram("Cannot continue without a skillset");
    }

    return skillset;
}

أضف الأسطر التالية إلى Main.

// Create the skills
Console.WriteLine("Creating the skills...");
OcrSkill ocrSkill = CreateOcrSkill();
MergeSkill mergeSkill = CreateMergeSkill();
EntityRecognitionSkill entityRecognitionSkill = CreateEntityRecognitionSkill();
LanguageDetectionSkill languageDetectionSkill = CreateLanguageDetectionSkill();
SplitSkill splitSkill = CreateSplitSkill();
KeyPhraseExtractionSkill keyPhraseExtractionSkill = CreateKeyPhraseExtractionSkill();

// Create the skillset
Console.WriteLine("Creating or updating the skillset...");
List<SearchIndexerSkill> skills = new List<SearchIndexerSkill>();
skills.Add(ocrSkill);
skills.Add(mergeSkill);
skills.Add(languageDetectionSkill);
skills.Add(splitSkill);
skills.Add(entityRecognitionSkill);
skills.Add(keyPhraseExtractionSkill);

SearchIndexerSkillset skillset = CreateOrUpdateDemoSkillSet(indexerClient, skills, cognitiveServicesKey);

الخطوة 3: إنشاء فهرس

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

يستخدم هذا التمرين الحقول وأنواع الحقول التالية:

اسم الحقل أنواع الحقل
id Edm.String
content Edm.String
languageCode Edm.String
keyPhrases قائمة<Edm.String>
organizations قائمة<Edm.String>

إنشاء فئة DemoIndex

تُحدد حقول هذا الفهرس باستخدام فئة النموذج. تحتوي كل خاصية لفئة النموذج على سمات تحدد السلوكيات المتعلقة بالبحث في حقل الفهرس المقابل.

سنضيف فئة النموذج إلى ملف C# جديد. انقر بزر الفأرة الأيمن على مشروعك وحدد Add>New Item... ، حدد "Class" وباشر بتسمية الملف DemoIndex.cs، ثم حدد Add.

تأكد من الإشارة إلى أنك تريد استخدام أنواع من مساحات الأسماء Azure.Search.Documents.Indexes و System.Text.Json.Serialization.

أضف تعريف فئة النموذج أدناه DemoIndex.cs وبادر بتضمينه في نفس مساحة الاسم حيث ستنشئ الفهرس.

using Azure.Search.Documents.Indexes;
using System.Text.Json.Serialization;

namespace EnrichwithAI
{
    // The SerializePropertyNamesAsCamelCase is currently unsupported as of this writing. 
    // Replace it with JsonPropertyName
    public class DemoIndex
    {
        [SearchableField(IsSortable = true, IsKey = true)]
        [JsonPropertyName("id")]
        public string Id { get; set; }

        [SearchableField]
        [JsonPropertyName("content")]
        public string Content { get; set; }

        [SearchableField]
        [JsonPropertyName("languageCode")]
        public string LanguageCode { get; set; }

        [SearchableField]
        [JsonPropertyName("keyPhrases")]
        public string[] KeyPhrases { get; set; }

        [SearchableField]
        [JsonPropertyName("organizations")]
        public string[] Organizations { get; set; }
    }
}

الآن بعد أن عرَّفت فئة نموذج، يمكنك مرةً أخرى Program.cs إنشاء تعريف فهرس بسهولةٍ إلى حدٍ ما. سيكون اسم هذا الفهرس demoindex. إذا كان هناك فهرس بهذا الاسم بالفعل، فسيُحذف.

private static SearchIndex CreateDemoIndex(SearchIndexClient indexClient)
{
    FieldBuilder builder = new FieldBuilder();
    var index = new SearchIndex("demoindex")
    {
        Fields = builder.Build(typeof(DemoIndex))
    };

    try
    {
        indexClient.GetIndex(index.Name);
        indexClient.DeleteIndex(index.Name);
    }
    catch (RequestFailedException ex) when (ex.Status == 404)
    {
        //if the specified index not exist, 404 will be thrown.
    }

    try
    {
        indexClient.CreateIndex(index);
    }
    catch (RequestFailedException ex)
    {
        Console.WriteLine("Failed to create the index\n Exception message: {0}\n", ex.Message);
        ExitProgram("Cannot continue without an index");
    }

    return index;
}

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

أضف الأسطر التالية إلى Main.

// Create the index
Console.WriteLine("Creating the index...");
SearchIndex demoIndex = CreateDemoIndex(indexClient);

أضِف عبارة الاستخدام التالية لحل مرجع إزالة الغموض.

using Index = Azure.Search.Documents.Indexes.Models;

لمعرفة المزيد عن مفاهيم الفهرس، راجع إنشاء فهرس (واجهة برمجة تطبيقات REST).

4 - إنشاء وتشغيل المفهرس

لقد أنشأت حتى الآن مصدر بيانات ومجموعة مهارات وفهرس. تصبح هذه المكونات الثلاثة جزءاً من مفهرس يجمع كل قطعةٍ معاً في عملية واحدة متعددة المراحل. لربطها معاً في مفهرس، يجب عليك تحديد تعيينات الحقول.

  • تُعالج fieldMappings قبل مجموعة المهارات، وتعيين الحقول المصدر من مصدر البيانات إلى الحقول المستهدفة في الفهرس. إذا كانت أسماء الحقول وأنواعها هي نفسها في كلا الطرفين، فلا يلزم التعيين.

  • تُعالج outputFieldMappings بعد مجموعة المهارات، مع الإشارة إلى أسماء الحقول المصدر غير الموجودة حتى إنشاءها بواسطة شق المستند أو إثرائه. targetFieldName عبارة حقل في فهرس.

بالإضافة إلى ربط المدخلات بالمخرجات، يمكنك أيضاً استخدام تعيينات الحقول لتسوية هياكل البيانات. لمزيد من المعلومات، راجع كيفية تعيين الحقول التي جرى إثراؤها إلى فهرس قابل للبحث.

private static SearchIndexer CreateDemoIndexer(SearchIndexerClient indexerClient, SearchIndexerDataSourceConnection dataSource, SearchIndexerSkillset skillSet, SearchIndex index)
{
    IndexingParameters indexingParameters = new IndexingParameters()
    {
        MaxFailedItems = -1,
        MaxFailedItemsPerBatch = -1,
    };
    indexingParameters.Configuration.Add("dataToExtract", "contentAndMetadata");
    indexingParameters.Configuration.Add("imageAction", "generateNormalizedImages");

    SearchIndexer indexer = new SearchIndexer("demoindexer", dataSource.Name, index.Name)
    {
        Description = "Demo Indexer",
        SkillsetName = skillSet.Name,
        Parameters = indexingParameters
    };

    FieldMappingFunction mappingFunction = new FieldMappingFunction("base64Encode");
    mappingFunction.Parameters.Add("useHttpServerUtilityUrlTokenEncode", true);

    indexer.FieldMappings.Add(new FieldMapping("metadata_storage_path")
    {
        TargetFieldName = "id",
        MappingFunction = mappingFunction

    });
    indexer.FieldMappings.Add(new FieldMapping("content")
    {
        TargetFieldName = "content"
    });

    indexer.OutputFieldMappings.Add(new FieldMapping("/document/pages/*/organizations/*")
    {
        TargetFieldName = "organizations"
    });
    indexer.OutputFieldMappings.Add(new FieldMapping("/document/pages/*/keyPhrases/*")
    {
        TargetFieldName = "keyPhrases"
    });
    indexer.OutputFieldMappings.Add(new FieldMapping("/document/languageCode")
    {
        TargetFieldName = "languageCode"
    });

    try
    {
        indexerClient.GetIndexer(indexer.Name);
        indexerClient.DeleteIndexer(indexer.Name);
    }
    catch (RequestFailedException ex) when (ex.Status == 404)
    {
        //if the specified indexer not exist, 404 will be thrown.
    }

    try
    {
        indexerClient.CreateIndexer(indexer);
    }
    catch (RequestFailedException ex)
    {
        Console.WriteLine("Failed to create the indexer\n Exception message: {0}\n", ex.Message);
        ExitProgram("Cannot continue without creating an indexer");
    }

    return indexer;
}

أضف الأسطر التالية إلى Main.

// Create the indexer, map fields, and execute transformations
Console.WriteLine("Creating the indexer and executing the pipeline...");
SearchIndexer demoIndexer = CreateDemoIndexer(indexerClient, dataSource, skillset, demoIndex);

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

تلميح

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

استكشاف إنشاء المفهرس

تعين "maxFailedItems" التعليمات البرمجية إلى -1، الذي يوجه محرك الفهرسة لتجاهل الأخطاء أثناء استيراد البيانات. يعد هذا مفيدًا نظرًا لوجود عدد قليل جدًّا من المستندات في مصدر بيانات العرض التوضيحي. بالنسبة لمصدر بيانات أكبر، يمكنك تعيين القيمة إلى أكبر من 0.

لاحظ أيضاً أن "dataToExtract" مُعين إلى "contentAndMetadata". تخبر هذه العبارة المفهرس باستخراج المحتوى تلقائياً من تنسيقات ملفات مختلفة بالإضافة إلى البيانات التعريفية المتعلقة بكل ملف.

عند استخراج المحتوى، يمكنك تعيين imageAction لاستخراج النص من الصور الموجودة في مصدر البيانات. إن "imageAction" المجموعة "generateNormalizedImages" المراد ضبطها، جنباً إلى جنب مع مهارة التعرف البصري على الحروف (OCR) ومهارة دمج النص، تخبر المفهرس باستخراج النص من الصور (على سبيل المثال، كلمة "إيقاف" من علامة توقف نسبة استخدام الشبكة)، وتضمينها باعتبارها جزءاً من حقل المحتوى. ينطبق هذا السلوك على كل من الصور المضمنة في المستندات (فكر في صورة داخل ملف PDF)، وكذلك الصور الموجودة في مصدر البيانات، على سبيل المثال ملف JPG.

4 - مراقبة الفهرسة

بمجرد تحديد المفهرس، يجري تشغيله تلقائيًّا عند إرسال الطلب. اعتماداً على المهارات المعرفية التي حددتها، يمكن أن تستغرق الفهرسة وقتاً أطول مما تتوقع. لمعرفة ما إذا كان المفهرس لا يزال قيد التشغيل، استخدم الأسلوب GetStatus.

private static void CheckIndexerOverallStatus(SearchIndexerClient indexerClient, SearchIndexer indexer)
{
    try
    {
        var demoIndexerExecutionInfo = indexerClient.GetIndexerStatus(indexer.Name);

        switch (demoIndexerExecutionInfo.Value.Status)
        {
            case IndexerStatus.Error:
                ExitProgram("Indexer has error status. Check the Azure Portal to further understand the error.");
                break;
            case IndexerStatus.Running:
                Console.WriteLine("Indexer is running");
                break;
            case IndexerStatus.Unknown:
                Console.WriteLine("Indexer status is unknown");
                break;
            default:
                Console.WriteLine("No indexer information");
                break;
        }
    }
    catch (RequestFailedException ex)
    {
        Console.WriteLine("Failed to get indexer overall status\n Exception message: {0}\n", ex.Message);
    }
}

demoIndexerExecutionInfo يمثل الوضع الحالي وتاريخ التنفيذ للمفهرس.

التحذيرات شائعة مع بعض الملفات المصدر ومجموعات المهارات ولا تشير دائماً إلى وجود مشكلة. في هذا البرنامج التعليمي، تكون التحذيرات مأمونة (على سبيل المثال، لا توجد مدخلات نصية من ملفات JPEG).

أضف الأسطر التالية إلى Main.

// Check indexer overall status
Console.WriteLine("Check the indexer overall status...");
CheckIndexerOverallStatus(indexerClient, demoIndexer);

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

الاختيار الأسهل هو Search explorer في المدخل. يمكنك أولاً تشغيل استعلام فارغ يرجع جميع المستندات، أو يجري بحثاً أكثر استهدافاً والذي يرجع محتوى حقل جديد أُنشئ بواسطة التدفق.

  1. في مدخل Azure، في الصفحة "Overview"، حدد Indexes.

  2. اعثر على demoindex في القائمة. يجب أن تحتوي على 14 مستنداً. إذا كان عدد المستندات صفرًا، فهذا يعني أن المفهرس لا يزال قيد التشغيل أو أن الصفحة لم تحدث بعد.

  3. حدد demoindex. مستكشف البحث هو علامة التبويب الأولى.

  4. المحتوى قابل للبحث بمجرد تحميل المستند الأول. للتحقق من وجود المحتوى، بادر بتشغيل استعلام غير محدد عن طريق النقر فوق Search. هذا الاستعلام يرجع المستندات المُفهرسة حاليًا، مما يمنحك فكرة عما يحتويه الفهرس.

  5. بعد ذلك، الصق السلسلة التالية للحصول على نتائج أكثر قابليةً للإدارة: search=*&$select=id, languageCode, organizations

إعادة تعيين وإعادة تشغيل

في المراحل التجريبية المبكرة من التطوير، فإن النهج الأكثر عملية لتكرار التصميم هو حذف الكائنات من Azure Cognitive Search والسماح لتعليماتك البرمجية بإعادة بنائها. أسماء الموارد فريدة. يتيح لك حذف كائن إعادة إنشائه باستخدام الاسم نفسه.

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

التعاليم الرئيسية

أظهر هذا البرنامج التعليمي الخطوات الأساسية لبناء تدفق فهرسة ثري من خلال إنشاء مكونات: مصدر بيانات ومجموعة مهارات وفهرس ومفهرس.

المهارات المُضمنةقُدِّمت جنبًا إلى جنب مع تعريف مجموعة المهارات وآليات تسلسل المهارات معًا من خلال المدخلات والمخرجات. لقد تعلمت أيضاً أن outputFieldMappings في تعريف المفهرس مطلوب لتوجيه القيم التي جرى إثراؤها من التدفق إلى فهرس قابل للبحث في خدمة Azure Cognitive Search.

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

تنظيف الموارد

عندما تعمل في اشتراكك الخاص، في نهاية المشروع، من المستحسن إزالة الموارد التي لم تعد بحاجة إليها. الموارد المتروكة قيد التشغيل يمكن أن تكلفك المال. يمكنك حذف الموارد كلٌّ على حدة أو حذف مجموعة الموارد لحذف مجموعة الموارد بأكملها.

يمكنك البحث عن الموارد وإدارتها في المدخل، باستخدام الرابط الخاص بجميع الموارد أو مجموعات الموارد في جزء التنقل الأيسر.

الخطوات التالية

الآن بعد أن أصبحت على دراية بجميع العناصر الموجودة في تدفق إثراء AI، فلنلقِ نظرةً فاحصةً على تعريفات مجموعة المهارات والمهارات الفردية.