Condividi tramite


Indicizzare BLOB e file Markdown in Azure AI Search

Annotazioni

Questa funzionalità è attualmente disponibile in anteprima pubblica. Questa anteprima viene fornita senza un contratto di servizio e non è consigliata per i carichi di lavoro di produzione. Alcune funzionalità potrebbero non essere supportate o potrebbero presentare funzionalità limitate. Per altre informazioni, vedere le Condizioni supplementari per l'uso delle anteprime di Microsoft Azure.

In Azure AI Search, gli indicizzatori per Archiviazione BLOB di Azure, File di Azure e Microsoft OneLake supportano una modalità di analisi markdown per i file Markdown. I file Markdown possono essere indicizzati in due modi:

  • Modalità di analisi uno-a-molti, creazione di più documenti di ricerca per ogni file Markdown
  • Modalità di analisi uno-a-uno, creazione di un documento di ricerca per ogni file Markdown

Suggerimento

Continuare con l'Esercitazione: Cercare dati Markdown da Archiviazione BLOB di Azure dopo aver letto questo articolo.

Prerequisiti

  • Un'origine dati supportata: Archiviazione BLOB di Azure, Archiviazione file di Azure, Microsoft OneLake.

    Per OneLake, assicurarsi di soddisfare tutti i requisiti dell'indicizzatore OneLake.

    Archiviazione di Azure per indicizzatori BLOB e indicizzatori di file è un'istanza standard dalle prestazioni (per utilizzo generico v2) che supporta i livelli di accesso ad accesso frequente e sporadico.

Parametri della modalità di analisi Markdown

I parametri della modalità di analisi vengono specificati in una definizione dell'indicizzatore quando si crea o si aggiorna un indicizzatore.

POST https://[service name].search.windows.net/indexers?api-version=2025-11-01-preview
Content-Type: application/json
api-key: [admin key]

{
  "name": "my-markdown-indexer",
  "dataSourceName": "my-blob-datasource",
  "targetIndexName": "my-target-index",
  "parameters": {
    "configuration": {
      "parsingMode": "markdown",
      "markdownParsingSubmode": "oneToMany",
      "markdownHeaderDepth": "h6"
    }
  },
}

L'indicizzatore BLOB fornisce un parametro submode per determinare l'output della struttura dei documenti di ricerca. La modalità di analisi Markdown offre le opzioni di submode seguenti:

parsingMode submode Cerca documento Description
markdown oneToMany Più documenti per BLOB (impostazione predefinita) Suddivide il Markdown in più documenti di ricerca, ognuno dei quali rappresenta una sezione di contenuto (non intestazione) del file Markdown. È possibile omettere la submode a meno che non si voglia analizzare uno-a-uno.
markdown oneToOne Un solo documento per BLOB Analizza il Markdown in un documento di ricerca, con sezioni mappate a intestazioni specifiche nel file Markdown.

Per la submode oneToMany, è necessario prendere in esame Indicizzazione di un BLOB per produrre molti documenti di ricerca per comprendere il modo in cui l'indicizzatore BLOB gestisce la disambiguazione della chiave del documento per più documenti di ricerca generati dallo stesso BLOB.

Le sezioni successive descrivono ogni submode in modo più dettagliato. Se non si ha familiarità con i client e i concetti dell'indicizzatore, vedere Creare un indicizzatore di ricerca. È anche necessario avere familiarità con i dettagli della configurazione dell'indicizzatore BLOB di base, che non viene ripetuta qui.

Parametri di analisi Markdown facoltativi

I parametri fanno distinzione tra maiuscole e minuscole.

Nome del parametro Valori consentiti Description
markdownHeaderDepth h1, h2, h3, h4, h5h6(default) Questo parametro determina il livello di intestazione più profondo che viene considerato durante l'analisi, consentendo la gestione flessibile della struttura del documento (ad esempio, quando markdownHeaderDepth è impostato su h1, il parser riconosce solo le intestazioni di primo livello che iniziano con "#" e tutte le intestazioni di livello inferiore vengono considerate come testo normale). Se non specificato, per impostazione predefinita viene impostato su h6.

Questa impostazione può essere modificata dopo la creazione iniziale dell'indicizzatore, tuttavia la struttura dei documenti di ricerca risultanti potrebbe cambiare a seconda del contenuto Markdown.

Elementi Markdown supportati

L'analisi del Markdown suddivide solo il contenuto in base alle intestazioni. Tutti gli altri elementi, ad esempio elenchi, blocchi di codice, tabelle e così via, vengono trattati come testo normale e passati in un campo di contenuto.

Contenuto Markdown di esempio

Il contenuto Markdown seguente viene usato per gli esempi in questa pagina:

# Section 1
Content for section 1.

## Subsection 1.1
Content for subsection 1.1.

# Section 2
Content for section 2.

Usare la modalità di analisi uno-a-molti

La modalità di analisi uno-a-molti analizza i file Markdown in più documenti di ricerca, in cui ogni documento corrisponde a una sezione di contenuto specifica del file Markdown in base ai metadati dell'intestazione in quel punto del documento. Il Markdown viene analizzato in base alle intestazioni nei documenti di ricerca, che contengono il contenuto seguente:

  • content: stringa contenente il Markdown non elaborato trovato in una posizione specifica, in base ai metadati dell'intestazione in quel punto del documento.

  • sections: oggetto che contiene campi secondari per i metadati dell'intestazione fino al livello di intestazione desiderato. Ad esempio, quando markdownHeaderDepth è impostato su h3, contiene campi stringa h1, h2 e h3. Questi campi vengono indicizzati eseguendo il mirroring di questa struttura nell'indice o tramite mapping dei campi nel formato /sections/h1, sections/h2 e così via. Per esempi di contesto, vedere le configurazioni dell'indice e dell'indicizzatore negli esempi seguenti. I campi secondari contenuti sono:

    • h1 - Stringa contenente il valore dell'intestazione h1. Stringa vuota se non impostata a questo punto del documento.
    • (Facoltativo) h2- Stringa contenente il valore dell'intestazione h2. Stringa vuota se non impostata a questo punto del documento.
    • (Facoltativo) h3- Stringa contenente il valore dell'intestazione h3. Stringa vuota se non impostata a questo punto del documento.
    • (Facoltativo) h4- Stringa contenente il valore dell'intestazione h4. Stringa vuota se non impostata a questo punto del documento.
    • (Facoltativo) h5- Stringa contenente il valore dell'intestazione h5. Stringa vuota se non impostata a questo punto del documento.
    • (Facoltativo) h6- Stringa contenente il valore dell'intestazione h6. Stringa vuota se non impostata a questo punto del documento.
  • ordinal_position: valore intero che indica la posizione della sezione all'interno della gerarchia del documento. Questo campo viene usato per ordinare le sezioni nella sequenza originale come appaiono nel documento, a partire da una posizione ordinale di 1 e incrementando in sequenza per ogni intestazione.

Schema dell'indice per l'analisi uno-a-molti

Una configurazione di indice di esempio potrebbe essere simile alla seguente:

{
  "name": "my-markdown-index",
  "fields": [
  {
    "name": "id",
    "type": "Edm.String",
    "key": true
  },
  {
    "name": "content",
    "type": "Edm.String",
  },
  {
    "name": "ordinal_position",
    "type": "Edm.Int32"
  },
  {
    "name": "sections",
    "type": "Edm.ComplexType",
    "fields": [
    {
      "name": "h1",
      "type": "Edm.String"
    },
    {
      "name": "h2",
      "type": "Edm.String"
    }]
  }]
}

Definizione dell'indicizzatore per l'analisi uno-a-molti

Se i nomi dei campi e i tipi di dati sono allineati, l'indicizzatore BLOB può dedurre il mapping senza un mapping di campo esplicito presente nella richiesta, pertanto una configurazione dell'indicizzatore corrispondente alla configurazione dell'indice fornita potrebbe essere simile alla seguente:

