Självstudie: Använda .NET och AI för att generera sökbart innehåll från Azure-blobar

Om du har ostrukturerad text eller bilder i Azure Blob Storage kan en AI-berikande pipeline i Azure AI Search extrahera information och skapa nytt innehåll för fulltextsökning eller kunskapsutvinningsscenarier.

I den här C#-självstudien lär du dig att:

  • Konfigurera en utvecklingsmiljö.
  • Definiera en pipeline som använder OCR, språkidentifiering, entitetsigenkänning och extrahering av nyckelfraser.
  • Kör pipelinen för att anropa transformeringar och för att skapa och läsa in ett sökindex.
  • Utforska resultat med hjälp av fulltextsökning och en rtF-frågesyntax.

Om du inte har en Azure-prenumeration öppnar du ett kostnadsfritt konto innan du börjar.

Översikt

I den här självstudien används C# och Azure.Search.Documents-klientbiblioteket för att skapa en datakälla, ett index, en indexerare och en kunskapsuppsättning.

Indexeraren ansluter till exempeldata i en blobcontainer som anges i datakällans objekt och skickar allt berikat innehåll till ett sökindex.

Kompetensuppsättningen är kopplad till indexeraren. Den använder inbyggda kunskaper från Microsoft för att hitta och extrahera information. Steg i pipelinen är optisk teckenigenkänning (OCR) på bilder, språkidentifiering på text, extrahering av nyckelfraser och entitetsigenkänning (organisationer). Ny information som skapas av pipelinen lagras i nya fält i ett index. När indexet har fyllts i kan du använda fälten i frågor, fasetter och filter.

Förutsättningar

Kommentar

Du kan använda den kostnadsfria söktjänsten för den här självstudien. En kostnadsfri söktjänst begränsar dig till tre index, tre indexerare och tre datakällor. I den här kursen skapar du en av varje. Innan du börjar bör du se till att du har plats för din tjänst för att acceptera de nya resurserna.

Ladda ned filer

Exempeldata består av 14 filer av typen blandat innehåll som du laddar upp till Azure Blob Storage i ett senare steg.

  1. Hämta filerna från azure-search-sample-data/ai-enrichment-mixed-media/ och kopiera dem till din lokala dator.

  2. Hämta sedan källkoden för den här självstudien. Källkoden finns i mappen tutorial-ai-enrichment/v11lagringsplatsen azure-search-dotnet-samples .

1 – Skapa tjänster

I den här självstudien används Azure AI Search för indexering och frågor, Azure AI-tjänster på serverdelen för AI-berikning och Azure Blob Storage för att tillhandahålla data. Den här självstudien ligger under den kostnadsfria allokeringen av 20 transaktioner per indexerare och dag i Azure AI-tjänster, så de enda tjänster du behöver skapa är sökning och lagring.

Om möjligt skapar du både i samma region och resursgrupp för närhet och hanterbarhet. I praktiken kan ditt Azure Storage-konto finnas i valfri region.

