チュートリアル: 入れ子になった Markdown BLOB に REST を使用してAzure Storageからインデックスを作成する

Azure AI 検索では、Markdown データの読み取り方法を知っている indexer を使用して、Azure Blob Storage内の Markdown ドキュメントと配列のインデックスを作成できます。

このチュートリアルでは、 oneToMany Markdown 解析モードと Search Service REST API を使用して Markdown ファイルのインデックスを作成する方法について説明します。

このチュートリアルでは、次の操作を行います。

  • サンプル データを設定し、 azureblob データ ソースを構成する
  • 検索可能なコンテンツを含むAzure AI 検索 インデックスを作成する
  • インデクサーを作成して実行してコンテナーを読み取り、検索可能なコンテンツを抽出する
  • 先ほど作成したインデックスを検索する

前提 条件

メモ

このチュートリアルでは、無料の検索サービスを使用できます。 Free レベルでは、3 つのインデックス、3 つのインデクサー、3 つのデータ ソースに制限されます。 このチュートリアルでは、それぞれ 1 つを作成します。 開始する前に、サービスに新しいリソースを受け入れる余地があることを確認します。

サンプル データを準備する

Markdown ファイルを作成する

次の Markdown をコピーして、 sample_markdown.mdという名前のファイルに貼り付けます。 サンプル データは、さまざまな Markdown 要素を含む 1 つの Markdown ファイルです。 Free レベルのストレージ制限の下に留まるマークダウン ファイルを 1 つ選択しました。

# 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!

ファイルをアップロードして接続文字列を取得する

これらの手順 に従って、Azure Storage アカウントのコンテナーに sample_markdown.md ファイルをアップロードします。 ストレージ アカウントの接続文字列も取得する必要があります。 後で使用するために、接続文字列とコンテナー名をメモしておきます。

検索サービスの URL と API キーをコピーする

このチュートリアルでは、Azure AI 検索への接続にはエンドポイントと API キーが必要です。 これらの値は、Azure ポータルから取得できます。 別の接続方法については、「 マネージド ID」を参照してください。

  1. Azure ポータルで検索サービスに移動します。

  2. 左側のウィンドウで、[ 概要] を選択します。

  3. URL を書き留めます。これは https://my-service.search.windows.netのようになります。

  4. 左側のウィンドウで、[設定]>[キー] を選択します。

  5. サービスに対する完全な権限については、管理者キーをメモしておきます。 1 つをロールオーバーする必要がある場合に備えて、ビジネス継続性のために提供される 2 つの交換可能な管理キーがあります。 オブジェクトの追加、変更、および削除の要求では、いずれかのキーを使用できます。

    Azure ポータル内の URL と API キーのスクリーンショット。

REST ファイルを設定する

  1. Visual Studio Codeでファイルを作成します。

  2. 要求で使用される変数の値を指定します。

    @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. .restまたは.httpファイル拡張子を使用してファイルを保存します。

REST クライアントのヘルプについては、「 クイック スタート: REST を使用したフルテキスト検索」を参照してください。

データ ソースを作成する

データ ソース - 作成 (REST API) は、インデックスを作成するデータを指定するデータ ソース接続を作成します。

### Create a data source
POST {{baseUrl}}/datasources?api-version=2026-04-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
}

要求を送信します。 応答は次のようになります。

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=2026-04-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
}

インデックスを作成する

インデックス - Create (REST API) は、検索サービスに検索インデックスを作成します。 インデックスは、すべてのフィールドとその属性を指定します。

一対多解析では、検索ドキュメントによってリレーションシップの "多" 側が定義されます。 インデックスで指定するフィールドによって、検索ドキュメントの構造が決まります。

パーサーがサポートする Markdown 要素のフィールドのみが必要です。 これらのフィールドは次のとおりです。

  • content: ドキュメント内のその時点のヘッダー メタデータに基づいて、特定の場所で見つかった未加工の Markdown を含む文字列。

  • sections: 目的のヘッダー レベルまでのヘッダー メタデータのサブフィールドを含むオブジェクト。 たとえば、 markdownHeaderDepthh3に設定されている場合は、文字列フィールド h1h2、および h3が含まれます。 これらのフィールドは、インデックス内のこの構造をミラーリングするか、 /sections/h1/sections/h2などの形式でフィールド マッピングを使用してインデックスを作成します。 コンテキスト内の例については、次のサンプルのインデックスとインデクサーの構成を参照してください。 含まれるサブフィールドは次のとおりです。

    • h1 - h1 ヘッダー値を含む文字列。 ドキュメントのこの時点で設定されていない場合は空の文字列。
    • (省略可能) h2- h2 ヘッダー値を含む文字列。 ドキュメントのこの時点で設定されていない場合は空の文字列。
    • (省略可能) h3- h3 ヘッダー値を含む文字列。 ドキュメントのこの時点で設定されていない場合は空の文字列。
    • (省略可能) h4- h4 ヘッダー値を含む文字列。 ドキュメントのこの時点で設定されていない場合は空の文字列。
    • (省略可能) h5- h5 ヘッダー値を含む文字列。 ドキュメントのこの時点で設定されていない場合は空の文字列。
    • (省略可能) h6- h6 ヘッダー値を含む文字列。 ドキュメントのこの時点で設定されていない場合は空の文字列。
  • ordinal_position: ドキュメント階層内のセクションの位置を示す整数値。 このフィールドは、文書に表示される元の順序でセクションを並べ替える場合に使用されます。序数の位置は 1 から始まり、コンテンツ ブロックごとに順番にインクリメントされます。