POST https://[service name].search.windows.net/indexers?api-version=2025-11-01-preview
Content-Type: application/json
api-key: [admin key]

{
  "name": "my-markdown-indexer",
  "dataSourceName": "my-blob-datasource",
  "targetIndexName": "my-target-index",
  "parameters": {
    "configuration": { "parsingMode": "markdown" }
  },
}

Annotazioni

Non è necessario impostare submode in modo esplicito qui perché oneToMany è l'impostazione predefinita.

Output dell'indicizzatore per l'analisi uno-a-molti

Questo file Markdown genera tre documenti di ricerca dopo l'indicizzazione, a causa delle tre sezioni di contenuto. Il documento di ricerca risultante dalla prima sezione contenuto del documento Markdown fornito conterrà i valori seguenti per content, sectionsh1, e h2:

{
  {
    "content": "Content for section 1.\r\n",
    "sections": {
      "h1": "Section 1",
      "h2": ""
    },
    "ordinal_position": 1
  },
  {
    "content": "Content for subsection 1.1.\r\n",
    "sections": {
      "h1": "Section 1",
      "h2": "Subsection 1.1"
    },
    "ordinal_position": 2
  },
  {
    "content": "Content for section 2.\r\n",
    "sections": {
      "h1": "Section 2",
      "h2": ""
    },
    "ordinal_position": 3
  }
}   

Eseguire il mapping di campi uno-a-molti in un indice di ricerca

I mapping dei campi associano un campo di origine a un campo di destinazione in situazioni in cui i nomi e i tipi dei campi non sono identici. Ma i mapping dei campi possono essere usati anche per trovare le corrispondenze tra parti di un documento Markdown e "sollevarle" in campi di primo livello del documento di ricerca.

Nel seguente scenario di esempio viene illustrato questo aspetto. Per altre informazioni sui mapping dei campi in generale, vedere Mapping dei campi.

Si supponga di avere un indice di ricerca con i campi seguenti: raw_content di tipo Edm.String, h1_header di tipo Edm.String e h2_header di tipo Edm.String. Per eseguire il mapping del file Markdown per ottenere la forma desiderata, usare i mapping dei campi seguenti:

"fieldMappings" : [
    { "sourceFieldName" : "/content", "targetFieldName" : "raw_content" },
    { "sourceFieldName" : "/sections/h1", "targetFieldName" : "h1_header" },
    { "sourceFieldName" : "/sections/h2", "targetFieldName" : "h2_header" },
  ]

Il documento di ricerca risultante nell'indice sarà simile al seguente:

{
  {
    "raw_content": "Content for section 1.\r\n",
    "h1_header": "Section 1",
    "h2_header": "",
  },
  {
    "raw_content": "Content for section 1.1.\r\n",
    "h1_header": "Section 1",
    "h2_header": "Subsection 1.1",
  },
  {
    "raw_content": "Content for section 2.\r\n",
    "h1_header": "Section 2",
    "h2_header": "",
  }
}

Usare la modalità di analisi uno-a-uno

Nella modalità di analisi uno-a-uno, l'intero documento Markdown viene indicizzato come un singolo documento di ricerca, mantenendo la gerarchia e la struttura del contenuto originale. Questa modalità è più utile quando i file da indicizzare condividono una struttura comune, in modo da poter usare questa struttura comune nell'indice per rendere i campi pertinenti ricercabili.

Nella definizione dell'indicizzatore impostare parsingMode su "markdown" e usare il parametro facoltativo markdownHeaderDepth per definire la profondità massima dell'intestazione per la suddivisione in blocchi. Se non specificato, il valore predefinito è h6, acquisendo tutte le possibili profondità delle intestazioni.