Börja med Azure Storage

  1. Logga in på Azure-portalen och klicka på + Skapa resurs.

  2. Sök efter lagringskonto och välj Microsofts lagringskontoerbjudande.

    Create Storage account

  3. På fliken Grundinställningar krävs följande objekt. Acceptera standardinställningarna för allt annat.

    • Resursgrupp. Välj en befintlig eller skapa en ny, men använd samma grupp för alla tjänster så att du kan hantera dem kollektivt.

    • Namn på lagringskonto. Om du tror att du kan ha flera resurser av samma typ använder du namnet för att skilja mellan typ och region, till exempel blobstoragewestus.

    • Plats. Om möjligt väljer du samma plats som används för Azure AI Search och Azure AI-tjänster. En enda plats ogiltigförklarar bandbreddsavgifter.

    • Typ av konto. Välj standardvärdet StorageV2 (generell användning v2).

  4. Välj Granska + Skapa för att skapa tjänsten.

  5. När den har skapats väljer du Gå till resursen för att öppna sidan Översikt.

  6. Välj Blobs-tjänsten .

  7. Välj + Container för att skapa en container och ge den namnet cog-search-demo.

  8. Välj cog-search-demo och välj sedan Ladda upp för att öppna mappen där du sparade nedladdningsfilerna. Markera alla filer. Välj överför.

    Screenshot of the files in File Explorer.

  9. Innan du lämnar Azure Storage kan du skaffa en anslutningssträng så att du kan formulera en anslutning i Azure AI Search.

    1. Bläddra tillbaka till sidan Översikt för ditt lagringskonto (vi använde blobstragewestus som exempel).

    2. I det vänstra navigeringsfönstret väljer du Åtkomstnycklar och kopierar en av de anslutningssträng.

    Anslutningssträng är en URL som liknar följande exempel:

    DefaultEndpointsProtocol=https;AccountName=cogsrchdemostorage;AccountKey=<your account key>;EndpointSuffix=core.windows.net
    
  10. Spara anslutningssträng till Anteckningar. Du behöver det senare när du konfigurerar datakällans anslutning.

AI-tjänster i Azure

AI-berikande backas upp av Azure AI-tjänster, inklusive Language Service och Azure AI Vision för naturligt språk och bildbearbetning. Om målet var att slutföra en verklig prototyp eller ett projekt skulle du nu etablera Azure AI-tjänster (i samma region som Azure AI Search) så att du kan koppla den till indexeringsåtgärder.

I den här övningen kan du dock hoppa över resursetablering eftersom Azure AI Search kan ansluta till Azure AI-tjänster i bakgrunden och ge dig 20 kostnadsfria transaktioner per indexerare. Eftersom den här självstudien använder 14 transaktioner räcker det med den kostnadsfria allokeringen. För större projekt planerar du att etablera Azure AI-tjänster på S0-nivån betala per användning. Mer information finns i Bifoga Azure AI-tjänster.

Den tredje komponenten är Azure AI Search, som du kan skapa i portalen eller hitta en befintlig söktjänst i din prenumeration.

Du kan använda den kostnadsfria nivån för att slutföra den här genomgången.

För att interagera med din Azure AI-tjänsten Search behöver du tjänstens URL och en åtkomstnyckel.

  1. Logga in på Azure-portalen och hämta namnet på söktjänsten på sidan Översikt för söktjänsten. Du kan bekräfta tjänstnamnet genom att granska slutpunkts-URL:en. Om slutpunkts-URL:en var https://mydemo.search.windows.netskulle tjänstnamnet vara mydemo.

  2. I Inställningar> Keys hämtar du en administratörsnyckel för fullständiga rättigheter för tjänsten. Du kan kopiera antingen den primära eller sekundära nyckeln.

    Get the service name and admin key

En giltig nyckel upprättar förtroende, i varje begäran, mellan programmet som skickar begäran och tjänsten som hanterar den.

2 – Konfigurera din miljö

Börja med att öppna Visual Studio och skapa ett nytt Konsolappsprojekt som kan köras på .NET Core.

Installera Azure.Search.Documents

Azure AI Search .NET SDK består av ett klientbibliotek som gör att du kan hantera dina index, datakällor, indexerare och kompetensuppsättningar, samt ladda upp och hantera dokument och köra frågor, allt utan att behöva ta itu med informationen om HTTP och JSON. Det här klientbiblioteket distribueras som ett NuGet-paket.

För det här projektet installerar du version 11 eller senare av och Azure.Search.Documents den senaste versionen av Microsoft.Extensions.Configuration.

  1. I Visual Studio väljer du Verktyg>NuGet Package Manager>Hantera NuGet-paket för lösning...

  2. Bläddra efter Azure.Search.Document.

  3. Välj den senaste versionen och klicka sedan på Installera.

  4. Upprepa föregående steg för att installera Microsoft.Extensions.Configuration och Microsoft.Extensions.Configuration.Json.

