Tutorial: Blobs de Markdown aninhados de índice do Armazenamento do Azure usando REST

Nota

Esta funcionalidade está atualmente em pré-visualização pública. Esta pré-visualização é fornecida sem um contrato de nível de serviço e não é recomendada para cargas de trabalho de produção. Algumas funcionalidades poderão não ser suportadas ou poderão ter capacidades limitadas. Para obter mais informações, veja Termos Suplementares de Utilização para Pré-visualizações do Microsoft Azure.

A Pesquisa de IA do Azure pode indexar documentos e matrizes de Markdown no Armazenamento de Blobs do Azure usando um indexador que sabe como ler dados de Markdown.

Este tutorial mostra-lhe como indexar ficheiros Markdown indexados usando o oneToMany modo de análise sintática Markdown e as APIs REST do Serviço de Pesquisa.

Neste tutorial, você:

  • Configurar dados de exemplo e definir uma fonte de dados azureblob
  • Criar um índice do Azure AI Search para conter conteúdo pesquisável
  • Criar e executar um indexador para ler o contêiner e extrair conteúdo pesquisável
  • Pesquisar o índice que acabou de criar

Pré-requisitos

Nota

Você pode usar um serviço de pesquisa gratuito para este tutorial. O nível Gratuito limita você a três índices, três indexadores e três fontes de dados. Este tutorial cria um de cada. Antes de começar, certifique-se de que o seu serviço tem espaço para aceitar os novos recursos.

Preparar dados de exemplo

Criar um ficheiro Markdown

Copie e cole o Markdown a seguir em um arquivo chamado sample_markdown.md. Os dados de exemplo são um único arquivo Markdown contendo vários elementos Markdown. Escolhemos um arquivo Markdown para ficar abaixo dos limites de armazenamento do nível Gratuito.

# Project Documentation

## Introduction
This document provides a complete overview of the **Markdown Features** used within this project. The following sections demonstrate the richness of Markdown formatting, with examples of lists, tables, links, images, blockquotes, inline styles, and more.

---