Il Markdown viene analizzato in base alle intestazioni nei documenti di ricerca, che contengono il contenuto seguente:

  • document_content: contiene il testo del Markdown completo come singola stringa. Questo campo funge da rappresentazione non elaborata del documento di input.

  • sections: matrice di oggetti che contiene la rappresentazione gerarchica delle sezioni all'interno del documento Markdown. Ogni sezione viene rappresentata come oggetto all'interno di questa matrice e acquisisce la struttura del documento in modo annidato corrispondente alle intestazioni e al rispettivo contenuto. I campi sono accessibili tramite mapping dei campi facendo riferimento al percorso, ad esempio /sections/content. Gli oggetti in questa matrice hanno le proprietà seguenti:

    • header_level: stringa che indica il livello dell'intestazione (h1, h2, h3e così via) nella sintassi Markdown. Questo campo consente di comprendere la gerarchia e la strutturazione del contenuto.

    • header_name: stringa contenente il testo dell'intestazione visualizzata nel documento Markdown. Questo campo fornisce un'etichetta o un titolo per la sezione.

    • content: stringa contenente contenuto di testo che segue immediatamente l'intestazione, fino all'intestazione successiva. Questo campo acquisisce le informazioni dettagliate o la descrizione associata all'intestazione. Se non è presente alcun contenuto direttamente in un'intestazione, il valore è una stringa vuota.

    • ordinal_position: valore intero che indica la posizione della sezione all'interno della gerarchia del documento. Questo campo viene usato per ordinare le sezioni nella sequenza originale come appaiono nel documento, a partire da una posizione ordinale di 1 e incrementando in sequenza per ogni blocco di contenuto.

    • sections: matrice che contiene oggetti che rappresentano sottosezioni annidate nella sezione corrente. Questa matrice segue la stessa struttura della matrice di primo livello sections, consentendo la rappresentazione di più livelli di contenuto annidato. Ogni oggetto sottosezione include header_levelanche le proprietà, header_name, content e ordinal_position, abilitando una struttura ricorsiva che rappresenta e gerarchia del contenuto Markdown.

Ecco l'esempio Markdown usato per spiegare gli schemi di indice progettati per ogni modalità di analisi.

# Section 1
Content for section 1.

## Subsection 1.1
Content for subsection 1.1.

# Section 2
Content for section 2.

Schema dell'indice per l'analisi uno-a-uno

Se non si utilizzano mapping di campi, la forma dell'indice deve riflettere la forma del contenuto Markdown. Data la struttura di esempio Markdown con le due sezioni e la sottosezione singola, l'indice dovrebbe essere simile all'esempio seguente:

{
  "name": "my-markdown-index",
  "fields": [
  {
    "name": "id",
    "type": "Edm.String",
    "key": true
  },
  {
    "name": "document_content",
    "type": "Edm.String"
  },
  {
    "name": "sections",
    "type": "Collection(Edm.ComplexType)",
    "fields": [
    {
      "name": "header_level",
      "type": "Edm.String"
    },
    {
      "name": "header_name",
      "type": "Edm.String"
    },
    {
      "name": "content",
      "type": "Edm.String"
    },
    {
      "name": "ordinal_position",
      "type": "Edm.Int32"
    },
    {
      "name": "sections",
      "type": "Collection(Edm.ComplexType)",
      "fields": [
      {
        "name": "header_level",
        "type": "Edm.String"
      },
      {
        "name": "header_name",
        "type": "Edm.String"
      },
      {
        "name": "content",
        "type": "Edm.String"
      },
      {
        "name": "ordinal_position",
        "type": "Edm.Int32"
      }]
    }]
  }]
}

Definizione dell'indicizzatore per l'analisi uno-a-uno

POST https://[service name].search.windows.net/indexers?api-version=2025-11-01-preview
Content-Type: application/json
api-key: [admin key]

{
  "name": "my-markdown-indexer",
  "dataSourceName": "my-blob-datasource",
  "targetIndexName": "my-target-index",
  "parameters": {
    "configuration": {
      "parsingMode": "markdown",
      "markdownParsingSubmode": "oneToOne",
    }
  }
}

Output dell'indicizzatore per l'analisi uno-a-uno

