Samouczek: generowanie zawartości z możliwością wyszukiwania na podstawie obiektów blob platformy Azure przy użyciu platformy .NET i sztucznej inteligencji

Jeśli w Azure Blob Storage masz nieustrukturyzowany tekst lub obrazy, potok wzbogacania sztucznej inteligencji może wyodrębnić informacje i utworzyć nową zawartość dla scenariuszy wyszukiwania pełnotekstowego lub wyszukiwania wiedzy.

Z tego samouczka w języku C# dowiesz się, jak wykonywać następujące działania:

  • Konfigurowanie środowiska deweloperskiego.
  • Zdefiniuj potok, który używa protokołu OCR, wykrywania języka, rozpoznawania jednostek i wyodrębniania kluczowych fraz.
  • Wykonaj potok, aby wywołać przekształcenia oraz utworzyć i załadować indeks wyszukiwania.
  • Eksploruj wyniki przy użyciu wyszukiwania pełnotekstowego i składni kwerendy sformatowanej.

Jeśli nie masz subskrypcji platformy Azure, przed rozpoczęciem otwórz bezpłatne konto .

Omówienie

W tym samouczku użyto języka C# i biblioteki klienta Azure.Search.Documents do utworzenia źródła danych, indeksu, indeksatora i zestawu umiejętności.

Indeksator łączy się z przykładowymi danymi w kontenerze obiektów blob określonym w obiekcie źródła danych i wysyła całą wzbogaconą zawartość do indeksu wyszukiwania.

Zestaw umiejętności jest dołączony do indeksatora. Wykorzystuje wbudowane umiejętności z Microsoft do znajdowania i wyodrębniania informacji. Kroki w potoku obejmują optyczne rozpoznawanie znaków (OCR) na obrazach, wykrywanie języka tekstu, wyodrębnianie kluczowych fraz i rozpoznawanie jednostek (organizacje). Nowe informacje utworzone przez potok są przechowywane w nowych polach w indeksie. Po wypełnieniu indeksu można użyć pól w zapytaniach, aspektach i filtrach.

Wymagania wstępne

Uwaga

Możesz użyć bezpłatnej usługi wyszukiwania na potrzeby tego samouczka. Bezpłatna usługa wyszukiwania ogranicza do trzech indeksów, trzech indeksatorów i trzech źródeł danych. W ramach tego samouczka tworzony jest jeden element każdego z tych typów. Przed rozpoczęciem upewnij się, że masz miejsce na usługę, aby zaakceptować nowe zasoby.

Pobieranie plików

Przykładowe dane składają się z 14 plików mieszanego typu zawartości, które zostaną przekazane do Azure Blob Storage w późniejszym kroku.

  1. Pobierz pliki z pliku azure-search-sample-data/ai-enrichment-mixed-media/ i skopiuj je na komputer lokalny.

  2. Następnie pobierz kod źródłowy dla tego samouczka. Kod źródłowy znajduje się w folderze tutorial-ai-enrichment/v11 w repozytorium azure-search-dotnet-samples .

1 — Tworzenie usług

W tym samouczku użyto Azure Cognitive Search do indeksowania i zapytań, usług Cognitive Services w zapleczu na potrzeby wzbogacania sztucznej inteligencji i Azure Blob Storage w celu udostępnienia danych. Ten samouczek pozostaje w ramach bezpłatnej alokacji 20 transakcji na indeksator dziennie w usługach Cognitive Services, więc jedynymi usługami, które należy utworzyć, są wyszukiwanie i przechowywanie.

Jeśli to możliwe, utwórz zarówno w tym samym regionie, jak i w grupie zasobów w celu zapewnienia zbliżenia i możliwości zarządzania. W praktyce konto usługi Azure Storage może znajdować się w dowolnym regionie.

