البرنامج التعليمي C#: استخدام مجموعات المهارات لإنشاء محتوى قابل للبحث في Azure الذكاء الاصطناعي Search

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

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

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

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

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

نظرة عامة

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

يقوم المفهرس بمحرك كل خطوة في المسار، بدءا من استخراج محتوى بيانات العينة (نص وصور غير منظمة) في حاوية كائن ثنائي كبير الحجم على Azure Storage.

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

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

إشعار

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

تحميل الملفات

قم بتنزيل ملف مضغوط لنموذج مستودع البيانات واستخرج المحتويات. تعرف على الكيفية.

تحميل نموذج البيانات إلى Azure Storage

  1. في Azure Storage، قم بإنشاء حاوية جديدة وسمها cog-search-demo.

  2. تحميل ملفات البيانات النموذجية.

  3. احصل على سلسلة الاتصال تخزين بحيث يمكنك صياغة اتصال في Azure الذكاء الاصطناعي Search.

    1. على اليسار، حدد Access keys.

    2. انسخ سلسلة الاتصال للمفتاح واحد أو المفتاحين. يشبه سلسلة الاتصال المثال التالي:

      DefaultEndpointsProtocol=https;AccountName=<your account name>;AccountKey=<your account key>;EndpointSuffix=core.windows.net
      

خدمات الذكاء الاصطناعي في Azure

يتم دعم الإثراء الذكاء الاصطناعي المضمن بواسطة خدمات Azure الذكاء الاصطناعي، بما في ذلك خدمة Language وAzure الذكاء الاصطناعي Vision للغة الطبيعية ومعالجة الصور. بالنسبة لأحمال العمل الصغيرة مثل هذا البرنامج التعليمي، يمكنك استخدام التخصيص المجاني ل 20 معاملة لكل مفهرس. بالنسبة لأحمال العمل الأكبر، قم بإرفاق مورد متعدد المناطق لخدمات Azure الذكاء الاصطناعي بمجموعة مهارات لتسعير الدفع أولا بأول.

نسخ عنوان URL لخدمة البحث ومفتاح API

بالنسبة لهذا البرنامج التعليمي، تتطلب الاتصالات ب Azure الذكاء الاصطناعي Search نقطة نهاية ومفتاح API. يمكنك الحصول على هذه القيم من مدخل Microsoft Azure.

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

  2. ضمن الإعدادات> Keys، انسخ مفتاح مسؤول. يتم استخدام مفاتيح مسؤول لإضافة الكائنات وتعديلها وحذفها. هناك مفتاحان للمسؤول قابلان للتبديل. انسخ أي منهما.

    Screenshot of the URL and API keys in the Azure portal.

إعداد بيئتك

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

ثبت Azure.Search.Documents

يتكون Azure الذكاء الاصطناعي 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. حدد أحدث إصدار ثم حدد تثبيت.

  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": "<YourSearchServiceUri>",
      "SearchServiceAdminApiKey": "<YourSearchServiceAdminApiKey>",
      "SearchServiceQueryApiKey": "<YourSearchServiceQueryApiKey>",
      "AzureAIServicesKey": "<YourMultiRegionAzureAIServicesKey>",
      "AzureBlobConnectionString": "<YourAzureBlobConnectionString>"
    }
    

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

لـ 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 azureAiServicesKey = configuration["AzureAIServicesKey"];

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

إنشاء البنية الأساسية لبرنامج ربط العمليات التجارية

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

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

SearchIndexerClient لديه خاصية DataSourceName يمكنك تعيينها لكائن SearchIndexerDataSourceConnection. يوفر هذا الكائن جميع الطرق التي تحتاجها لإنشاء مصادر بيانات Azure الذكاء الاصطناعي 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 Azure AI 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);

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

Data sources tile in the portal

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

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

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

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

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

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

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

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

أثناء المعالجة الأولية، يكسر Azure الذكاء الاصطناعي 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 الذي يدمج حقل محتوى المستند مع النص الذي تم إنتاجه بواسطة مهارة التعرف البصري على الحروف.

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 azureAiServicesKey)
{
    SearchIndexerSkillset skillset = new SearchIndexerSkillset("demoskillset", skills)
    {
        // Azure AI services was formerly known as Cognitive Services.
        // The APIs still use the old name, so we need to create a CognitiveServicesAccountKey object.
        Description = "Demo skillset",
        CognitiveServicesAccount = new CognitiveServicesAccountKey(azureAiServicesKey)
    };

    // 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, azureAiServicesKey);

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

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

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

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

إنشاء فئة DemoIndex

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

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

تأكد من الإشارة إلى أنك تريد استخدام أنواع من مساحات الأسماء 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.

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

بمجرد تحديد المفهرس، يجري تشغيله تلقائيًّا عند إرسال الطلب. اعتمادا على المهارات التي حددتها، قد تستغرق الفهرسة وقتا أطول مما تتوقع. لمعرفة ما إذا كان المفهرس لا يزال قيد التشغيل، استخدم الأسلوب 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 الذكاء الاصطناعي، نضيف عادة تأخيرا لمدة ثانيتين قبل تشغيل الاستعلامات التي ترجع النتائج، ولكن نظرا لأن الإثراء يستغرق عدة دقائق حتى يكتمل، فسنغلق تطبيق وحدة التحكم ونستخدم نهجا آخر بدلا من ذلك.

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

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

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

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

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

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

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

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

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

النقاط الرئيسية

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

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

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

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

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

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

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

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