Poiché il Markdown che si vuole indicizzare passa solo a una profondità di h2 ("##"), sono necessari campi sections annidati a una profondità pari a 2 per trovare una corrispondenza. Questa configurazione genera i dati seguenti nell'indice:

  "document_content": "# Section 1\r\nContent for section 1.\r\n## Subsection 1.1\r\nContent for subsection 1.1.\r\n# Section 2\r\nContent for section 2.\r\n",
  "sections": [
    {
      "header_level": "h1",
      "header_name": "Section 1",
      "content": "Content for section 1.",
      "ordinal_position": 1,
      "sections": [
        {
          "header_level": "h2",
          "header_name": "Subsection 1.1",
          "content": "Content for subsection 1.1.",
          "ordinal_position": 2,
        }]
    }],
    {
      "header_level": "h1",
      "header_name": "Section 2",
      "content": "Content for section 2.",
      "ordinal_position": 3,
      "sections": []
    }]
  }

Come si può notare, la posizione ordinale aumenta in base alla posizione del contenuto all'interno del documento.

Si noti anche che se i livelli di intestazione vengono ignorati nel contenuto, la struttura del documento risultante riflette le intestazioni presenti nel contenuto Markdown, che non contengono necessariamente sezioni nidificate per h1 fino a h6 consecutivamente. Ad esempio, quando il documento inizia da h2, il primo elemento nella matrice delle sezioni di primo livello è h2.

Eseguire il mapping di campi uno-a-uno in un indice di ricerca

Se si desidera estrarre campi con nomi personalizzati dal documento, è possibile usare i mapping dei campi a tale scopo. Usando lo stesso esempio di Markdown di prima, prendere in considerazione la configurazione dell'indice seguente:

{
  "name": "my-markdown-index",
  "fields": [
    {
      "name": "document_content",
      "type": "Edm.String",
    },
    {
      "name": "document_title",
      "type": "Edm.String",
    },
    {
      "name": "opening_subsection_title"
      "type": "Edm.String",
    }
    {
      "name": "summary_content",
      "type": "Edm.String",
    }
  ]
}

L'estrazione di campi specifici dal Markdown analizzato viene gestita in modo simile a come i percorsi dei documenti si trovano in outputFieldMappings, ad eccezione del percorso che inizia con /sections invece di /document. Ad esempio, /sections/0/content eseguirà il mapping al contenuto sotto l'elemento nella posizione 0 nella matrice di sezioni.

Un esempio di caso d'uso sicuro potrebbe essere simile al seguente: tutti i file Markdown hanno un titolo del documento nel primo h1, un titolo di sottosezione nel primo h2e un riepilogo nel contenuto del paragrafo finale sotto l'ultimo h1. È possibile usare i mapping dei campi seguenti per indicizzare solo il contenuto:

"fieldMappings" : [
  { "sourceFieldName" : "/content", "targetFieldName" : "raw_content" },
  { "sourceFieldName" : "/sections/0/header_name", "targetFieldName" : "document_title" },
  { "sourceFieldName" : "/sections/0/sections/header_name", "targetFieldName" : "opening_subsection_title" },
  { "sourceFieldName" : "/sections/1/content", "targetFieldName" : "summary_content" },
]

Qui si estraggono solo le parti pertinenti da tale documento. Per usare in modo più efficace questa funzionalità, i documenti che si prevede di indicizzare devono condividere la stessa struttura di intestazione gerarchica.

Il documento di ricerca risultante nell'indice sarà simile al seguente:

{
  "content": "Content for section 1.\r\n",
  "document_title": "Section 1",
  "opening_subsection_title": "Subsection 1.1",
  "summary_content": "Content for section 2."
}

Annotazioni

Questi esempi specificano come usare queste modalità di analisi interamente con o senza mapping dei campi, ma è possibile applicare entrambi in uno scenario se adatto alle proprie esigenze.

Gestione di documenti non aggiornati dalla nuova indicizzazione del Markdown

Quando si usa la modalità di analisi uno-a-molti, la nuova indicizzazione di un file Markdown modificato può comportare documenti obsoleti o duplicati se le sezioni vengono rimosse. Questo comportamento è specifico della modalità uno-a-molti e non si applica all'analisi uno-a-uno.

Panoramica del comportamento

Modalità di analisi uno-a-molti