Rozpoczynanie pracy z usługą Azure Storage

  1. Zaloguj się do Azure Portal i kliknij pozycję + Utwórz zasób.

  2. Wyszukaj konto magazynu i wybierz ofertę konta magazynu Microsoft.

    Tworzenie konta magazynu Utwórz

  3. Na karcie Podstawy wymagane są następujące elementy. Zaakceptuj wartości domyślne dla wszystkich innych elementów.

    • Grupa zasobów. Wybierz istniejącą lub utwórz nową, ale użyj tej samej grupy dla wszystkich usług, aby zarządzać nimi zbiorczo.

    • Nazwa konta magazynu. Jeśli uważasz, że może istnieć wiele zasobów tego samego typu, użyj nazwy , aby uściślać według typu i regionu, na przykład blobstoragewestus.

    • Lokalizacja. Jeśli to możliwe, wybierz tę samą lokalizację używaną dla usług Azure Cognitive Search i Cognitive Services. Jedna lokalizacja unieważnia opłaty za przepustowość.

    • Rodzaj konta. Wybierz wartość domyślną StorageV2 (ogólnego przeznaczenia w wersji 2).

  4. Wybierz pozycję Przejrzyj i utwórz , aby utworzyć usługę.

  5. Po utworzeniu wybierz pozycję Przejdź do zasobu , aby otworzyć stronę Przegląd.

  6. Wybierz pozycję Usługa obiektów blob .

  7. Wybierz pozycję + Kontener , aby utworzyć kontener i nadaj mu nazwę cog-search-demo.

  8. Wybierz pozycję cog-search-demo , a następnie wybierz pozycję Przekaż , aby otworzyć folder, w którym zapisano pliki pobierania. Wybierz wszystkie pliki. Wybierz pozycję Przekaż.

    Zrzut ekranu przedstawiający pliki w Eksplorator plików.

  9. Przed opuszczeniem usługi Azure Storage pobierz parametry połączenia, aby można było sformułować połączenie w Azure Cognitive Search.

    1. Wróć do strony Przegląd konta magazynu (jako przykład użyto obiektu blobstragewestus ).

    2. W okienku nawigacji po lewej stronie wybierz pozycję Klucze dostępu i skopiuj jeden z parametrów połączenia.

    Parametry połączenia są adresem URL podobnym do następującego przykładu:

    DefaultEndpointsProtocol=https;AccountName=cogsrchdemostorage;AccountKey=<your account key>;EndpointSuffix=core.windows.net
    
  10. Zapisz parametry połączenia w Notatniku. Będzie on potrzebny później podczas konfigurowania połączenia ze źródłem danych.

Cognitive Services

Wzbogacanie sztucznej inteligencji jest wspierane przez usługi Cognitive Services, w tym usługi językowe i przetwarzanie obrazów na potrzeby przetwarzania języka naturalnego i obrazu. Jeśli twoim celem było ukończenie rzeczywistego prototypu lub projektu, w tym momencie aprowizuj usługi Cognitive Services (w tym samym regionie co Azure Cognitive Search), aby można było dołączyć go do operacji indeksowania.

W tym ćwiczeniu można jednak pominąć aprowizowanie zasobów, ponieważ Azure Cognitive Search może łączyć się z usługami Cognitive Services w tle i zapewnić 20 bezpłatnych transakcji na przebieg indeksatora. Ponieważ ten samouczek używa 14 transakcji, bezpłatna alokacja jest wystarczająca. W przypadku większych projektów zaplanuj aprowizowanie usług Cognitive Services w warstwie S0 z płatnością zgodnie z rzeczywistym użyciem. Aby uzyskać więcej informacji, zobacz Dołączanie usług Cognitive Services.

Trzeci składnik jest Azure Cognitive Search, który można utworzyć w portalu lub znaleźć istniejącą usługę wyszukiwania w subskrypcji.

Aby ukończyć ten przewodnik, możesz użyć warstwy Bezpłatna.

Aby wchodzić w interakcję z usługą Azure Cognitive Search, potrzebny będzie adres URL usługi i klucz dostępu.

  1. Zaloguj się do Azure Portal i na stronie Przegląd usługi wyszukiwania uzyskaj nazwę usługi wyszukiwania. Nazwę usługi możesz potwierdzić, przeglądając adres URL punktu końcowego. Jeśli adres URL punktu końcowego to https://mydemo.search.windows.net, nazwa usługi to mydemo.

  2. W obszarzeKluczeustawień> pobierz klucz administratora dla pełnych praw w usłudze. Możesz skopiować klucz podstawowy lub pomocniczy.

