Compartir a través de

教程:使用 REST 为 Azure 存储中的嵌套 JSON Blob 编制索引

Azure AI 搜索可使用一个知晓如何读取半结构化数据的索引器来编制 Azure blob 存储中 JSON 文档和数组的索引。 半结构化数据包含用于分隔数据中的内容的标记或标签。 它的本质是提供必须全面索引的非结构化数据和符合数据模型的正式结构化数据之间的一个折中,例如可以按字段编制索引的关系数据库架构。

本教程介绍如何为嵌套 JSON 数组编制索引。 它使用 REST 客户端和搜索 REST API 执行以下任务:

  • 设置示例数据并配置 azureblob 数据源
  • 创建 Azure AI 搜索索引以包含可搜索的内容
  • 创建和运行索引器以读取容器和提取可搜索内容
  • 搜索刚刚创建的索引

如果没有 Azure 订阅,请在开始前创建一个试用版订阅

先决条件

注意

可在本教程中使用免费服务。 免费搜索服务限制为三个索引、三个索引器和三个数据源。 本教程每样创建一个。 在开始之前,请确保服务中有足够的空间可接受新资源。

下载文件

下载示例数据存储库的 zip 文件并提取内容。 了解操作方法

示例数据是包含一个 JSON 数组和 1,521 个嵌套 JSON 元素的单个 JSON 文件。 示例数据源自 Kaggle 上的纽约爱乐乐团演出历史记录。 我们选择了一个 JSON 文件,以保持在免费层的存储限制之下。

下面是文件中的第一个嵌套 JSON。 文件的其余部分包括 1,520 个其他音乐会表演实例。

    {
      "id": "7358870b-65c8-43d5-ab56-514bde52db88-0.1",
      "programID": "11640",
      "orchestra": "Beijing Philharmonic",
      "season": "2011-12",
      "concerts": [
        {
          "eventType": "Non-Subscription",
          "Location": "Manhattan, NY",
          "Venue": "Avery Fisher Hall",
          "Date": "2011-09-07T04:00:00Z",
          "Time": "7:30PM"
        },
        {
          "eventType": "Non-Subscription",
          "Location": "Manhattan, NY",
          "Venue": "Avery Fisher Hall",
          "Date": "2011-09-08T04:00:00Z",
          "Time": "7:30PM"
        }
      ],
      "works": [
        {
          "ID": "5733*",
          "composerName": "Bernstein,  Leonard",
          "workTitle": "WEST SIDE STORY (WITH FILM)",
          "conductorName": "Newman, David",
          "soloists": []
        },
        {
          "ID": "0*",
          "interval": "Intermission",
          "soloists": []
        }
      ]
    }

将示例数据上传到 Azure 存储

  1. 在 Azure 存储中,创建新容器并将其命名为 ny-philharmonic-free

  2. 上传示例数据文件

  3. 获取存储连接字符串,以便可以在 Azure AI 搜索中构建连接。

    1. 在左侧选择“访问密钥”

    2. 复制密钥 1 或密钥 2 对应的连接字符串。 连接字符串如以下示例所示:

      DefaultEndpointsProtocol=https;AccountName=<your account name>;AccountKey=<your account key>;EndpointSuffix=core.chinacloudapi.cn
      

复制搜索服务 URL 和 API 密钥

对于本教程,与 Azure AI 搜索的连接需要终结点和 API 密钥。 可以从 Azure 门户获取这些值。

  1. 登录到 Azure 门户,导航到搜索服务“概述”页,然后复制 URL。 示例终结点可能类似于 https://mydemo.search.azure.cn

  2. 在“设置”>“密钥”下,复制管理密钥。 管理密钥用于添加、修改和删除对象。 有两个可互换的管理密钥。 复制其中任意一个。

    Azure 门户中 URL 和 API 密钥的屏幕截图。

