註
Azure AI 搜尋服務 可透過 Azure 入口網站、REST API 及 Azure SDK 取得。 它同時也是 Foundry IQ 的基礎,這是一個管理式知識層,能將企業內容轉化為可重複使用、權限感知的知識庫,供 Microsoft Foundry 入口網站中的代理使用。
Important
這些功能支援與其他 Microsoft 服務 及第三方服務的連結。 使用這些服務須遵守其各自的條款,可能導致資料處理或儲存超出 Azure 合規邊界,以及資料流入 Azure 合規邊界。
你有責任管理資料是否會超出組織的合規與地理邊界及相關影響,並確保適當的權限、邊界與核准被提供。
你有責任仔細審查並測試你在特定使用情境中所建置的應用程式,並做出所有適當的決策與客製化。 這包括實施你自己負責任的 AI 緩解措施,例如元提示、內容過濾器或其他安全系統,並確保你的應用程式符合適當的品質、可靠性、安全性與可信度標準。 欲了解更多資訊,請參閱Azure AI 搜尋服務透明度說明。
在 Azure AI 搜尋服務 中,Azure Blob 儲存體、Azure 檔案儲存體 和 Microsoft OneLake 的索引器支援 Markdown 檔案的 markdown 解析模式。 Markdown 檔案可以透過兩種方式進行索引:
- 一對多解析模式,能在每個 Markdown 檔案中建立多個搜尋文件。
- 一對一解析模式,即每個 Markdown 檔案生成一個搜尋文件。
提示
閱讀完本文後,請繼續閱讀教學:從Azure Blob 儲存體搜尋Markdown資料。
先決條件
一個支援的資料來源:Azure Blob 儲存體、Azure File Storage、Microsoft OneLake。
對於 OneLake,務必符合 OneLake 索引器的所有要求。
Azure 儲存體 for blob indexers and file indexers(預覽版)是一個標準效能(通用 v2)實例,支援熱層級與冷層存取。
標記語法解析模式參數
解析模式參數會在建立或更新索引器時,在索引器的定義中指定。
POST https://[service name].search.windows.net/indexers?api-version=2026-04-01
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"
}
},
}
blob 索引器提供 submode 參數以決定搜尋文件的輸出結構。 Markdown 解析模式提供以下子模式選項:
| 解析模式 | 子模式 | 搜尋文件 | 描述 |
|---|---|---|---|
markdown |
oneToMany |
每個 Blob 多個 | (預設)將 Markdown 拆解成多個搜尋文件,每個文件代表 Markdown 檔案中一個內容(非標頭)區塊。 除非你想要一對一解析,否則可以省略子模式。 |
markdown |
oneToOne |
每個 Blob 一個 | 將 Markdown 解析成一個搜尋文件,並將部分對應到 Markdown 檔案中的特定標頭。 |
關於 oneToMany 子模式,你可以檢視 「索引一個 blob 以產生多個搜尋文件 」,以了解 blob 索引器如何處理同一 blob 產生的多個搜尋文件鍵的消歧義。
後面章節會更詳細描述每個子模式。 如果你不熟悉索引器客戶端和概念,請參考 「建立搜尋索引器」。 你也應該熟悉 基本 blob 索引器配置的細節,這裡沒有重複說明。
可選的 Markdown 解析參數
參數依大小寫區分。
| 參數名稱 | 允許的值 | 描述 |
|---|---|---|
markdownHeaderDepth |
h1, h2, h3, h4, h5, h6 (default) |
此參數決定解析時考慮的最深標頭層級,允許靈活處理文件結構(例如,當 markdownHeaderDepth 設為 h1時,解析器僅識別以「#」開頭的頂層標頭,所有較低階標頭視為純文字)。 若未指定,則預設為 h6。 |
這個設定可以在建立索引器後更改。 然而,最終搜尋文件的結構可能會根據 Markdown 內容而改變。
支援的 Markdown 元素
Markdown 解析只會根據標頭來分割內容。 其他元素,如清單、程式碼區塊和表格,則被視為純文字並傳遞到內容欄位。
Markdown 範例內容
以下 Markdown 內容用於本頁範例:
# Section 1
Content for section 1.
## Subsection 1.1
Content for subsection 1.1.
# Section 2
Content for section 2.
使用一對多解析模式
一對多剖析模式會將 Markdown 檔案剖析為多個搜尋文件,其中每個文件都會根據文件中該位置的標頭中繼資料,對應到 Markdown 檔案的特定內容區段。 Markdown 會根據標題來被剖析成搜尋文件,其中包含以下內容:
content:包含在特定位置找到的原始 Markdown 的字串,依據文件中該位置的標頭中繼資料而定。sections:包含標頭中繼資料子欄位的物件,最多可到所需標頭層級。 例如,當markdownHeaderDepth設為h3時,包含字串欄位h1、h2、 和h3。 這些欄位透過在索引中鏡像此結構,或透過格式/sections/h1、/sections/h2、 等格式的欄位映射來索引。 請參閱以下範例中的索引器與索引器配置,作為上下文範例。 所包含的子欄位包括:-
h1- 包含 h1 標頭值的字串。 如果此時文件中沒有設定,則為空字串。 - (可選)
h2- 包含 h2 標頭值的字串。 如果此時文件中沒有設定,則為空字串。 - (可選)
h3- 包含 h3 標頭值的字串。 如果此時文件中沒有設定,則為空字串。 - (可選)
h4- 包含 h4 標頭值的字串。 如果此時文件中沒有設定,則為空字串。 - (可選)
h5- 包含 h5 標頭值的字串。 如果此時文件中沒有設定,則為空字串。 - (可選)
h6- 包含 h6 標頭值的字串。 如果此時文件中沒有設定,則為空字串。
-
ordinal_position:一個整數值,表示該區段在文件階層中的位置。 此欄位用於依文件中原始順序排列各區段,從序數位置 1 開始,並依序遞增每個標頭。
一對多解析的索引結構
範例索引配置可能如下:
{
"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"
}]
}]
}
一對多解析的索引器定義
若欄位名稱與資料型態對齊,blob 索引器即使請求中未提供明確的欄位映射仍可推斷出映射,則對應於所提供索引配置的索引器配置可能如下所示:
POST https://[service name].search.windows.net/indexers?api-version=2026-04-01
Content-Type: application/json
api-key: [admin key]
{
"name": "my-markdown-indexer",
"dataSourceName": "my-blob-datasource",
"targetIndexName": "my-target-index",
"parameters": {
"configuration": { "parsingMode": "markdown" }
},
}
註
這裡不需要特別設定 submode,因為 oneToMany 是預設值。
一對多剖析的索引子輸出
由於有三個內容區段,這個 Markdown 檔案在索引後會產生三個搜尋文件。 由提供的 Markdown 文件的第一個內容區塊所生成的搜尋文件會包含以下值:content、sections、h1 以及 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
}
}
對應搜尋索引中的一對多欄位
欄位映射會在欄位名稱與類型不完全相同的情況下,將來源欄位與目的欄位關聯起來。 但欄位映射也可以用來匹配 Markdown 文件的部分,並將其「提升」到搜尋文件的頂層欄位。
以下範例說明此情境。 關於場映射的一般資訊,請參見場映射。
假設一個搜尋索引,包含以下欄位: raw_content 型別 Edm.String、 h1_header 型別 Edm.String、 h2_header 型別 Edm.String。 要將你的 Markdown 映射成所需的形狀,請使用以下欄位映射:
"fieldMappings" : [
{ "sourceFieldName" : "/content", "targetFieldName" : "raw_content" },
{ "sourceFieldName" : "/sections/h1", "targetFieldName" : "h1_header" },
{ "sourceFieldName" : "/sections/h2", "targetFieldName" : "h2_header" },
]
索引中產生的搜尋文件會如下所示:
{
{
"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": "",
}
}
使用一對一解析模式
在一對一解析模式下,整個 Markdown 文件會被索引為單一搜尋文件,保留原始內容的階層結構。 此模式最有用的是待索引檔案共享共同結構,因此你可以在索引中使用此共同結構,使相關欄位可搜尋。
在索引器定義中,設定 parsingMode to "markdown" ,並使用可選 markdownHeaderDepth 參數定義分區的最大標題深度。 若未指定,則預設為 h6,捕捉所有可能的標頭深度。
Markdown 會根據標題來被剖析成搜尋文件,其中包含以下內容:
document_content: 包含完整的 Markdown 文字為單一字串。 此欄位作為輸入文件的原始表示。sections:一個包含 Markdown 文件中各區段階層表示的物件陣列。 每個區段在此陣列中以物件形式表示,並以巢狀方式捕捉文件結構,對應標頭及其相應內容。 這些場可透過場映射來存取,方法是參考路徑,例如/sections/content。 此陣列中的物件具有以下特性:header_level: 一個字串,表示標頭(h1、h2h3等)在 Markdown 語法中的位置。 此領域有助於理解內容的層級結構與結構。header_name:包含 Markdown 文件中顯示的標頭文字的文字串。 此欄位提供該區段的標籤或標題。content: 字串包含緊接標頭後至下一個標頭的文字內容。 此欄位捕捉與標頭相關的詳細資訊或描述。 如果標頭下方沒有直接內容,該值就是空字串。ordinal_position:一個整數值,表示該區段在文件階層中的位置。 此欄位用於將章節按照它們在文件中出現的原始順序排列,從序號 1 開始,並為每個內容區塊依序遞增。sections:一個陣列,包含代表巢狀子區段的物件,這些物件位於當前區段下方。 此陣列遵循與頂層sections陣列相同的結構,允許表示多層巢狀內容。 每個子區段物件也包含header_level、header_name、content和ordinal_position屬性,使得一個遞迴結構能夠代表 Markdown 內容的階層結構。
以下是我們用來解釋針對每種解析模式設計的索引結構的範例 Markdown。
# Section 1
Content for section 1.
## Subsection 1.1
Content for subsection 1.1.
# Section 2
Content for section 2.
一對一解析的索引結構
如果你不使用欄位映射,索引的形狀應該會反映 Markdown 內容的形狀。 鑑於範例 Markdown 的結構,包含兩個部分和一個子部分,索引應該看起來與以下範例相似:
{
"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"
}]
}]
}]
}
一對一解析的索引器定義
POST https://[service name].search.windows.net/indexers?api-version=2026-04-01
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",
}
}
}
一對一解析的索引器輸出
因為我們想索引的 Markdown 只延伸到深度為 h2 (“##”),因此需要 sections 巢狀的欄位深度為 2 來匹配。 此配置會產生以下索引資料:
"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": []
}]
}
如你所見,序數位置會根據內容在文件中的位置遞增。
若內容中跳過標頭層級,最終文件的結構會顯示 Markdown 內容中的標頭,且不一定會包含連續的從 h1 到 h6 嵌套段落。 例如,當文件從 h2開始時,頂層區塊陣列中的第一個元素是 h2。
對應搜尋索引中的一對一欄位
要從文件中提取帶有自訂名稱的欄位,可以使用欄位映射。 使用相同的 Markdown 範例,考慮以下索引配置:
{
"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",
}
]
}
從解析後的 Markdown 中擷取特定欄位的處理方式類似於 outputFieldMappings 中的文件路徑,只是路徑以 開頭 /sections 而非 /document。 例如, /sections/0/content 會映射到區段陣列中位置 0 的項目下方的內容。
一個強效的使用案例範例如下:所有 Markdown 檔案在第一個 h1 包含文件標題,在第一個 h2 包含子節標題,最後一段內容為摘要,位於最終 h1 的段落下方。 你可以使用以下欄位映射來只索引該內容:
"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" },
]
在這裡,你只會從該文件中擷取相關的部分。 為了最有效地使用此功能,你計劃索引的文件應該共享相同的階層式標頭結構。
索引中產生的搜尋文件會如下所示:
{
"content": "Content for section 1.\r\n",
"document_title": "Section 1",
"opening_subsection_title": "Subsection 1.1",
"summary_content": "Content for section 2."
}
註
這些範例說明了如何完全使用這些解析模式,無論是否使用欄位映射,但如果你需要,也可以在同一情境中同時套用兩種模式。
管理來自 Markdown 重新索引的陳舊文件
在使用一對多解析模式時,若刪除部分區段,重新索引修改過的 Markdown 檔案可能會導致文件過時或重複。 此行為僅限於一對多模式,並不適用於一對一解析。
行為概述
一對多解析模式
在 oneToMany 模式下,每個 Markdown 區段(基於標頭)會被索引為獨立的搜尋文件。 當檔案重新索引時:
- 無自動刪除:索引器會用新文件覆蓋現有文件,但不會刪除與更新檔案中內容不再對應的文件。
- 重複風險:此問題僅在索引執行間刪除的區段多於插入的區段時出現。 在這種情況下,前一個版本剩餘的文件會留在索引中,導致條目過時,不再反映原始檔案的當前狀態。
一對一解析模式
在 oneToOne 模式下,整個 Markdown 檔案會被索引為單一的搜尋文件。 當檔案重新索引時:
- 覆寫行為:現有文件會被新版本完全取代。
- 無陳舊段落:當檔案重新索引時,現有文件會被更新版本取代,移除的內容則不再包含。 唯一的例外是檔案路徑或 blob 的 URI 改變,這可能導致新文件與舊文件同時建立。
解決方法
為了確保索引反映你 Markdown 檔案的當前狀態,請考慮以下方法之一:
選項一。 含元資料的軟刪除
此方法使用軟刪除來刪除與特定 blob 相關的文件。 欲了解更多資訊,請參閱Azure AI 搜尋服務 中使用索引器進行 Azure 儲存體的變更與刪除偵測。
步驟:
- 透過設定元資料欄位,將 blob 標記為已刪除。
- 讓索引器運行。 它會刪除與該 blob 相關的索引中的所有文件。
- 移除軟刪除標記並重新索引檔案。
選項二。 使用刪除 API
在重新索引修改過的 Markdown 檔案前,請明確使用 delete API 刪除與該檔案相關的現有文件。 你可以選擇:
- 手動辨識過時文件,透過識別索引中重複的檔案來刪除。 這對於小且熟悉的變更可能可行,但可能耗時。
- (推薦)在重新索引前,請移除所有從同一父檔案產生的文件,以避免不一致。
步驟:
識別與檔案相關的文件編號。 使用類似以下範例的查詢,取得所有綁定於特定檔案的文件的金鑰 ID(例如
idchunk_id或 )。 將metadata_storage_path取代為索引中對應到檔案路徑或 Blob URI 的相應欄位。 這個欄位必須是鍵。GET https://[service name].search.windows.net/indexes/[index name]/docs?api-version=2026-04-01 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" }對已識別金鑰的文件發出刪除請求。
POST https://[service name].search.windows.net/indexes/[index name]/docs/index?api-version=2026-04-01 Content-Type: application/json api-key: [admin key] { "value": [ { "@search.action": "delete", "id": "aHR0c...jI1" }, { "@search.action": "delete", "id": "aHR0...MQ2" } ] }重新索引更新後的檔案。