Pobieranie nazwy usługi i klucza administratora

Prawidłowy klucz ustanawia relację zaufania dla danego żądania między aplikacją wysyłającą żądanie i usługą, która je obsługuje.

2 — Konfigurowanie środowiska

Zacznij od otwarcia programu Visual Studio i utworzenia nowego projektu aplikacji konsolowej, który można uruchomić na platformie .NET Core.

Instalowanie pliku Azure.Search.Documents

Zestaw SDK platformy .NET Azure Cognitive Search składa się z biblioteki klienta, która umożliwia zarządzanie indeksami, źródłami danych, indeksatorami i zestawami umiejętności, a także przekazywanie dokumentów i wykonywanie zapytań oraz zarządzanie nimi bez konieczności czynienia ze szczegółami protokołu HTTP i JSON. Ta biblioteka klienta jest dystrybuowana jako pakiet NuGet.

W przypadku tego projektu zainstaluj wersję 11 lub nowszą Azure.Search.Documents i najnowszą wersję programu Microsoft.Extensions.Configuration.

  1. W programie Visual Studio wybierz pozycję Narzędzia>Menedżer> pakietówNuGet Zarządzaj pakietami NuGet dla rozwiązania...

  2. Wyszukaj plik Azure.Search.Document.

  3. Wybierz najnowszą wersję, a następnie kliknij przycisk Zainstaluj.

  4. Powtórz poprzednie kroki, aby zainstalować Microsoft. Extensions.Configuration i Microsoft. Extensions.Configuration.Json.

Dodawanie informacji o połączeniu z usługą

  1. Kliknij prawym przyciskiem myszy projekt w Eksplorator rozwiązań i wybierz pozycję Dodaj>nowy element... .

  2. Nadaj plikowi appsettings.json nazwę i wybierz pozycję Dodaj.

  3. Dołącz ten plik do katalogu wyjściowego.

    1. Kliknij prawym przyciskiem myszy appsettings.json i wybierz polecenie Właściwości.
    2. Zmień wartość Copy to Output Directory (Kopiuj do katalogu wyjściowego ), aby skopiować wartość , jeśli jest nowsza.
  4. Skopiuj poniższy kod JSON do nowego pliku 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",
    }
    

Dodaj informacje o usłudze wyszukiwania i koncie magazynu obiektów blob. Pamiętaj, że te informacje można uzyskać z kroków aprowizacji usług wskazanych w poprzedniej sekcji.

W polu SearchServiceUri wprowadź pełny adres URL.

Dodawanie przestrzeni nazw

W Program.cspliku dodaj następujące przestrzenie nazw.

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

Tworzenie klienta

Utwórz wystąpienie obiektu SearchIndexClient i w SearchIndexerClient obszarze 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));
}

Uwaga

Klienci łączą się z usługą wyszukiwania. Aby uniknąć otwierania zbyt wielu połączeń, w miarę możliwości należy spróbować udostępnić pojedyncze wystąpienie w aplikacji. Metody są bezpieczne wątkowo, aby umożliwić takie udostępnianie.

Dodawanie funkcji w celu zakończenia programu podczas niepowodzenia

Ten samouczek ma ułatwić zrozumienie każdego kroku potoku indeksowania. Jeśli występuje krytyczny problem uniemożliwiający programowi utworzenie źródła danych, zestawu umiejętności, indeksu lub indeksatora program wyświetli komunikat o błędzie i zakończy działanie, aby można było zrozumieć i rozwiązać problem.

Dodaj ExitProgram element do programu , aby Main obsługiwać scenariusze, które wymagają zakończenia działania programu.

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 — Tworzenie potoku

W Azure Cognitive Search przetwarzanie sztucznej inteligencji odbywa się podczas indeksowania (lub pozyskiwania danych). Ta część przewodnika tworzy cztery obiekty: źródło danych, definicję indeksu, zestaw umiejętności, indeksator.

Krok 1. Tworzenie źródła danych

SearchIndexerClientDataSourceName ma właściwość , którą można ustawić na SearchIndexerDataSourceConnection obiekt. Ten obiekt zawiera wszystkie metody tworzenia, wyświetlania listy, aktualizacji lub usuwania Azure Cognitive Search źródeł danych.

Utwórz nowe SearchIndexerDataSourceConnection wystąpienie, wywołując polecenie indexerClient.CreateOrUpdateDataSourceConnection(dataSource). Poniższy kod tworzy źródło danych typu 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;
}

W przypadku pomyślnego żądania metoda zwróci utworzone źródło danych. Jeśli wystąpi problem z żądaniem, taki jak nieprawidłowy parametr, metoda zgłosi wyjątek.

Teraz dodaj wiersz , Main aby wywołać CreateOrUpdateDataSource właśnie dodaną funkcję.

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

Skompiluj i uruchom rozwiązanie. Ponieważ jest to pierwsze żądanie, sprawdź Azure Portal, aby potwierdzić utworzenie źródła danych w Azure Cognitive Search. Na stronie przeglądu usługi wyszukiwania sprawdź, czy lista Źródła danych zawiera nowy element. Może trzeba będzie zaczekać kilka minut na odświeżenie strony portalu.

Kafelek Źródła danych w portalu

Krok 2. Tworzenie zestawu umiejętności

W tej sekcji zdefiniujesz zestaw kroków wzbogacania, które chcesz zastosować do danych. Każdy krok wzbogacania jest nazywany umiejętnością i zestawem kroków wzbogacania, zestawem umiejętności. W tym samouczku używane są wbudowane umiejętności poznawcze dla zestawu umiejętności:

  • Optyczne rozpoznawanie znaków do rozpoznawania tekstu drukowanego i odręcznego w plikach obrazów.

  • Scalanie tekstu w celu skonsolidowania tekstu z kolekcji pól w jednym polu "scalona zawartość".

  • Wykrywanie języka — identyfikowanie języka zawartości.

  • Rozpoznawanie jednostek do wyodrębniania nazw organizacji z zawartości w kontenerze obiektów blob.

  • Podział tekstu w celu podzielenia dużej zawartości na mniejsze fragmenty przed wywołaniem umiejętności wyodrębniania kluczowych fraz i umiejętności rozpoznawania jednostek. Wyodrębnianie kluczowych fraz i rozpoznawanie jednostek akceptuje dane wejściowe 50 000 znaków lub mniej. Kilka przykładowych plików należy podzielić, aby zmieścić się w tym limicie.

  • Wyodrębnianie kluczowych fraz — określanie najczęściej występujących fraz kluczowych.

Podczas przetwarzania początkowego Azure Cognitive Search pęka każdy dokument w celu wyodrębnienia zawartości z różnych formatów plików. Tekst pochodzący z pliku źródłowego jest umieszczany w wygenerowanym content polu , po jednym dla każdego dokumentu. W związku z tym ustaw wartość wejściową "/document/content" , aby użyć tego tekstu. Zawartość obrazu jest umieszczana w wygenerowanym normalized_images polu określonym w zestawie umiejętności jako /document/normalized_images/*.

Dane wyjściowe można mapować na indeks i/lub używać ich jako danych wejściowych umiejętności podrzędnej — jak w przypadku kodu języka. W indeksie kod języka jest przydatny do filtrowania. Kod języka jest używany jako dane wejściowe przez umiejętności analizy tekstu w celu określenia zasad podziału wyrazów przez reguły językowe.

Aby uzyskać więcej podstawowych informacji na temat zestawów umiejętności, zobacz Jak zdefiniować zestaw umiejętności.

Umiejętność OCR

Element OcrSkill wyodrębnia tekst z obrazów. Ta umiejętność zakłada, że istnieje pole normalized_images. Aby wygenerować to pole, w dalszej części samouczka ustawimy konfigurację "imageAction" w definicji indeksatora na "generateNormalizedImages"wartość .

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

Umiejętność scalania

W tej sekcji utworzysz MergeSkill element, który scala pole zawartości dokumentu z tekstem utworzonym przez umiejętności 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;
}

Umiejętność wykrywania języka

Funkcja LanguageDetectionSkill wykrywa język tekstu wejściowego i zgłasza pojedynczy kod języka dla każdego dokumentu przesłanego na żądanie. Użyjemy danych wyjściowych umiejętności wykrywania języka jako części danych wejściowych umiejętności dzielenia tekstu .

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

Umiejętność dzielenia tekstu

Poniższy SplitSkill tekst podzieli się na strony i ograniczy długość strony do 4000 znaków mierzonych przez String.Length. Algorytm spróbuje podzielić tekst na fragmenty, które mają największy maximumPageLength rozmiar. W takim przypadku algorytm zrobi wszystko, aby przerwać zdanie na granicy zdania, więc rozmiar fragmentu może być nieco mniejszy niż 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;
}

Umiejętność rozpoznawania jednostek

To EntityRecognitionSkill wystąpienie jest ustawione na rozpoznawanie typu organizationkategorii . Może EntityRecognitionSkill również rozpoznawać typy person kategorii i location.

Zwróć uwagę, że pole "kontekst" jest ustawione na "/document/pages/*" gwiazdkę, co oznacza, że krok wzbogacania jest wywoływany dla każdej strony w obszarze "/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;
}

Umiejętność wyodrębniania kluczowych fraz

EntityRecognitionSkill Podobnie jak właśnie utworzone wystąpienie, KeyPhraseExtractionSkill element jest wywoływany dla każdej strony dokumentu.

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

Tworzenie i tworzenie zestawu umiejętności

SearchIndexerSkillset Użyj utworzonych umiejętności.

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

Dodaj następujące wiersze do .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);

Krok 3. Tworzenie indeksu

W tej sekcji zdefiniujesz schemat indeksu przez określenie pól do umieszczenia w indeksie z możliwością wyszukiwania oraz atrybutów wyszukiwania dla każdego pola. Pola mogą mieć typ i atrybuty, które określają sposób używania pola (z możliwością wyszukiwania, sortowania itp.). Nazwy pól w indeksie nie muszą dokładnie zgadzać się z nazwami pól w źródle. W kolejnym kroku są dodawane mapowania pól w indeksatorze w celu połączenia pól źródłowych z polami docelowymi. W tym kroku zdefiniuj indeks przy użyciu konwencji nazewnictwa pól właściwej dla aplikacji wyszukiwania.

W tym ćwiczeniu są używane następujące pola i typy pól:

Nazwy pól Typy pól
id Edm.String
content Edm.String
languageCode Edm.String
keyPhrases Lista<Edm.String>
organizations Lista<Edm.String>

Tworzenie klasy DemoIndex

Pola dla tego indeksu są definiowane przy użyciu klasy modelu. Każda właściwość klasy modelu ma atrybuty, które określają związane z wyszukiwaniem zachowania odpowiedniego pola indeksu.

Dodamy klasę modelu do nowego pliku C#. Kliknij prawym przyciskiem myszy projekt i wybierz polecenie Dodaj>nowy element..., wybierz pozycję "Klasa" i nadaj plikowi DemoIndex.csnazwę , a następnie wybierz pozycję Dodaj.

Pamiętaj, aby wskazać, że chcesz używać typów z Azure.Search.Documents.Indexes przestrzeni nazw i System.Text.Json.Serialization .

Dodaj poniższą definicję klasy modelu i DemoIndex.cs dołącz ją do tej samej przestrzeni nazw, w której utworzysz indeks.

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

Teraz, po zdefiniowaniu klasy modelu, Program.cs możesz łatwo utworzyć definicję indeksu. Nazwa tego indeksu to demoindex. Jeśli indeks już istnieje o tej nazwie, zostanie usunięty.

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

Podczas testowania może się okazać, że próbujesz utworzyć indeks więcej niż raz. W związku z tym sprawdź, czy indeks, który chcesz utworzyć, już istnieje przed podjęciem próby jego utworzenia.

Dodaj następujące wiersze do Main.

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

Dodaj następującą instrukcję using, aby rozwiązać problem z niejednoznacznym odwołaniem.

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

Aby dowiedzieć się więcej na temat pojęć związanych z indeksem, zobacz Create Index (INTERFEJS API REST).

Krok 4. Tworzenie i uruchamianie indeksatora

Do tej pory utworzono źródło danych, zestaw umiejętności i indeks. Te trzy składniki staną się częścią indeksatora, który łączy wszystkie części w pojedynczą operację obejmującą wiele faz. Aby powiązać je razem w indeksatorze, należy zdefiniować mapowania pól.

  • PolaMappings są przetwarzane przed zestawem umiejętności, mapowanie pól źródłowych ze źródła danych na pola docelowe w indeksie. Jeśli nazwy pól i typy są takie same na obu końcach, nie jest wymagane mapowanie.

  • Dane wyjścioweFieldMappings są przetwarzane po zestawie umiejętności, odwołując się do parametrów sourceFieldName, które nie istnieją, dopóki nie zostaną utworzone przez pęknięcie dokumentu lub wzbogacenie. TargetFieldName to pole w indeksie.

Oprócz podłączania danych wejściowych do danych wyjściowych można również używać mapowań pól do spłaszczania struktur danych. Aby uzyskać więcej informacji, zobacz Jak mapować wzbogacone pola na indeks z możliwością wyszukiwania.

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

Dodaj następujące wiersze do 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);

Spodziewaj się, że przetwarzanie indeksatora potrwa trochę czasu. Mimo że zestaw danych jest mały, umiejętności analityczne wykorzystują znaczną moc obliczeniową. Wykonywanie niektórych umiejętności, takich jak analiza obrazu, jest długotrwałe.

Porada

Utworzenie indeksatora powoduje wywołanie potoku. Jeśli występują problemy z dostępem do danych, mapowaniem danych wejściowych i wyjściowych lub kolejnością operacji, pojawią się one na tym etapie.

Eksplorowanie tworzenia indeksatora

Kod ustawia "maxFailedItems" wartość -1, co nakazuje aparatowi indeksowania ignorowanie błędów podczas importowania danych. Jest to przydatne, ponieważ pokazowe źródło danych zawiera tak mało dokumentów. W przypadku większego źródła danych należy ustawić wartość większą od 0.

Zwróć również uwagę, że dla parametru ustawiono "dataToExtract" wartość "contentAndMetadata". Ta instrukcja nakazuje indeksatorowi automatyczne wyodrębnianie zawartości z plików w różnych formatach, a także metadanych związanych z każdym plikiem.

Gdy zawartość zostanie wyodrębniona, możesz ustawić element imageAction, aby wyodrębnić tekst z obrazów znalezionych w źródle danych. Zestaw "imageAction" do "generateNormalizedImages" konfiguracji, w połączeniu z umiejętnością OCR i scalaniem tekstu, informuje indeksator, aby wyodrębnił tekst z obrazów (na przykład słowo "stop" z znaku zatrzymania ruchu) i osadzić go w ramach pola zawartości. To zachowanie dotyczy zarówno obrazów osadzonych w dokumentach (np. w pliku PDF), jak i znalezionych w źródle danych (np. pliku JPG).

4 — Monitorowanie indeksowania

Po zdefiniowaniu indeksatora jest on uruchamiany automatycznie przy przesyłaniu żądania. W zależności od tego, które umiejętności poznawcze zdefiniowano, indeksowanie może trwać dłużej, niż oczekujesz. Aby dowiedzieć się, czy indeksator jest nadal uruchomiony, użyj GetStatus metody .

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 reprezentuje bieżący stan i historię wykonywania indeksatora.

Ostrzeżenia często występują dla niektórych kombinacji plików źródłowych i umiejętności oraz nie zawsze wskazują istnienie problemu. W tym samouczku ostrzeżenia są niegroźne (np. brak tekstowych danych wejściowych dla plików JPEG).

Dodaj następujące wiersze do Main.

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

W Azure Cognitive Search samouczku aplikacje konsolowe zwykle dodajemy 2-sekundowe opóźnienie przed uruchomieniem zapytań, które zwracają wyniki, ale ponieważ wzbogacanie trwa kilka minut, zamkniemy aplikację konsolową i użyjemy innego podejścia.

Najprostszą opcją jest Eksplorator wyszukiwania w portalu. Możesz najpierw uruchomić puste zapytanie zwracające wszystkie dokumenty lub bardziej ukierunkowane wyszukiwanie zwracające nową zawartość pola utworzoną przez potok.

  1. W Azure Portal na stronie Przegląd wyszukiwania wybierz pozycję Indeksy.

  2. Znajdź demoindex na liście. Powinien zawierać 14 dokumentów. Jeśli liczba dokumentów wynosi zero, indeksator jest nadal uruchomiony lub strona nie została jeszcze odświeżona.

  3. Wybierz pozycję demoindex. Eksplorator wyszukiwania to pierwsza karta.

  4. Zawartość można przeszukiwać zaraz po załadowaniu pierwszego dokumentu. Aby sprawdzić, czy zawartość istnieje, uruchom nieokreślone zapytanie, klikając pozycję Wyszukaj. To zapytanie zwraca wszystkie aktualnie indeksowane dokumenty, co daje wyobrażenie o tym, co zawiera indeks.

  5. Następnie wklej następujący ciąg, aby uzyskać bardziej możliwe do zarządzania wyniki: search=*&$select=id, languageCode, organizations

Resetowanie i ponowne uruchamianie

We wczesnych etapach eksperymentalnych programowania najbardziej praktyczne podejście do iteracji projektowej polega na usunięciu obiektów z Azure Cognitive Search i umożliwieniu ponownego skompilowania kodu. Nazwy zasobów są unikatowe. Usunięcie obiektu umożliwia jego ponowne utworzenie przy użyciu tej samej nazwy.

Przykładowy kod tego samouczka sprawdza istniejące obiekty i usuwa je, aby można było ponownie uruchomić kod. Portal umożliwia również usuwanie indeksów, indeksatorów, źródeł danych i zestawów umiejętności.

Wnioski

W tym samouczku przedstawiono podstawowe kroki tworzenia wzbogaconego potoku indeksowania poprzez tworzenie części składników: źródła danych, zestawu umiejętności, indeksu i indeksatora.

Wprowadzono wbudowane umiejętności wraz z definicją zestawu umiejętności i mechaniką łączenia umiejętności za pomocą danych wejściowych i wyjściowych. Wiesz również, że outputFieldMappings w definicji indeksatora jest wymagany routing wzbogaconych wartości z potoku do indeksu z możliwością wyszukiwania w usłudze Azure Cognitive Search.

Ponadto przedstawiono sposób testowania wyników i resetowania systemu na potrzeby przyszłych iteracji. Omówiono proces, w ramach którego odpytanie indeksu powoduje zwrócenie danych wyjściowych utworzonych przez wzbogacony potok indeksowania. Zaprezentowano procedurę sprawdzania stanu indeksatora i usuwania obiektów przed ponownym uruchomieniem potoku.

Czyszczenie zasobów

Podczas pracy w ramach własnej subskrypcji na końcu projektu warto usunąć zasoby, których już nie potrzebujesz. Uruchomione zasoby mogą generować koszty. Zasoby możesz usuwać pojedynczo lub możesz usunąć grupę zasobów, aby usunąć cały ich zestaw.

Zasoby można znaleźć w portalu i zarządzać nimi, korzystając z linku Wszystkie zasoby lub Grupy zasobów w okienku nawigacji po lewej stronie.

Następne kroki

Teraz, gdy znasz już wszystkie obiekty w potoku wzbogacania sztucznej inteligencji, przyjrzyjmy się bliżej definicjom zestawu umiejętności i indywidualnym umiejętnościom.