Lägga till information om tjänstanslutning

  1. Högerklicka på projektet i Solution Explorer och välj Lägg till>nytt objekt... .

  2. Namnge filen appsettings.json och välj Lägg till.

  3. Inkludera den här filen i utdatakatalogen.

    1. Högerklicka på appsettings.json och välj Egenskaper.
    2. Ändra värdet för Kopiera till utdatakatalog till Kopiera om det är nyare.
  4. Kopiera JSON nedan till din nya JSON-fil.

    {
      "SearchServiceUri": "<YourSearchServiceUri>",
      "SearchServiceAdminApiKey": "<YourSearchServiceAdminApiKey>",
      "SearchServiceQueryApiKey": "<YourSearchServiceQueryApiKey>",
      "AzureAIServicesKey": "<YourMultiRegionAzureAIServicesKey>",
      "AzureBlobConnectionString": "<YourAzureBlobConnectionString>"
    }
    

Lägg till din söktjänst och bloblagringskontoinformation. Kom ihåg att du kan hämta den här informationen från de tjänstetableringssteg som anges i föregående avsnitt.

För SearchServiceUri anger du den fullständiga URL:en.

Lägga till namnområden

I Program.cslägger du till följande namnområden.

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

Skapa en klient

Skapa en instans av en SearchIndexClient och en SearchIndexerClient under 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));
}

Kommentar

Klienterna ansluter till söktjänsten. För att undvika att öppna för många anslutningar bör du försöka dela en enda instans i ditt program om det är möjligt. Metoderna är trådsäkra för att aktivera sådan delning.

Lägg till funktion för att avsluta programmet vid fel

Den här självstudien är avsedd att hjälpa dig att förstå varje steg i indexeringspipelinen. Om det finns ett kritiskt problem som hindrar programmet från att skapa datakällan, kompetensuppsättningen, indexet eller indexeraren kommer programmet att mata ut felmeddelandet och avsluta så att problemet kan förstås och åtgärdas.

Lägg till ExitProgramMain i för att hantera scenarier som kräver att programmet avslutas.

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 – Skapa pipelinen

I Azure AI Search sker AI-bearbetning under indexering (eller datainmatning). Den här delen av genomgången skapar fyra objekt: datakälla, indexdefinition, kompetensuppsättning, indexerare.

Steg 1: Skapa en datakälla

SearchIndexerClient har en DataSourceName egenskap som du kan ange till ett SearchIndexerDataSourceConnection objekt. Det här objektet innehåller alla metoder som du behöver för att skapa, lista, uppdatera eller ta bort Azure AI Search-datakällor.

Skapa en ny SearchIndexerDataSourceConnection instans genom att anropa indexerClient.CreateOrUpdateDataSourceConnection(dataSource). Följande kod skapar en datakälla av typen 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;
}

För en lyckad begäran returnerar metoden den datakälla som skapades. Om det uppstår ett problem med begäran, till exempel en ogiltig parameter, utlöser metoden ett undantag.

Lägg nu till en rad i Main för att anropa funktionen CreateOrUpdateDataSource som du just har lagt till.

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

Skapa och kör lösningen. Eftersom det här är din första begäran kontrollerar du Azure-portalen för att bekräfta att datakällan skapades i Azure AI Search. På översiktssidan för söktjänsten kontrollerar du att listan Datakällor har ett nytt objekt. Du kan behöva vänta några minuter medan portalsidan uppdateras.

Data sources tile in the portal

Steg 2: Skapa en kompetensuppsättning