## Table of Contents
1. [Headers](#headers)
2. [Introduction](#introduction)
3. [Basic Text Formatting](#basic-text-formatting)
4. [Lists](#lists)
5. [Blockquotes](#blockquotes)
6. [Images](#images)
7. [Links](#links)
8. [Tables](#tables)
9. [Code Blocks and Inline Code](#code-blocks-and-inline-code)
10. [Horizontal Rules](#horizontal-rules)
11. [Inline Elements](#inline-elements)
12. [Escaping Characters](#escaping-characters)
13. [HTML Elements](#html-elements)
14. [Emojis](#emojis)
15. [Footnotes](#footnotes)
16. [Task Lists](#task-lists)
17. [Conclusion](#conclusion)

---

## Headers
Markdown supports six levels of headers. Use `#` to create headers:
"# Project Documentation" at the top of the document is an example of an h1 header.
"## Headers" above is an example of an h2 header.
### h3 example
#### h4 example
##### h5 example
###### h6 example
This is an example of content underneath a header.

## Basic Text Formatting
You can apply various styles to your text:
- **Bold**: Use double asterisks or underscores: `**bold**` or `__bold__`.
- *Italic*: Use single asterisks or underscores: `*italic*` or `_italic_`.
- ~~Strikethrough~~: Use double tildes: `~~strikethrough~~`.

## Lists

### Ordered List
1. First item  
2. Second item  
3. Third item  

### Unordered List
- Item A  
- Item B  
- Item C  

### Nested List
1. Parent item  
   - Child item  
   - Child item  

## Blockquotes
> This is a blockquote.  
> Blockquotes are great for emphasizing important information.  
>> Nested blockquotes are also possible!

## Images
![Markdown Logo](https://markdown-here.com/img/icon256.png)

## Links
[Visit Markdown Guide](https://www.markdownguide.org)

## Tables

| Syntax      | Description | Example       |
|-------------|-------------|---------------|
| Header      | Title       | Header Cell   |
| Paragraph   | Text block  | Row Content   |

## Code Blocks and Inline Code

### Inline Code
Use backticks to create `inline code`.

### Code Block
```javascript
// JavaScript example
function greet(name) {
  console.log(`Hello, ${name}!`);
}
greet('World');
```

## Horizontal Rules
Use three or more dashes or underscores to create a horizontal rule.

---
___

## Inline Elements
Sometimes, it’s useful to include `inline code` to highlight code-like content.  

You can also emphasize text like *this* or make it **bold**.

## Escaping Characters
To render special Markdown characters, use backslashes:
- \*Asterisks\*
- \#Hashes\#
- \[Brackets\]

## HTML Elements
You can mix HTML tags with Markdown:

<table>
  <tr>
    <th>HTML Table</th>
    <th>With Markdown</th>
  </tr>
  <tr>
    <td>Row 1</td>
    <td>Data 1</td>
  </tr>
</table>

## Emojis
Markdown supports some basic emojis:
- :smile: 😄  
- :rocket: 🚀  
- :checkered_flag: 🏁  

## Footnotes
This is an example of a footnote[^1]. Footnotes allow you to add notes without cluttering the main text.

[^1]: This is the content of the footnote.

## Task Lists
- [x] Complete the introduction  
- [ ] Add more examples  
- [ ] Review the document 

## Conclusion
Markdown is a lightweight yet powerful tool for writing documentation. It supports a variety of formatting options while maintaining simplicity and readability.

Thank you for reviewing this example!

Carrega o ficheiro e obtém uma cadeia de ligação

Siga estas instruções para carregar o sample_markdown.md ficheiro num contentor na sua conta Azure Storage. Deves também obter a cadeia de ligação à conta de armazenamento. Regista a cadeia de ligação e o nome do contentor para uso posterior.

Copiar um URL de serviço de pesquisa e uma chave de API

Para este tutorial, as conexões com o Azure AI Search exigem um ponto de extremidade e uma chave de API. Você pode obter esses valores no portal do Azure. Para métodos de conexão alternativos, consulte Identidades gerenciadas.

  1. Vá para o seu serviço de pesquisa no portal do Azure.

  2. No painel esquerdo, selecione Visão geral.

  3. Tome nota do URL, que deve ter a aparência de https://my-service.search.windows.net.

  4. No painel esquerdo, selecione Teclas de configurações>.

  5. Registe uma chave de administrador para obter direitos completos sobre o serviço. Existem duas chaves de administrador intercambiáveis, fornecidas para continuidade operacional caso seja necessário substituir uma. Pode usar qualquer uma das teclas nas solicitações para adicionar, modificar e eliminar objetos.

    Captura de ecrã do URL e das chaves de API no portal do Azure.

Configurar o arquivo REST

  1. Crie um ficheiro no Visual Studio Code.

  2. Forneça valores para variáveis usadas no pedido.

    @baseUrl = PUT-YOUR-SEARCH-SERVICE-ENDPOINT-HERE
    @apiKey = PUT-YOUR-ADMIN-API-KEY-HERE
    @storageConnectionString = PUT-YOUR-STORAGE-CONNECTION-STRING-HERE
    @blobContainer = PUT-YOUR-CONTAINER-NAME-HERE
    
  3. Guarde o ficheiro usando uma extensão de ficheiro .rest ou .http.

Para obter ajuda com o cliente REST, consulte Guia de início rápido: pesquisa de texto completo usando REST.

Criar uma origem de dados

Create Data Source (REST) cria uma conexão de fonte de dados que especifica quais dados indexar.

### Create a data source
POST {{baseUrl}}/datasources?api-version=2025-09-01  HTTP/1.1
Content-Type: application/json
api-key: {{apiKey}}

{
    "name" : "sample-markdown-ds",
    "description": null,
    "type": "azureblob",
    "subtype": null,
    "credentials": {
        "connectionString": "{{storageConnectionString}}"
    },
    "container": {
        "name": "{{blobContainer}}",
        "query": null
    },
    "dataChangeDetectionPolicy": null,
    "dataDeletionDetectionPolicy": null
}

Envie o pedido. A resposta deve ser semelhante a:

HTTP/1.1 201 Created
Transfer-Encoding: chunked
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
ETag: "0x8DCF52E926A3C76"
Location: https://<YOUR-SEARCH-SERVICE-NAME>.search.windows.net:443/datasources('sample-markdown-ds')?api-version=2025-09-01
Server: Microsoft-IIS/10.0
Strict-Transport-Security: max-age=2592000, max-age=15724800; includeSubDomains
Preference-Applied: odata.include-annotations="*"
OData-Version: 4.0
request-id: 0714c187-217e-4d35-928a-5069251e5cba
elapsed-time: 204
Date: Fri, 25 Oct 2024 19:52:35 GMT
Connection: close

{
  "@odata.context": "https://<YOUR-SEARCH-SERVICE-NAME>.search.windows.net/$metadata#datasources/$entity",
  "@odata.etag": "\"0x8DCF52E926A3C76\"",
  "name": "sample-markdown-ds",
  "description": null,
  "type": "azureblob",
  "subtype": null,
  "credentials": {
    "connectionString": null
  },
  "container": {
    "name": "markdown-container",
    "query": null
  },
  "dataChangeDetectionPolicy": null,
  "dataDeletionDetectionPolicy": null,
  "encryptionKey": null,
  "identity": null
}

Criar um índice

Criar índice (REST) cria um índice de pesquisa no seu serviço de pesquisa. Um índice especifica todos os campos e seus atributos.

Na análise um-para-muitos, o documento de pesquisa define o lado "muitos" da relação. Os campos especificados no índice determinam a estrutura do documento de pesquisa.

Você só precisa de campos para os elementos Markdown suportados pelo analisador. Estes campos são:

  • content: Uma cadeia de caracteres que contém a marcação bruta encontrada em um local específico, com base nos metadados do cabeçalho nesse ponto do documento.

  • sections: Um objeto que contém subcampos para os metadados do cabeçalho até o nível de cabeçalho desejado. Por exemplo, quando markdownHeaderDepth é definido como h3, contém campos h1de cadeia de caracteres , h2e h3. Estes campos são indexados espelhando esta estrutura no índice, ou através de mapeamentos de campo no formato /sections/h1, sections/h2, etc. Para obter exemplos no contexto, consulte as configurações de índice e indexador nos exemplos a seguir. Os subcampos contidos são:

    • h1 - Uma cadeia de caracteres que contém o valor do cabeçalho h1. Cadeia de caracteres vazia se não estiver definida neste ponto do documento.
    • (Opcional) h2- Uma string contendo o valor do cabeçalho h2. Cadeia de caracteres vazia se não estiver definida neste ponto do documento.
    • (Opcional) h3- Uma string contendo o valor do cabeçalho h3. Cadeia de caracteres vazia se não estiver definida neste ponto do documento.
    • (Opcional) h4- Uma string contendo o valor do cabeçalho h4. Cadeia de caracteres vazia se não estiver definida neste ponto do documento.
    • (Opcional) h5- Uma string contendo o valor do cabeçalho h5. Cadeia de caracteres vazia se não estiver definida neste ponto do documento.
    • (Opcional) h6- Uma string contendo o valor do cabeçalho h6. Cadeia de caracteres vazia se não estiver definida neste ponto do documento.
  • ordinal_position: Um valor inteiro que indica a posição da seção dentro da hierarquia de documentos. Este campo é utilizado para ordenar as secções na sua sequência original tal como aparecem no documento, começando com uma posição ordinal de 1 e incrementando sequencialmente para cada bloco de conteúdo.

Essa implementação usa mapeamentos de campo no indexador para mapear do conteúdo enriquecido para o índice. Para obter mais informações sobre a estrutura de documento um-para-muitos analisada, consulte Blobs de Markdown de índice.

Este exemplo fornece exemplos de como indexar dados com e sem mapeamentos de campo. Neste caso, sabemos que h1 contém o título do documento, para que possamos mapeá-lo para um campo chamado title. Também mapearemos os h2 campos e h3 para h2_subheader e h3_subheader, respectivamente. Os content campos e ordinal_position não requerem mapeamento porque são extraídos do Markdown diretamente para campos usando esses nomes. Para obter um exemplo de um esquema de índice completo que não requer mapeamentos de campo, consulte o final desta seção.

### Create an index
POST {{baseUrl}}/indexes?api-version=2025-09-01  HTTP/1.1
Content-Type: application/json
api-key: {{apiKey}}

{
  "name": "sample-markdown-index",  
  "fields": [
    {"name": "id", "type": "Edm.String", "key": true, "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true},
    {"name": "content", "type": "Edm.String", "key": false, "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true},
    {"name": "title", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true},
    {"name": "h2_subheader", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true},
    {"name": "h3_subheader", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true},
    {"name": "ordinal_position", "type": "Edm.Int32", "searchable": false, "retrievable": true, "filterable": true, "facetable": true, "sortable": true}
  ]
}

Esquema de índice em uma configuração sem mapeamentos de campo

Os mapeamentos de campo permitem manipular e filtrar conteúdo enriquecido para se ajustar à forma de índice desejada. No entanto, você pode querer apenas pegar o conteúdo enriquecido diretamente. Nesse caso, o esquema teria a seguinte aparência:

{
  "name": "sample-markdown-index",
  "fields": [
    {"name": "id", "type": "Edm.String", "key": true, "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true},
    {"name": "content", "type": "Edm.String", "key": false, "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true},
    {"name": "sections", 
      "type": "Edm.ComplexType", 
      "fields": [
        {"name": "h1", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true},
        {"name": "h2", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true},
        {"name": "h3", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true}
      ]
    },
    {"name": "ordinal_position", "type": "Edm.Int32", "searchable": false, "retrievable": true, "filterable": true, "facetable": true, "sortable": true}
  ]
}

Para reiterar, temos subcampos até h3 no objeto sections porque markdownHeaderDepth está definido como h3.

Se você usar esse esquema, certifique-se de ajustar as solicitações posteriores de acordo. Isso exigirá a remoção dos mapeamentos de campo da configuração do indexador e a atualização das consultas de pesquisa para usar os nomes de campo correspondentes.

Criar e executar um indexador

Criar indexador cria um indexador no seu serviço de pesquisa. Um indexador se conecta à fonte de dados, carrega e indexa dados e, opcionalmente, fornece um agendamento para automatizar a atualização de dados.

### Create and run an indexer
POST {{baseUrl}}/indexers?api-version=2025-09-01  HTTP/1.1
Content-Type: application/json
api-key: {{apiKey}}

{
  "name": "sample-markdown-indexer",
  "dataSourceName": "sample-markdown-ds",
  "targetIndexName": "sample-markdown-index",
  "parameters" : { 
    "configuration": { 
      "parsingMode": "markdown",
      "markdownParsingSubmode": "oneToMany",
      "markdownHeaderDepth": "h3"
      }
    },
  "fieldMappings" : [ 
    {
      "sourceFieldName": "/sections/h1",
      "targetFieldName": "title",
      "mappingFunction": null
    }
  ]
}

Pontos principais:

  • O indexador analisará apenas cabeçalhos até h3. Quaisquer cabeçalhos de nível inferior (h4,,)h5 são tratados como texto simples e aparecem no h6contentcampo. É por isso que os mapeamentos de índice e campo só existem até uma profundidade de h3.

  • Os campos content e ordinal_position não exigem mapeamento de campo porque existem com esses nomes no conteúdo enriquecido.

Executar consultas

Pode começar a pesquisar assim que o primeiro documento for carregado.

### Query the index
POST {{baseUrl}}/indexes/sample-markdown-index/docs/search?api-version=2025-09-01  HTTP/1.1
Content-Type: application/json
api-key: {{apiKey}}
  
{
  "search": "*",
  "count": true
}

Envie o pedido. Esta é uma consulta de pesquisa de texto completo não especificada que retorna todos os campos marcados como recuperáveis no índice, juntamente com uma contagem de documentos. A resposta deve ser semelhante a:

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
Server: Microsoft-IIS/10.0
Strict-Transport-Security: max-age=2592000, max-age=15724800; includeSubDomains
Preference-Applied: odata.include-annotations="*"
OData-Version: 4.0
request-id: 6b94e605-55e8-47a5-ae15-834f926ddd14
elapsed-time: 77
Date: Fri, 25 Oct 2024 20:22:58 GMT
Connection: close

{
  "@odata.context": "https://<YOUR-SEARCH-SERVICE-NAME>.search.windows.net/indexes('sample-markdown-index')/$metadata#docs(*)",
  "@odata.count": 22,
  "value": [
    <22 search documents here>
  ]
}

Adicione um search parâmetro para pesquisar em uma cadeia de caracteres.

### Query the index
POST {{baseUrl}}/indexes/sample-markdown-index/docs/search?api-version=2025-09-01  HTTP/1.1
Content-Type: application/json
api-key: {{apiKey}}
  
{
  "search": "h4",
  "count": true
}

Envie o pedido. A resposta deve ser semelhante a:

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
Server: Microsoft-IIS/10.0
Strict-Transport-Security: max-age=2592000, max-age=15724800; includeSubDomains
Preference-Applied: odata.include-annotations="*"
OData-Version: 4.0
request-id: ec5d03f1-e3e7-472f-9396-7ff8e3782105
elapsed-time: 52
Date: Fri, 25 Oct 2024 20:26:29 GMT
Connection: close

{
  "@odata.context": "https://<YOUR-SEARCH-SERVICE-NAME>.search.windows.net/indexes('sample-markdown-index')/$metadata#docs(*)",
  "@odata.count": 1,
  "value": [
    {
      "@search.score": 0.8744742,
      "section_id": "aHR0cHM6Ly9hcmphZ2Fubmpma2ZpbGVzLmJsb2IuY29yZS53aW5kb3dzLm5ldC9tYXJrZG93bi10dXRvcmlhbC9zYW1wbGVfbWFya2Rvd24ubWQ7NA2",
      "content": "#### h4 example\r\n##### h5 example\r\n###### h6 example\r\nThis is an example of content underneath a header.\r\n",
      "title": "Project Documentation",
      "h2_subheader": "Headers",
      "h3_subheader": "h3 example",
      "ordinal_position": 4
    }
  ]
}

Pontos principais:

  • Como o markdownHeaderDepth está definido como h3, o h4, h5e h6 os cabeçalhos são tratados como texto sem formatação, por isso aparecem no content campo.

  • A posição ordinal aqui é 4. Este conteúdo aparece em quarto lugar entre as 22 seções de conteúdo total.

Adicione um select parâmetro para limitar os resultados a menos campos. Adicione um filter para restringir ainda mais a pesquisa.

### Query the index
POST {{baseUrl}}/indexes/sample-markdown-index/docs/search?api-version=2025-09-01  HTTP/1.1
Content-Type: application/json
api-key: {{apiKey}}
  
{
  "search": "Markdown",
  "count": true,
  "select": "title, content, h2_subheader",
  "filter": "h2_subheader eq 'Conclusion'"
}
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
Server: Microsoft-IIS/10.0
Strict-Transport-Security: max-age=2592000, max-age=15724800; includeSubDomains
Preference-Applied: odata.include-annotations="*"
OData-Version: 4.0
request-id: a6f9bd46-a064-4e28-818f-ea077618014b
elapsed-time: 35
Date: Fri, 25 Oct 2024 20:36:10 GMT
Connection: close

{
  "@odata.context": "https://<YOUR-SEARCH-SERVICE-NAME>.search.windows.net/indexes('sample-markdown-index')/$metadata#docs(*)",
  "@odata.count": 1,
  "value": [
    {
      "@search.score": 1.1029507,
      "content": "Markdown is a lightweight yet powerful tool for writing documentation. It supports a variety of formatting options while maintaining simplicity and readability.\r\n\r\nThank you for reviewing this example!",
      "title": "Project Documentation",
      "h2_subheader": "Conclusion"
    }
  ]
}

Para filtros, você também pode usar operadores lógicos (e, ou, não) e operadores de comparação (eq, ne, gt, lt, ge, le). As comparações de strings são sensíveis a maiúsculas e minúsculas. Para obter mais informações e exemplos, consulte Criar uma consulta.

Nota

O $filter parâmetro só funciona em campos que foram marcados como filtráveis na criação do índice.

Repor e executar novamente

Os indexadores podem ser redefinidos para limpar o histórico de execução, o que permite uma nova execução completa. As seguintes solicitações GET são para redefinição, seguidas de reexecução.

### Reset the indexer
POST {{baseUrl}}/indexers/sample-markdown-indexer/reset?api-version=2025-09-01  HTTP/1.1
api-key: {{apiKey}}

### Run the indexer
POST {{baseUrl}}/indexers/sample-markdown-indexer/run?api-version=2025-09-01  HTTP/1.1
api-key: {{apiKey}}

### Check indexer status 
GET {{baseUrl}}/indexers/sample-markdown-indexer/status?api-version=2025-09-01  HTTP/1.1
api-key: {{apiKey}}

Limpar recursos

Quando estiver a trabalhar na sua própria subscrição, ao terminar um projeto, é uma boa ideia remover os recursos de que já não necessita. Os recursos deixados em execução podem custar-lhe dinheiro. Pode eliminar recursos individualmente ou eliminar o grupo de recursos para eliminar todo o conjunto de recursos.

Você pode usar o portal do Azure para excluir índices, indexadores e fontes de dados.

Próximos passos

Agora que você está familiarizado com os conceitos básicos da indexação de Blobs do Azure, dê uma olhada mais de perto na configuração do indexador para blobs Markdown no Armazenamento do Azure: