教學課程:使用 REST 和 AI 從 Azure Blob 產生可搜尋的內容

如果您在 Azure Blob 儲存體中有非結構化文字或影像, AI 擴充管線 可以擷取資訊,並為全文檢索搜尋或知識採礦案例建立新內容。

在本 REST 教學課程中,您將瞭解如何:

  • 設定開發環境。
  • 定義使用 OCR、語言偵測、實體辨識和關鍵字組擷取的管線。
  • 執行管線以叫用轉換,以及建立和載入搜尋索引。
  • 使用全文檢索搜尋和豐富的查詢語法來探索結果。

如果您沒有 Azure 訂用帳戶,請在開始前開啟免費帳戶

總覽

本教學課程使用 Postman 和 Azure 認知搜尋 REST API 來建立資料來源、索引子及技能集。

索引子會連線到 Azure Blob 儲存體,並擷取您必須事先載入的內容。 接著,索引子會叫用技能 進行特製化處理,並將擴充的內容內嵌到 搜尋索引中。

技能集會附加至 索引子。 它會使用 Microsoft 的內建技能來尋找和擷取資訊。 管線中的步驟包括影像上的光學字元辨識 (OCR) 、語言偵測、關鍵字組擷取,以及實體辨識 (組織、位置、人員) 。 管線所建立的新資訊會儲存在索引的新欄位中。 填入索引之後,您可以在查詢、Facet 和篩選中使用這些欄位。

必要條件

注意

您可以使用免費服務來進行本教學課程。 免費的搜尋服務會有限制,您只能使用三個索引、三個索引子和三個資料來源。 本教學課程會各建立一個。 開始之前,請確定您的服務有空間可接受新的資源。

下載檔案

範例資料包含 14 個混合內容類型的檔案,您將在稍後的步驟中上傳至 Azure Blob 儲存體。

  1. azure-search-sample-data/ai-enrichment-mixed-media/ 取得檔案,並將其複製到本機電腦。

  2. 接下來,取得本教學課程的原始程式碼 Postman 集合檔案。 原始程式碼位於 azure-search-postman-samples/tree/master/Tutorial

1 - 建立服務

本教學課程使用 Azure 認知搜尋來編制索引和查詢、AI 擴充的後端認知服務,以及 Azure Blob 儲存體來提供資料。 本教學課程在認知服務上使用的資源會保持在每個索引子每日 20 筆交易的免費配置以內,因此您需要建立的服務只有搜尋和儲存體。

為具備鄰近性和管理方面的優勢,如果可能,請將這兩項服務建立在相同的區域和資源群組中。 實際上,您的 Azure 儲存體帳戶可以位在任何區域中。

開始使用 Azure 儲存體

  1. 登入 Azure 入口網站,然後按一下 [+ 建立資源]。

  2. 搜尋「儲存體帳戶」,然後選取 Microsoft 的儲存體帳戶供應項目。

    Create Storage account

  3. 在 [基本] 索引標籤中,需要下列項目。 接受所有其他項目的預設值。

    • 資源群組。 選取現有群組或建立一個新的群組,但必須對所有服務使用相同的群組,以便您一起管理這些服務。

    • 儲存體帳戶名稱。 如果您認為您可能會有多個相同類型的資源,請透過名稱在類型和區域上做出區別,例如 blobstoragewestus。

    • 位置。 可能的話,請選擇用於 Azure 認知搜尋和認知服務的相同位置。 單一位置可避免產生頻寬費用。

    • 帳戶種類。 選擇預設值 [StorageV2 (一般用途 v2)]。

  4. 選取 [檢閱 + 建立] 以建立服務。

  5. 建立之後,請選取 [移至資源] 以開啟 [概觀] 頁面。

  6. 選取 [Blob 服務]。

  7. 選取 [+ 容器 ] 以建立容器,並將其命名為 cog-search-demo

  8. 選取 cog-search-demo ,然後選取 [ 上傳 ] 以開啟您儲存下載檔案的資料夾。 選取所有檔案。 選取 [上傳] 。

    Screenshot of the files in File Explorer.

  9. 在您離開 Azure 儲存體之前,請取得連接字串,以便在 Azure 認知搜尋中制定連線。

    1. 往回瀏覽到儲存體帳戶的 [概觀] 頁面 (我們使用 blobstragewestus 作為範例)。

    2. 在左側導覽窗格中,選取 [存取金鑰] 並複製其中一個連接字串。

    連接字串應為類似於下列範例的 URL:

    DefaultEndpointsProtocol=https;AccountName=cogsrchdemostorage;AccountKey=<your account key>;EndpointSuffix=core.windows.net
    
  10. 將連接字串儲存到記事本。 您稍後設定資料來源連線時會用到該字串。