この実装では、インデクサーの フィールド マッピング を使用して、エンリッチされたコンテンツからインデックスにマップします。 解析された一対多ドキュメント構造の詳細については、「 インデックス マークダウン BLOB」を参照してください。

この例では、フィールド マッピングの有無にかかわらず、データのインデックスを作成する方法のサンプルを示します。 この場合、 h1 にはドキュメントのタイトルが含まれており、 titleという名前のフィールドにマップされます。 h2フィールドとh3 フィールドはそれぞれ、h2_subheaderh3_subheaderにマップされます。 contentフィールドとordinal_position フィールドは、Markdown からそれらの名前を使用してフィールドに直接抽出されるため、マッピングは必要ありません。 フィールド マッピングを必要としない完全なインデックス スキーマの例については、このセクションの最後を参照してください。

### Create an index
POST {{baseUrl}}/indexes?api-version=2026-04-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}
  ]
}

フィールド マッピングのない構成のインデックス スキーマ

フィールド マッピングを使用すると、エンリッチされたコンテンツを操作してフィルター処理し、目的のインデックス図形に収めることができます。 しかし、エンリッチされたコンテンツを直接受け取りたいと思うかもしれません。 その場合、スキーマは次のようになります。

{
  "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}
  ]
}

繰り返しになりますが、h3markdownHeaderDepthに設定されているため、sections オブジェクトには最大h3のサブフィールドがあります。

このスキーマを使用する場合は、それに応じて後の要求を調整してください。 そのためには、インデクサー構成からフィールド マッピングを削除し、対応するフィールド名を使用するように検索クエリを更新する必要があります。

インデクサーを作成して実行する

インデクサー - Create (REST API) は、検索サービスにインデクサーを作成します。 インデクサーはデータ ソースに接続し、データの読み込みとインデックス作成を行い、必要に応じてデータ更新を自動化するスケジュールを提供します。

### Create and run an indexer
POST {{baseUrl}}/indexers?api-version=2026-04-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
    }
  ]
}

重要なポイント:

  • インデクサーは、 h3までのヘッダーのみを解析します。 下位レベルのヘッダー (h4h5h6) はプレーン テキストとして扱われ、 content フィールドに表示されます。 このため、インデックスとフィールドのマッピングは、 h3の深さまでしか存在しません。

  • contentフィールドとordinal_position フィールドは、エンリッチされたコンテンツ内にそれらの名前と共に存在するため、フィールド マッピングは必要ありません。

クエリの実行

最初のドキュメントが読み込まれたらすぐに検索を開始できます。

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

要求を送信します。 これは、インデックスで取得可能としてマークされたすべてのフィールドとドキュメント数を返す、指定されていないフルテキスト検索クエリです。 応答は次のようになります。

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

文字列を検索する search パラメーターを追加します。

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

要求を送信します。 応答は次のようになります。

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

重要なポイント:

  • markdownHeaderDepthh3に設定されているため、h4h5、およびh6ヘッダーはプレーンテキストとして扱われるため、content フィールドに表示されます。

  • ここでの序数の位置は 4です。 このコンテンツは、合計 22 のコンテンツ セクションのうち 4 番目に表示されます。

selectパラメーターを追加して、結果を少数のフィールドに制限します。 filterを追加して、検索をさらに絞り込みます。

### Query the index
POST {{baseUrl}}/indexes/sample-markdown-index/docs/search?api-version=2026-04-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"
    }
  ]
}

フィルターの場合は、論理演算子 (and、or、not) と比較演算子 (eq、ne、gt、lt、ge、le) を使用することもできます。 文字列比較では大文字と小文字が区別されます。 詳細と例については、「 クエリの作成」を参照してください。

メモ

$filter パラメーターは、インデックスの作成時にフィルター可能とマークされたフィールドでのみ機能します。

リセットして再実行する

インデクサーをリセットして実行履歴をクリアすると、完全な再実行が可能になります。 次の要求は、インデクサーをリセットして再実行します。

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

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

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

リソースのクリーンアップ

自分のサブスクリプションで作業している場合は、プロジェクトの最後に、不要になったリソースを削除することをお勧めします。 リソースをそのままにしていると、コストがかかる可能性があります。 リソースを個別に削除することも、リソース グループを削除してリソースのセット全体を削除することもできます。

Azure ポータルを使用して、インデックス、インデクサー、データ ソースを削除できます。

次の手順

AZURE BLOB インデックス作成の基本を理解したら、Azure Storageの Markdown BLOB のインデクサー構成を詳しく見てみましょう。