I det här avsnittet definierar du en uppsättning berikningssteg som du vill tillämpa på dina data. Varje berikningssteg kallas för en färdighet och en uppsättning berikningssteg, en kompetensuppsättning. I den här självstudien används inbyggda kunskaper för kompetensuppsättningen:

  • Optisk teckenigenkänning för att identifiera tryckt och handskriven text i bildfiler.

  • Textsammanslagning för att konsolidera text från en samling fält till ett enda "sammanfogat innehåll"-fält.

  • Språkidentifiering för att identifiera innehållets språk.

  • Entitetsigenkänning för att extrahera namnen på organisationer från innehåll i blobcontainern.

  • Textdelning för att dela upp stort innehåll i mindre segment innan du anropar kunskapen om extrahering av nyckelfraser och kunskapen om entitetsigenkänning. Extrahering av nyckelfraser och entitetsigenkänning accepterar indata på högst 50 000 tecken. Några av exempelfilerna måste delas upp för att rymmas inom gränsen.

  • Extrahering av nyckelfraser för att hämta viktigaste nyckelfraserna.

Under den inledande bearbetningen spricker Azure AI Search varje dokument för att extrahera innehåll från olika filformat. Text som kommer från källfilen placeras i ett genererat content fält, ett för varje dokument. Ange därför indata för "/document/content" att använda den här texten. Bildinnehåll placeras i ett genererat normalized_images fält som anges i en kompetensuppsättning som /document/normalized_images/*.

Utdata kan mappas till ett index som används som indata till en underordnad kunskap, eller både, vilket är fallet med språkkod. I indexet kan en språkkod användas för filtrering. Som indata används språkkoden av textanalyskunskaper för att informera om de språkliga reglerna kring ordnedbrytning.

Mer information om grunderna i kunskapsuppsättningar finns i Definiera en kunskapsuppsättning.

OCR-kompetens

Extraherar OcrSkill text från bilder. Den här färdigheten förutsätter att det finns ett normalized_images fält. För att generera det här fältet anger vi konfigurationen i indexerdefinitionen "imageAction" till "generateNormalizedImages"senare i självstudien.

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

Sammanslagningsfärdighet

I det här avsnittet skapar du en MergeSkill som sammanfogar dokumentinnehållsfältet med texten som producerades av OCR-färdigheten.

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

Språkidentifieringsfärdighet

Identifierar LanguageDetectionSkill språket i indatatexten och rapporterar en enda språkkod för varje dokument som skickas på begäran. Vi använder utdata från språkidentifieringsfärdigheten som en del av inmatningen till färdigheten Textdelning .

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

Kunskap om textdelning

Nedanstående SplitSkill delar upp text efter sidor och begränsar sidlängden till 4 000 tecken mätt med String.Length. Algoritmen försöker dela upp texten i segment som är som mest maximumPageLength stora. I det här fallet gör algoritmen sitt bästa för att bryta meningen på en meningsgräns, så storleken på segmentet kan vara något mindre än 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;
}

Kunskap om entitetsigenkänning

Den här EntityRecognitionSkill instansen är inställd på att identifiera kategoritypen organization. EntityRecognitionSkill Kan också identifiera kategorityper person och location.

Observera att fältet "context" är inställt på med en asterisk, vilket innebär att "/document/pages/*" berikningssteget anropas för varje sida under "/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;
}

Extraheringsfärdighet för nyckelfraser

Precis som den EntityRecognitionSkill instans som just skapades KeyPhraseExtractionSkill anropas för varje sida i dokumentet.

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

Skapa och skapa kompetensuppsättningen

Skapa med hjälp av SearchIndexerSkillset de kunskaper du skapade.

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

Lägg till följande rader i 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);

Steg 3: Skapa ett index

I det här avsnittet definierar du indexschemat genom att ange vilka fält som ska ingå i det sökbara indexet och sökattributen för varje fält. Fält har en typ och kan ta attribut som bestämmer hur fältet ska användas (sökbart, sorteringsbart och så vidare). Fältnamn i ett index krävs inte för att matcha fältnamn identiskt i källan. I ett senare steg lägger du till fältmappningar i en indexerare för att ansluta källa-mål-fält. För det här steget definiera indexet med fältnamnkonventioner som är relevanta för ditt sökprogram.

Den här övningen använder följande fält och fälttyp:

Fältnamn Fälttyper
id Edm.String
content Edm.String
languageCode Edm.String
keyPhrases Lista<Edm.String>
organizations Lista<Edm.String>

Skapa DemoIndex-klass

Fälten för det här indexet definieras med hjälp av en modellklass. Varje egenskap i modellklassen har attribut som avgör motsvarande indexfälts sökrelaterade beteende.

Vi lägger till modellklassen i en ny C#-fil. Högerklicka på projektet och välj Lägg till>nytt objekt..., välj "Klass" och ge filen DemoIndex.csnamnet och välj sedan Lägg till.

Se till att ange att du vill använda typer från namnrymderna Azure.Search.Documents.Indexes och System.Text.Json.Serialization .

Lägg till modellklassdefinitionen nedan i DemoIndex.cs och inkludera den i samma namnområde där du skapar indexet.

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

Nu när du har definierat en modellklass Program.cs kan du skapa en indexdefinition ganska enkelt. Namnet på det här indexet blir demoindex. Om det redan finns ett index med det namnet tas det bort.

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

Under testningen kanske du försöker skapa indexet mer än en gång. Därför kontrollerar du om det index som du ska skapa redan finns innan du försöker skapa det.

Lägg till följande rader i Main.

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

Lägg till följande instruktion för att lösa den tvetydiga referensen.

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

Mer information om indexbegrepp finns i Skapa index (REST API).

Steg 4: Skapa och köra en indexerare

Hittills har du skapat en datakälla, en kunskapsuppsättning och ett index. De här tre komponenterna blir en del av en indexerare som sammanför varje del till en enda åtgärd i flera faser. Om du vill sammanfoga dem i en indexerare måste du definiera fältmappningar.

  • FieldMappings bearbetas före kompetensuppsättningen och mappar källfält från datakällan till målfält i ett index. Om fältnamn och typer är samma i båda ändar krävs ingen mappning.

  • OutputFieldMappings bearbetas efter kompetensuppsättningen och refererar till sourceFieldNames som inte finns förrän dokumentet spricker eller berikar skapar dem. targetFieldName är ett fält i ett index.

Förutom att koppla indata till utdata kan du även använda fältmappningar för att platta ut datastrukturer. Mer information finns i Mappa berikade fält till ett sökbart index.

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

Lägg till följande rader i 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);

Förvänta dig att indexerarens bearbetning tar lite tid att slutföra. Trots att datauppsättningen är liten är analytiska kunskaper beräkningsintensiva. Vissa kunskaper, som bildanalys, är tidskrävande.

Dricks

När en indexerare skapas anropas pipelinen. Om det uppstår problem med att ansluta till data, mappningsindata eller -utdata eller ordningen på åtgärder visas dem i det här stadiet.

Utforska hur du skapar indexeraren

Koden anges "maxFailedItems" till -1, vilket instruerar indexeringsmotorn att ignorera fel under dataimporten. Detta är användbart eftersom det finns det så få dokument i demo-datakällan. För en större datakälla skulle du ställa in värdet på större än 0.

Observera också att är inställt på "dataToExtract""contentAndMetadata". Den här instruktionen anger att indexeraren automatiskt ska extrahera innehållet från olika filformat samt metadata som är relaterade till varje fil.

När innehållet har extraherats kan du ställa in imageAction på att extrahera text från avbildningar som hittades i datakällan. Konfigurationsuppsättningen "imageAction""generateNormalizedImages" , kombinerad med OCR Skill and Text Merge Skill, instruerar indexeraren att extrahera text från bilderna (till exempel ordet "stopp" från en trafikstoppsskylt) och bädda in den som en del av innehållsfältet. Det här beteendet gäller både avbildningarna som är inbäddade i dokumenten (tänk på en avbildning i en PDF) samt avbildningar som hittas i datakällan, till exempel en JPG-fil.

4 – Övervaka indexering

När du har definierat indexeraren körs den automatiskt när du skickar din begäran. Beroende på vilka kunskaper du har definierat kan indexeringen ta längre tid än förväntat. Använd metoden för att ta reda på om indexeraren fortfarande körs 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 representerar den aktuella status- och körningshistoriken för en indexerare.

Varningar är vanliga med vissa källfils- och kunskapskombinationer och är inte alltid tecken på problem. I den här självstudien är varningarna ofarliga (till exempel inga textindata från JPEG-filerna).

Lägg till följande rader i Main.

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

I azure AI Search-självstudiekonsolappar lägger vi vanligtvis till en fördröjning på 2 sekunder innan vi kör frågor som returnerar resultat, men eftersom berikning tar flera minuter att slutföra stänger vi konsolappen och använder en annan metod i stället.

Det enklaste alternativet är Sökutforskaren i portalen. Du kan först köra en tom fråga som returnerar alla dokument eller en mer riktad sökning som returnerar nytt fältinnehåll som skapats av pipelinen.

  1. I Azure-portalen går du till sököversiktssidan och väljer Index.

  2. Sök demoindex i listan. Den bör ha 14 dokument. Om antalet dokument är noll körs indexeraren fortfarande eller så har sidan inte uppdaterats ännu.

  3. Välj demoindex. Sökutforskaren är den första fliken.

  4. Innehållet kan sökas efter så snart det första dokumentet har lästs in. Kontrollera att innehållet finns genom att köra en ospecificerad fråga genom att klicka på Sök. Den här frågan returnerar alla för närvarande indexerade dokument, vilket ger dig en uppfattning om vad indexet innehåller.

  5. Klistra sedan in följande sträng för mer hanterbara resultat: search=*&$select=id, languageCode, organizations

Återställa och köra igen

I de tidiga experimentella utvecklingsfaserna är det mest praktiska sättet att utforma iteration att ta bort objekten från Azure AI Search och låta koden återskapa dem. Resursnamn är unika. Om du tar bort ett objekt kan du återskapa det med samma namn.

Exempelkoden för den här självstudien söker efter befintliga objekt och tar bort dem så att du kan köra koden igen. Du kan också använda portalen för att ta bort index, indexerare, datakällor och kompetensuppsättningar.

Lärdomar

Den här självstudien visade de grundläggande stegen för att skapa en berikad indexeringspipeline genom att skapa komponentdelar: en datakälla, kompetensuppsättning, index och indexerare.

Inbyggda färdigheter introducerades, tillsammans med kompetensuppsättningsdefinition och mekaniken för sammanlänkning av färdigheter genom indata och utdata. Du har också lärt dig att outputFieldMappings i indexerarens definition krävs för att dirigera berikade värden från pipelinen till ett sökbart index på en Azure AI-tjänsten Search.

Slutligen lärde du dig att testa resultat och återställa systemet för ytterligare iterationer. Du har lärt dig att när du utfärdar frågor mot indexet returneras utdata som skapades av pipelinen för berikande indexering. Du har också lärt dig att kontrollera indexerarstatus, och vilka objekt du ska ta bort innan du kör en pipeline igen.

Rensa resurser

När du arbetar i din egen prenumeration i slutet av ett projekt är det en bra idé att ta bort de resurser som du inte längre behöver. Resurser som fortsätter att köras kostar pengar. Du kan ta bort enstaka resurser eller hela resursgruppen om du vill ta bort alla resurser.

Du kan hitta och hantera resurser i portalen med hjälp av länken Alla resurser eller Resursgrupper i det vänstra navigeringsfönstret.

Nästa steg

Nu när du är bekant med alla objekt i en AI-berikningspipeline ska vi titta närmare på definitioner för kompetensuppsättningar och individuella färdigheter.