In modalità oneToMany, ogni sezione Markdown (basata sulle intestazioni) viene indicizzata come documento di ricerca separato. Quando il file viene indicizzato nuovamente:

  • Nessuna eliminazione automatica: l'indicizzatore sovrascrive i documenti esistenti con quelli nuovi, ma non elimina i documenti che non corrispondono più ad alcun contenuto nel file aggiornato.
  • Potenziale di duplicati: questo problema si verifica in modo specifico solo quando vengono eliminate più sezioni rispetto all'inserimento tra esecuzioni di indicizzazione. In questi casi, i documenti lasciati dalla versione precedente rimangono nell'indice, causando voci non aggiornate che non riflettono più lo stato corrente del file di origine.

Modalità di analisi uno-a-uno

In modalità oneToOne, l'intero file Markdown viene indicizzato come singolo documento di ricerca. Quando il file viene indicizzato nuovamente:

  • Comportamento di sovrascrittura: il documento esistente viene sostituito interamente con la nuova versione.
  • Nessuna sezione non aggiornata: quando il file viene indicizzato nuovamente, il documento esistente viene sostituito con la versione aggiornata e il contenuto rimosso non è più incluso. L'unica eccezione è se il percorso del file o l'URI BLOB cambia, il che potrebbe comportare la creazione di un nuovo documento insieme a quello precedente.

Soluzioni alternative

Per garantire che l'indice rifletta lo stato corrente dei file Markdown, considerare uno degli approcci seguenti:

Opzione 1. Eliminazione temporanea con metadati

Questo metodo usa un'eliminazione temporanea per eliminare i documenti associati a un BLOB specifico. Per altre informazioni, vedere Rilevamento delle modifiche ed eliminazione tramite indicizzatori per Archiviazione di Azure in Azure AI Search.

Passaggi:

  1. Contrassegnare il BLOB come eliminato impostando un campo di metadati.
  2. Consentire l'esecuzione dell'indicizzatore. Elimina tutti i documenti nell'indice associato a tale BLOB.
  3. Rimuovere il marcatore di eliminazione temporanea e indicizzare nuovamente il file.

Opzione 2. Usare l'API Elimina

Prima di indicizzare nuovamente un file Markdown modificato, eliminare in modo esplicito i documenti esistenti associati a tale file usando l'API di eliminazione. È possibile:

  • Identificare manualmente i singoli documenti non aggiornati identificando i duplicati nell'indice da eliminare. Questo può essere fattibile per piccole e ben comprese modifiche, ma può richiedere molto tempo.
  • (Scelta consigliata) Rimuovere tutti i documenti generati dallo stesso file padre prima di indicizzare nuovamente, assicurandosi che le incoerenze vengano evitate.

Passaggi:

  1. Identificare l'ID dei documenti associati al file. Usare una query come l'esempio seguente per recuperare gli ID chiave del documento (ad esempio, id, chunk_id e così via) per tutti i documenti associati a un file specifico. Sostituire metadata_storage_path con il campo appropriato nell'indice mappato al percorso del file o all'URI del BLOB. Il valore del campo deve essere una chiave.

    GET https://[service name].search.windows.net/indexes/[index name]/docs?api-version=2025-05-01-preview
    Content-Type: application/json
    api-key: [admin key]
    
    
      {  
          "filter": "metadata_storage_path eq 'https://<storage-account>.blob.core.windows.net/<container-name>/<file-name>.md'",
          "select": "id"
      }
    
  2. Eseguire una richiesta di eliminazione per i documenti con le chiavi identificate.

    POST https://[service name].search.windows.net/indexes/[index name]/docs/index?api-version=2025-05-01-preview
    Content-Type: application/json
    api-key: [admin key]
    
    {  
      "value": [  
        {  
          "@search.action": "delete",  
          "id": "aHR0c...jI1"  
        },
        {  
          "@search.action": "delete",  
          "id": "aHR0...MQ2"  
        }  
      ]  
    }
    
  3. Indicizzare nuovamente il file aggiornato.

Passaggi successivi