设置 REST 文件

  1. 启动 Visual Studio Code,并创建一个新文件

  2. 为请求中使用的变量提供值:

    @baseUrl = PUT-YOUR-SEARCH-SERVICE-ENDPOINT-HERE
    @apiKey = PUT-YOUR-ADMIN-API-KEY-HERE
    @storageConnection = PUT-YOUR-STORAGE-CONNECTION-STRING-HERE
    @blobContainer = PUT-YOUR-CONTAINER-NAME-HERE
    
  3. 使用 .rest.http 文件扩展名保存文件。

如需 REST 客户端的帮助信息,请参阅快速入门:使用 REST 进行文本搜索

创建数据源

创建数据源 (REST) 会创建数据源连接,用于指定要编制索引的数据。

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

    {
        "name" : "ny-philharmonic-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: "0x8DC43A5FDB8448F"
Location: https://free-demo-search-svc.search.azure.cn:443/datasources('ny-philharmonic-ds')?api-version=2024-07-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: 7ca53f73-1054-4959-bc1f-616148a9c74a
elapsed-time: 111
Date: Wed, 13 Mar 2024 21:38:58 GMT
Connection: close

{
  "@odata.context": "https://free-demo-search-svc.search.azure.cn/$metadata#datasources/$entity",
  "@odata.etag": "\"0x8DC43A5FDB8448F\"",
  "name": "ny-philharmonic-ds",
  "description": null,
  "type": "azureblob",
  "subtype": null,
  "credentials": {
    "connectionString": null
  },
  "container": {
    "name": "ny-philharmonic-free",
    "query": null
  },
  "dataChangeDetectionPolicy": null,
  "dataDeletionDetectionPolicy": null,
  "encryptionKey": null
}

创建索引

创建索引 (REST) 会在搜索服务中创建搜索索引。 索引指定所有参数及其属性。

对于嵌套 JSON,索引字段必须与源字段相同。 目前,Azure AI 搜索不支持将字段映射到嵌套 JSON。 因此,字段名称和数据类型必须完全匹配。 以下索引与原始内容中的 JSON 元素保持一致。

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

    {
      "name": "ny-philharmonic-index",  
      "fields": [
        {"name": "programID", "type": "Edm.String", "key": true, "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true},
        {"name": "orchestra", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true},
        {"name": "season", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "facetable": true, "sortable": true},
        { "name": "concerts", "type": "Collection(Edm.ComplexType)", 
          "fields": [
            { "name": "eventType", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": false, "sortable": false, "facetable": false},
            { "name": "Location", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "sortable": false, "facetable": true },
            { "name": "Venue", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "sortable": false, "facetable": true },
            { "name": "Date", "type": "Edm.String", "searchable": false, "retrievable": true, "filterable": true, "sortable": false, "facetable": true },
            { "name": "Time", "type": "Edm.String", "searchable": false, "retrievable": true, "filterable": true, "sortable": false, "facetable": true }
          ]
        },
        { "name": "works", "type": "Collection(Edm.ComplexType)", 
          "fields": [
            { "name": "ID", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": false, "sortable": false, "facetable": false},
            { "name": "composerName", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "sortable": false, "facetable": true },
            { "name": "workTitle", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "sortable": false, "facetable": true },
            { "name": "conductorName", "type": "Edm.String", "searchable": true, "retrievable": true, "filterable": true, "sortable": false, "facetable": true },
            { "name": "soloists", "type": "Collection(Edm.String)", "searchable": true, "retrievable": true, "filterable": true, "sortable": false, "facetable": true }
          ]
        }
      ]
    }

要点

  • 不能使用字段映射来协调字段名称或数据类型的差异。 此索引架构旨在镜像原始内容。

  • 嵌套 JSON 建模为 Collection(Edm.ComplextType)。 在原始内容中,每个季节都有多场音乐会,每场音乐会都有多个作品。 若要适应此结构,请对复杂类型使用集合。

  • 在原始内容中,DateTime 是字符串,因此索引中的相应数据类型也是字符串。

创建并运行索引器

创建索引器会在搜索服务上创建索引器。 索引器会连接到数据源、加载和索引数据,还可以选择提供自动刷新数据的计划。

索引器配置包括 jsonArray 分析模式和 documentRoot

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

    {
      "name" : "ny-philharmonic-indexer",
      "dataSourceName" : "ny-philharmonic-ds",
      "targetIndexName" : "ny-philharmonic-index",
      "parameters" : { 
        "configuration" : { 
          "parsingMode" : "jsonArray", "documentRoot": "/programs"}
        },
      "fieldMappings" : [ 
      ]
    }

要点

  • 原始内容文件包含一个 JSON 数组 ("programs"),其中具有 1,526 个嵌套 JSON 结构。 将 parsingMode 设置为 jsonArray 可告知索引器每个 Blob 都包含一个 JSON 数组。 由于嵌套 JSON 从下一级开始,因此请将 documentRoot 设置为 /programs

  • 索引器运行时间为数分钟。 等待索引器执行完成,然后再运行任何查询。

运行查询

加载第一个文档后,可立即开始搜索。

### Query the index
POST {{baseUrl}}/indexes/ny-philharmonic-index/docs/search?api-version=2024-07-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: a95c4021-f7b4-450b-ba55-596e59ecb6ec
elapsed-time: 106
Date: Wed, 13 Mar 2024 22:09:59 GMT
Connection: close

{
  "@odata.context": "https://free-demo-search-svc.search.azure.cn/indexes('ny-philharmonic-index')/$metadata#docs(*)",
  "@odata.count": 1521,
  "@search.nextPageParameters": {
    "search": "*",
    "count": true,
    "skip": 50
  },
  "value": [
  ],
  "@odata.nextLink": "https://free-demo-search-svc.search.azure.cn/indexes/ny-philharmonic-index/docs/search?api-version=2024-07-01"
}

添加 search 参数以对字符串进行搜索。 添加 select 参数以将结果限制为更少的字段。 添加 filter 以进一步缩小搜索范围。

### Query the index
POST {{baseUrl}}/indexes/ny-philharmonic-index/docs/search?api-version=2024-07-01  HTTP/1.1
  Content-Type: application/json
  api-key: {{apiKey}}

  {
    "search": "puccini",
    "count": true,
    "select": "season, concerts/Date, works/composerName, works/workTitle",
    "filter": "season gt '2015-16'"
  }

响应中会返回两个文档。

对于筛选器,还可以使用逻辑运算符(and、or、not)和比较运算符(eq、ne、gt、lt、ge、le)。 字符串比较区分大小写。 有关详细信息和示例,请参阅创建查询

注意

$filter 参数只适用于在创建索引时标记为可筛选的字段。

重置并重新运行

可以通过清除执行历史记录来重置索引器,从而允许完全重新运行索引器。 以下 GET 请求用于重置,之后将重新运行索引器。

### Reset the indexer
POST {{baseUrl}}/indexers/ny-philharmonic-indexer/reset?api-version=2024-07-01  HTTP/1.1
  api-key: {{apiKey}}
### Run the indexer
POST {{baseUrl}}/indexers/ny-philharmonic-indexer/run?api-version=2024-07-01  HTTP/1.1
  api-key: {{apiKey}}
### Check indexer status 
GET {{baseUrl}}/indexers/ny-philharmonic-indexer/status?api-version=2024-07-01  HTTP/1.1
  api-key: {{apiKey}}

清理资源

在自己的订阅中操作时,最好在项目结束时删除不再需要的资源。 持续运行资源可能会产生费用。 可以逐个删除资源,也可以删除资源组以删除整个资源集。

可以使用门户来删除索引、索引器和数据源。

后续步骤

熟悉 Azure Blob 索引编制的基础知识后,接下来让我们更详细地了解 Azure 存储中 JSON Blob 的索引器配置。