認知服務

AI 擴充是由認知服務所支援,包括語言服務和電腦視覺,以進行自然語言和影像處理。 如果您的目標是要完成實際的原型或專案,此時您會在與 Azure 認知搜尋) 相同的區域中布建認知服務 (,以便您將 它附加至技能集

不過,在此練習中,您可以略過資源布建,因為 Azure 認知搜尋可以連線到認知服務,每個索引子執行 20 筆交易,免費。 由於本教學課程會使用 14 筆交易,因此使用免費配置就已足夠。 針對較大型的專案,請考慮以隨用隨付 S0 層來佈建認知服務。

第三個元件是 Azure 認知搜尋,您可以在入口網站中建立或在訂用帳戶中尋找現有的搜尋服務

您可以使用免費層來完成此逐步解說。

若要與 Azure 認知搜尋服務互動,您需要服務 URL 和存取金鑰。

  1. 登入 Azure 入口網站,並在搜尋服務的 [概觀] 頁面中取得您的搜尋服務名稱。 您可藉由檢閱端點 URL 來確認您的服務名稱。 如果您的端點 URL 為 https://mydemo.search.windows.net,您的服務名稱會是 mydemo

  2. 在 [設定]> [金鑰] 中,取得服務上完整權限的管理金鑰。 您可以複製主要或次要金鑰。

    Get the service name and admin key

搜尋服務的所有 HTTP 要求都需要 API 金鑰。 有效的金鑰能為每個要求在傳送要求之應用程式與處理要求的服務間建立信任。

2 - 設定 Postman

  1. 啟動 Postman、匯入集合,並設定環境變數。 如果您不熟悉此工具,請參閱探索 Azure 認知搜尋 REST API

  2. 您必須提供搜尋服務名稱、管理員 API 金鑰、索引名稱、Azure 儲存體帳戶的連接字串,以及容器名稱。

    Screenshot of the Variables page in Postman.

此集合中使用的要求方法是 PUTGET。 您將使用 方法來建立資料來源、技能集、索引和索引子。

3 - 建立管線

在 Azure 認知搜尋中,擴充會在編製索引 (或資料擷取) 期間進行。 逐步解說的這個部分會建立四個物件:資料來源、索引定義、技能集、索引子。

步驟 1:建立資料來源

呼叫 建立資料來源 ,將連接字串設定為包含範例資料檔案的 Blob 容器。

  1. 選取 [建立資料來源] 要求。

  2. 要求的主體是 JSON,並包含索引子資料來源物件的屬性。 連接字串包含存取服務的認證。

    {   
        "description" : "Demo files to demonstrate cognitive search capabilities.",  
        "type" : "azureblob",
        "credentials" : { 
           "connectionString": "{{azure-storage-connection-string}}"
        },  
      "container" : { 
        "name" : "{{blob-container}}"
      }
    }
    
  3. 傳送要求。 您應該會看到確認成功的狀態碼 201。

如果您收到 403 或 404 錯誤,請檢查搜尋管理員 API 金鑰和 Azure 儲存體連接字串。

步驟 2:建立技能集

呼叫 建立技能集 ,以指定哪些擴充步驟會套用至您的內容。

  1. 選取 [建立技能集] 要求。

  2. 要求的本文會指定下列內建技能:

    技能 說明
    光學字元辨識 辨識影像檔中的文字和數位。
    文字合併 建立「合併的內容」,以重新組合先前分隔的內容,適用于內嵌影像的檔 (PDF、DOCX 等等) 。 影像和文字會在檔破解階段分開。 合併技能會藉由將擴充期間建立的任何辨識文字、影像標題或標記插入檔中擷取影像的相同位置,以重新組合它們。

    在技能集中使用合併的內容時,此節點將包含檔中所有文字,包括從未經歷 OCR 或影像分析的僅限文字檔。
    語言偵測 偵測語言,並輸出語言名稱或程式碼。 在多語系資料集中,語言欄位對於篩選很有用。
    實體辨識 從合併的內容中擷取人員、組織和位置的名稱。
    文字分割 呼叫關鍵字組擷取技能之前,先將大型合併的內容分成較小的區塊。 關鍵片語擷取可接受不超過 50,000 個字元的輸入。 有些範例檔案需要進行分割,以符合這項限制。
    關鍵片語擷取 提取前幾個關鍵片語。

    每項技術會分別對文件的內容執行。 在處理期間,Azure 認知搜尋會萃取每份文件,以讀取不同檔案格式的內容。 找到來自來源檔案的文字時,會將文字放入產生的 content 欄位中,每份文件一個欄位。 因此,輸入會變成 "/document/content"

    針對關鍵片語的擷取,因為我們使用文字分隔器技能將較大的檔案分成多個頁面,所以關鍵片語擷取技能的內容會是 "document/pages/*",而不是 "/document/content"

    {
      "description": "Apply OCR, detect language, extract entities, and extract key-phrases.",
      "cognitiveServices": null,
      "skills":
      [
        {
          "@odata.type": "#Microsoft.Skills.Vision.OcrSkill",
          "context": "/document/normalized_images/*",
          "defaultLanguageCode": "en",
          "detectOrientation": true,
          "inputs": [
            {
              "name": "image",
              "source": "/document/normalized_images/*"
            }
          ],
          "outputs": [
            {
              "name": "text"
            }
          ]
        },
        {
          "@odata.type": "#Microsoft.Skills.Text.MergeSkill",
          "description": "Create merged_text, which includes all the textual representation of each image inserted at the right location in the content field. This is useful for PDF and other file formats that supported embedded images.",
          "context": "/document",
          "insertPreTag": " ",
          "insertPostTag": " ",
          "inputs": [
            {
              "name":"text", 
              "source": "/document/content"
            },
            {
              "name": "itemsToInsert", 
              "source": "/document/normalized_images/*/text"
            },
            {
              "name":"offsets", 
              "source": "/document/normalized_images/*/contentOffset" 
            }
          ],
          "outputs": [
            {
              "name": "mergedText", 
              "targetName" : "merged_text"
            }
          ]
        },
        {
          "@odata.type": "#Microsoft.Skills.Text.SplitSkill",
          "textSplitMode": "pages",
          "maximumPageLength": 4000,
          "defaultLanguageCode": "en",
          "context": "/document",
          "inputs": [
            {
              "name": "text",
              "source": "/document/merged_text"
            }
          ],
          "outputs": [
            {
              "name": "textItems",
              "targetName": "pages"
            }
          ]
        },
        {
          "@odata.type": "#Microsoft.Skills.Text.LanguageDetectionSkill",
          "description": "If you have multilingual content, adding a language code is useful for filtering",
          "context": "/document",
          "inputs": [
            {
              "name": "text",
              "source": "/document/merged_text"
            }
          ],
          "outputs": [
            {
              "name": "languageName",
              "targetName": "language"
            }
          ]
        },
        {
          "@odata.type": "#Microsoft.Skills.Text.KeyPhraseExtractionSkill",
          "context": "/document/pages/*",
          "inputs": [
            {
              "name": "text",
              "source": "/document/pages/*"
            }
          ],
          "outputs": [
            {
              "name": "keyPhrases",
              "targetName": "keyPhrases"
            }
          ]
        },
        {
          "@odata.type": "#Microsoft.Skills.Text.V3.EntityRecognitionSkill",
          "categories": ["Organization"],
          "context": "/document",
          "inputs": [
            {
              "name": "text",
              "source": "/document/merged_text"
            }
          ],
          "outputs": [
            {
              "name": "organizations",
              "targetName": "organizations"
            }
          ]
        },
        {
          "@odata.type": "#Microsoft.Skills.Text.V3.EntityRecognitionSkill",
          "categories": ["Location"],
          "context": "/document",
          "inputs": [
            {
              "name": "text",
              "source": "/document/merged_text"
            }
          ],
          "outputs": [
            {
              "name": "locations",
              "targetName": "locations"
            }
          ]
        },
        {
          "@odata.type": "#Microsoft.Skills.Text.V3.EntityRecognitionSkill",
          "categories": ["Person"],
          "context": "/document",
          "inputs": [
            {
              "name": "text",
              "source": "/document/merged_text"
            }
          ],
          "outputs": [
            {
              "name": "persons",
              "targetName": "persons"
            }
          ]
        }
      ]
    }
    

    技能集部分的圖形表示如下所示。

    Understand a skillset

  3. 傳送要求。 Postman 應該會傳回確認成功的狀態碼 201。

注意

輸出可以對應至索引、作為下游技能的輸入,或在使用語言代碼時同時作為對應和輸入。 在索引中,語言代碼可用於篩選。 如需技能集基本概念的詳細資訊,請參閱如何定義技能集

步驟 3:建立索引

呼叫 建立索引 ,以提供用來在 Azure 認知搜尋中建立反向索引和其他建構的架構。 索引的最大元件是欄位集合,其中資料類型和屬性會決定 Azure 認知搜尋中的內容和行為。

  1. 選取 [建立索引] 要求。

  2. 要求的主體會定義搜尋索引的架構。 欄位集合需要將一個欄位指定為索引鍵。 對於 Blob 內容,此欄位通常是可唯一識別容器中每個 Blob 的「metadata_storage_path」。

    在此架構中,「text」 欄位會接收 OCR 輸出,「content」 會接收合併的輸出,「language」 會接收語言偵測輸出。 從 Blob 儲存體增益的關鍵字組、實體和數個欄位組成其餘專案。

    {
      "fields": [
        {
          "name": "text",
          "type": "Collection(Edm.String)",
          "searchable": true,
          "sortable": false,
          "filterable": true,
          "facetable": false
        },
        {
          "name": "content",
          "type": "Edm.String",
          "searchable": true,
          "sortable": false,
          "filterable": false,
          "facetable": false
        },
        {
          "name": "language",
          "type": "Edm.String",
          "searchable": false,
          "sortable": true,
          "filterable": true,
          "facetable": false
        },
        {
          "name": "keyPhrases",
          "type": "Collection(Edm.String)",
          "searchable": true,
          "sortable": false,
          "filterable": true,
          "facetable": true
        },
        {
          "name": "organizations",
          "type": "Collection(Edm.String)",
          "searchable": true,
          "sortable": false,
          "filterable": true,
          "facetable": true
        },
        {
          "name": "persons",
          "type": "Collection(Edm.String)",
          "searchable": true,
          "sortable": false,
          "filterable": true,
          "facetable": true
        },
        {
          "name": "locations",
          "type": "Collection(Edm.String)",
          "searchable": true,
          "sortable": false,
          "filterable": true,
          "facetable": true
        },
        {
          "name": "metadata_storage_path",
          "type": "Edm.String",
          "key": true,
          "searchable": true,
          "sortable": false,
          "filterable": false,
          "facetable": false
        },
        {
          "name": "metadata_storage_name",
          "type": "Edm.String",
          "searchable": true,
          "sortable": false,
          "filterable": false,
          "facetable": false
        }
      ]
    }
    
  3. 傳送要求。 Postman 應該會傳回確認成功的狀態碼 201。

步驟 4:建立及執行索引子

呼叫 建立索引子 以驅動管線。 到目前為止所建立的三個元件 (資料來源、技能集、索引) 都是索引子的輸入。 在 Azure 認知搜尋上建立索引子,是用以啟動整個管線的事件。

  1. 選取 [建立索引子] 要求。

  2. 要求的本文包含先前物件的參考、影像處理所需的組態屬性,以及兩種類型的欄位對應。

    "fieldMappings" 會在技能集之前處理,將資料來源的內容傳送至索引中的目標欄位。 您會使用欄位對應將已修改的現有內容傳送至索引。 如果兩端上的欄位名稱和類型都相同,則不需要任何對應。

    "outputFieldMappings" 適用于技能所建立的欄位,在技能集執行之後。 針對 outputFieldMappingssourceFieldName 的參考項目,當您從文件萃取或擴充中建立這些項目之後,這些項目才會存在。 targetFieldName 是索引中的欄位,定義於索引結構描述中。

    {
      "dataSourceName" : "{{index_name}}-datasource",
      "targetIndexName" : "{{index_name}}",
      "skillsetName" : "{{index_name}}-skillset",
      "fieldMappings" : [
            {
              "sourceFieldName" : "metadata_storage_path",
              "targetFieldName" : "metadata_storage_path",
              "mappingFunction" : { "name" : "base64Encode" }
            },
            {
            	"sourceFieldName": "metadata_storage_name",
            	"targetFieldName": "metadata_storage_name"
            }
       ],
      "outputFieldMappings" : 
    	[
    		{
            	"sourceFieldName": "/document/merged_text",
            	"targetFieldName": "content"
            },
            {
                "sourceFieldName" : "/document/normalized_images/*/text",
                "targetFieldName" : "text"
            },
      		{
              "sourceFieldName" : "/document/organizations", 
              "targetFieldName" : "organizations"
            },
            {
            	"sourceFieldName": "/document/language",
            	"targetFieldName": "language"
            },
      		{
              "sourceFieldName" : "/document/persons", 
              "targetFieldName" : "persons"
            },
      		{
              "sourceFieldName" : "/document/locations", 
              "targetFieldName" : "locations"
            },
            {
              "sourceFieldName" : "/document/pages/*/keyPhrases/*", 
              "targetFieldName" : "keyPhrases"
            }
        ],
      "parameters":
      {
    	"batchSize": 1,
      	"maxFailedItems":-1,
      	"maxFailedItemsPerBatch":-1,
      	"configuration": 
    	{
        	"dataToExtract": "contentAndMetadata",
        	"imageAction": "generateNormalizedImages"
    	}
      }
    }
    
  3. 傳送要求。 Postman 應會傳回確認處理成功的狀態碼 201。

    預期此步驟需要幾分鐘的時間才能完成。 即使資料集很小,分析技能仍需要大量計算。

注意

建立索引子時會叫用管線。 資料的存取、輸入和輸出的對應或作業順序若有問題,都會在這個階段中出現。 若要透過程式碼或指令碼的變更重新執行管線,您可能需要先卸除物件。 如需詳細資訊,請參閱重設並重新執行

關於索引子參數

腳本會將 設定 "maxFailedItems" 為 -1,指示索引引擎在資料匯入期間忽略錯誤。 這是可接受的設定,因為示範資料來源中只有少量文件。 若要有較大的資料來源,您應將值設定為大於 0。

"dataToExtract":"contentAndMetadata" 陳述式會指示索引子自動擷取不同檔案格式的內容,以及每個檔案的相關中繼資料。

在擷取內容時,您可以設定 imageAction,以從在資料來源中找到的影像擷取文字。 "imageAction":"generateNormalizedImages" 組態可與 OCR 技術和文字合併技術結合,指示索引子從影像中擷取文字 (例如,從「停」交通號誌中擷取「停」這個字),並將其內嵌為內容欄位的一部分。 此行為適用於內嵌在文件中的影像 (例如 PDF 內的影像),以及在資料來源中找到的影像 (例如 JPG 檔案)。

4 - 監視編製索引

當您提交建立索引子的要求時,編制索引和擴充就會開始進行。 根據您所定義的認知技能,索引編製可能會需要一段時間。

若要找出索引子是否仍在執行中,請呼叫 [取得索引子狀態 ] 來檢查索引子狀態。

  1. 選取 ,然後傳送「檢查索引子狀態」要求。

  2. 請檢查回應以了解索引子是否正在執行,或查看錯誤和警告資訊。

警告在某些案例中很常見,但不一定表示有問題。 例如,如果 Blob 容器包含影像檔案,而管線並未處理影像,您就會收到指出影像未處理的警告。

在此範例中,有一個不含文字的 PNG 檔案。 這五個文字型技能都 (語言偵測、位置、組織、人員及關鍵字組擷取的實體辨識) 無法在此檔案上執行。 產生的通知會顯示在執行歷程記錄中。

既然您已建立包含 AI 產生內容的索引,請呼叫 搜尋檔 來執行一些查詢以查看結果。

回想一下,我們從 Blob 內容開始,並將整份文件封裝成單一 content 欄位。 您可以搜尋此欄位,並尋找與您查詢相符的項目。

  1. 開啟 「搜尋」要求並加以執行,以取得您第一次查看索引內容。 此要求是空的搜尋 (「search=*」) ,因此它會傳回每個 14 份檔的內容。 $select參數會將結果限制為檔案名、語言名稱和其中一個辨識的實體。

     GET /indexes//{{index_name}}/docs?search=*&$select=metadata_storage_name,language,organizations&$count=true&api-version=2020-06-30
    
  2. 修改先前的查詢,以搜尋「建立無界限的機會」。 此片語是透過 PDF 檔中內嵌影像檔的 OCR 取得。 包含「醒目提示」,以在密集填入的欄位中套用比對字詞的格式設定。

     GET /indexes//{{index_name}}/docs?search=creating boundaryless opportunities&$select=content&highlight=content&$count=true&api-version=2020-06-30
    
  3. 在下一個查詢中,套用篩選。 回想一下,語言欄位和所有實體欄位都是可篩選的。

     GET /indexes/{{index_name}}/docs?search=*&$filter=organizations/any(organizations: organizations eq 'NASDAQ')&$select=metadata_storage_name,organizations&$count=true&api-version=2020-06-30
    

這些查詢說明在認知搜尋所建立的新欄位上,您可使用的一些查詢語法和篩選方式。 如需更多查詢範例,請參閱搜尋文件 REST API 中的範例簡單的語法查詢範例完整的 Lucene 查詢範例

重設並重新執行

在開發初期階段,反復執行設計很常見。 您很可能會經常刪除和重建相同的物件。

如果您使用入口網站進行刪除,並先刪除索引子,入口網站會提示您刪除相關聯的物件。

Delete search objects

或者,您可以使用 DELETE 並提供每個物件的 URL。 下列命令會刪除索引子。

DELETE https://[YOUR-SERVICE-NAME].search.windows.net/indexers/cog-search-demo-idxr?api-version=2020-06-30

成功刪除時會傳回狀態碼 204。

重要心得

本教學課程示範了藉由建立下列元件組件來建置擴充索引管線的基本步驟:資料來源、技能集、索引和索引子。

內建技能已透過輸入和輸出連同技能集定義和鏈結技能的機制一起導入。 您也已了解在將管線中的擴充值路由至 Azure 認知搜尋服務上的可搜尋索引時,索引子定義中必須要有 outputFieldMappings

最後,您了解到如何測試結果並重設系統,以進行進一步的反覆運算。 您已了解對索引發出查詢,會傳回由擴充的索引管線建立的輸出。

清除資源

如果您使用自己的訂用帳戶,當專案結束時,建議您移除不再需要的資源。 讓資源繼續執行可能會產生費用。 您可以個別刪除資源,或刪除資源群組以刪除整組資源。

您可以使用左導覽窗格中的 [所有資源] 或 [資源群組] 連結,在入口網站中尋找和管理資源。

後續步驟

現在您已熟悉 AI 擴充管線中的所有物件,接下來我們將進一步了解技能集定義和個別技能。