Azure AI 搜索中的“简单”搜索查询示例

在 Azure AI 搜索中,简单查询语法调用默认查询分析程序来执行全文搜索。 此分析程序速度快,处理对象是全文搜索、筛选及分面搜索和前缀搜索等常见方案。 本文使用示例来说明搜索文档 (REST API) 请求中的简单语法用法。

注意

另一种查询语法是完整的 Lucene,它支持模糊搜索和通配符搜索等更复杂的查询结构。 有关详细信息和示例,请参阅使用完整的 Lucene 语法

酒店示例索引

以下查询基于 hotels-sample-index,你可以按照此快速入门中的说明进行创建。

示例查询使用 REST API 和 POST 请求来表达。 可以在 REST 客户端中粘贴并运行它们。 或者,在 Azure 门户中使用搜索资源管理器的 JSON 视图。 在 JSON 视图中,可以粘贴本文中所示的查询示例。

请求头必须具有以下值:

密钥
Content-Type application/json
api-key <your-search-service-api-key>,查询或管理密钥

URI 参数必须包括具有索引名、文档集合、搜索命令和 API 版本的搜索服务终结点,类似于以下示例:

https://{{service-name}}.search.azure.cn/indexes/hotels-sample-index/docs/search?api-version=2024-07-01

请求正文的格式应为有效的 JSON:

{
    "search": "*",
    "queryType": "simple",
    "select": "HotelId, HotelName, Category, Tags, Description",
    "count": true
}
  • “search”设置为 * 时,表示一个未指定的查询,等效于 NULL 或空搜索。 它不是特别有用,但却是你可以执行的最简单的搜索,并且会显示索引中所有可检索的字段以及所有值。

  • 默认情况下,“queryType”设置为“simple”,可以省略,但包含它可以进一步强调本文中的查询示例是采用简单语法来表达的。

  • “select”设置为以逗号分隔的字段列表时,可用于搜索结果组合,使其只包括在搜索结果上下文中有用的字段。

  • “count”返回与搜索条件匹配的文档数。 在空搜索字符串上,计数将是索引中的所有文档(在 hotels-sample-index 中,数量为 50)。

全文搜索可以是任意数量的独立词语或引号括起来的短语,其中包含或不包含布尔运算符。

POST /indexes/hotel-samples-index/docs/search?api-version=2024-07-01
{
    "search": "pool spa +airport",
    "searchMode": "any",
    "queryType": "simple",
    "select": "HotelId, HotelName, Category, Description",
    "count": true
}

由重要词语或短语组成的关键字搜索往往最适用。 在索引和查询过程中,字符串字段会进行文本分析,并删除非必要的单词,例如“the”、“and”和“it”。 若要查看如何在索引中标记化查询字符串,请在分析文本调用中将字符串传递给索引。

“SearchMode”参数可控制精准率和召回率。 如果需要更高召回率,请使用默认值“any”,即如果匹配查询字符串的任何部分,则将返回结果。 如果选择精准率,即必须完全匹配字符串,则将 searchMode 更改为“all”。 请尝试上述两种查询方法,了解 searchMode 如何改变结果。

对“pool spa +airport”查询的响应应类似于下面的示例,为简洁起见只截取了一部分。

"@odata.count": 6,
"value": [
    {
        "@search.score": 7.3617697,
        "HotelId": "21",
        "HotelName": "Nova Hotel & Spa",
        "Description": "1 Mile from the airport.  Free WiFi, Outdoor Pool, Complimentary Airport Shuttle, 6 miles from the beach & 10 miles from downtown.",
        "Category": "Resort and Spa",
        "Tags": [
            "pool",
            "continental breakfast",
            "free parking"
        ]
    },
    {
        "@search.score": 2.5560288,
        "HotelId": "25",
        "HotelName": "Scottish Inn",
        "Description": "Newly Redesigned Rooms & airport shuttle.  Minutes from the airport, enjoy lakeside amenities, a resort-style pool & stylish new guestrooms with Internet TVs.",
        "Category": "Luxury",
        "Tags": [
            "24-hour front desk service",
            "continental breakfast",
            "free wifi"
        ]
    },
    {
        "@search.score": 2.2988036,
        "HotelId": "35",
        "HotelName": "Suites At Bellevue Square",
        "Description": "Luxury at the mall.  Located across the street from the Light Rail to downtown.  Free shuttle to the mall and airport.",
        "Category": "Resort and Spa",
        "Tags": [
            "continental breakfast",
            "air conditioning",
            "24-hour front desk service"
        ]
    }
]

请注意响应中的搜索分数。 这是匹配项的相关性分数。 默认情况下,搜索服务将根据这个分数返回前 50 个匹配项。

当因为搜索不是全文搜索或者因为没有提供任何条件而没有排名时,会出现统一的分数“1.0”。 例如,在空搜索(搜索=*)中,行会按任意顺序返回。 包括实际条件时,你将看到搜索分数变成有意义的值。

示例 2:按 ID 查找

在查询中返回搜索结果时,合乎逻辑的下一步是提供包含文档中更多字段的详细信息页面。 此示例展示了如何使用查找文档通过传入文档 ID 来返回单个文档。

GET /indexes/hotels-sample-index/docs/41?api-version=2024-07-01

所有文档都有一个唯一标识符。 如果使用的是门户,请从“索引”选项卡中选择索引,然后查看字段定义以确定哪个字段是键。 通过使用 REST,获取索引调用会在响应正文中返回索引定义。

对上述查询的响应中包含键为 41 的文档。 在索引定义中标记为“retrievable”的任何字段都可以在搜索结果中返回并在应用中呈现。

{
    "HotelId": "41",
    "HotelName": "Ocean Air Motel",
    "Description": "Oceanfront hotel overlooking the beach features rooms with a private balcony and 2 indoor and outdoor pools. Various shops and art entertainment are on the boardwalk, just steps away.",
    "Description_fr": "L'hôtel front de mer surplombant la plage dispose de chambres avec balcon privé et 2 piscines intérieures et extérieures. Divers commerces et animations artistiques sont sur la promenade, à quelques pas.",
    "Category": "Budget",
    "Tags": [
        "pool",
        "air conditioning",
        "bar"
    ],
    "ParkingIncluded": true,
    "LastRenovationDate": "1951-05-10T00:00:00Z",
    "Rating": 3.5,
    "Location": {
        "type": "Point",
        "coordinates": [
            -157.846817,
            21.295841
        ],
        "crs": {
            "type": "name",
            "properties": {
                "name": "EPSG:4326"
            }
        }
    },
    "Address": {
        "StreetAddress": "1450 Ala Moana Blvd 2238 Ala Moana Ctr",
        "City": "Honolulu",
        "StateProvince": "HI",
        "PostalCode": "96814",
        "Country": "USA"
    }
}

示例 3:按文本筛选

筛选器语法是可以单独使用或配合 search 使用的 OData 表达式。 如果一起使用,则会先对整个索引应用 filter,再对筛选结果执行搜素。 filter 可减少 search 查询需要处理的文档集,因此是一种非常有用的技术,可用于提高查询性能。

筛选器可以在索引定义中标记为 filterable 的任何字段上定义。 对于 hotels-sample-index,可筛选字段包括类别、标记、ParkingIncluded、分级和大多数地址字段。

POST /indexes/hotels-sample-index/docs/search?api-version=2024-07-01
{
    "search": "art tours",
    "queryType": "simple",
    "filter": "Category eq 'Resort and Spa'",
    "searchFields": "HotelName,Description,Category",
    "select": "HotelId,HotelName,Description,Category",
    "count": true
}

上述查询的响应仅限于归类为“Report and Spa”的酒店,其中包括“art”或“tours”等术语。 在本例中,只有一个匹配项。

{
    "@search.score": 2.8576312,
    "HotelId": "31",
    "HotelName": "Santa Fe Stay",
    "Description": "Nestled on six beautifully landscaped acres, located 2 blocks from the Plaza. Unwind at the spa and indulge in art tours on site.",
    "Category": "Resort and Spa"
}

示例 4:筛选器函数

筛选器表达式可以包含“search.ismatch”和“search.ismatchscoring”函数,便于在筛选器中构建搜索查询。 此筛选器表达式在 free 上使用通配符,以选择免费 Wi-Fi、免费停车等设施。

POST /indexes/hotels-sample-index/docs/search?api-version=2024-07-01
  {
    "search": "",
    "filter": "search.ismatch('free*', 'Tags', 'full', 'any')",
    "select": "HotelId, HotelName, Category, Description",
    "count": true
  }

对上述查询的响应匹配了 19 家提供免费设施的酒店。 请注意,所有结果的搜索分数都是“1.0”。 这是因为搜索表达式为 NULL 或为空,导致逐字筛选器匹配,但未进行全文搜索。 仅全文搜索时返回相关性分数。 如果使用的筛选器没有 search,请确保有足够的可排序字段,以便可以控制搜索排名。

"@odata.count": 19,
"value": [
    {
        "@search.score": 1.0,
        "HotelId": "31",
        "HotelName": "Santa Fe Stay",
        "Tags": [
            "view",
            "restaurant",
            "free parking"
        ]
    },
    {
        "@search.score": 1.0,
        "HotelId": "27",
        "HotelName": "Super Deluxe Inn & Suites",
        "Tags": [
            "bar",
            "free wifi"
        ]
    },
    {
        "@search.score": 1.0,
        "HotelId": "39",
        "HotelName": "Whitefish Lodge & Suites",
        "Tags": [
            "continental breakfast",
            "free parking",
            "free wifi"
        ]
    },
    {
        "@search.score": 1.0,
        "HotelId": "11",
        "HotelName": "Regal Orb Resort & Spa",
        "Tags": [
            "free wifi",
            "restaurant",
            "24-hour front desk service"
        ]
    },

示例 5:范围筛选器

通过任何数据类型的筛选器表达式支持范围筛选。 下面的示例演示数值和字符串范围。 数据类型在范围筛选器中很重要,当数字数据位于数字字段且字符串数据位于字符串字段中时效果最佳。 由于数字字符串不可比较,因此字符串字段中的数字数据不适用于范围。

以下查询是一个数字范围。 在 hotels-sample-index 中,唯一可筛选的数字字段为“分级”。

POST /indexes/hotels-sample-index/docs/search?api-version=2024-07-01
{
    "search": "*",
    "filter": "Rating ge 2 and Rating lt 4",
    "select": "HotelId, HotelName, Rating",
    "orderby": "Rating desc",
    "count": true
}

对此查询的响应应类似于下面的示例,为简洁起见只截取了一部分。

"@odata.count": 27,
"value": [
    {
        "@search.score": 1.0,
        "HotelId": "22",
        "HotelName": "Stone Lion Inn",
        "Rating": 3.9
    },
    {
        "@search.score": 1.0,
        "HotelId": "25",
        "HotelName": "Scottish Inn",
        "Rating": 3.8
    },
    {
        "@search.score": 1.0,
        "HotelId": "2",
        "HotelName": "Twin Dome Motel",
        "Rating": 3.6
    }
...

接下来的查询是基于字符串字段 (Address/StateProvince) 的范围筛选器:

POST /indexes/hotels-sample-index/docs/search?api-version=2024-07-01
{
    "search": "*",
    "filter": "Address/StateProvince ge 'A*' and Address/StateProvince lt 'D*'",
    "select": "HotelId, HotelName, Address/StateProvince",
    "count": true
}

对此查询的响应应类似于下面的示例,为简洁起见只截取了一部分。 在此示例中,无法通过 StateProvince 进行排序,因为该字段在索引定义中未属性化为“sortable”。

"@odata.count": 9,
"value": [
    {
        "@search.score": 1.0,
        "HotelId": "9",
        "HotelName": "Smile Hotel",
        "Address": {
            "StateProvince": "CA "
        }
    },
    {
        "@search.score": 1.0,
        "HotelId": "39",
        "HotelName": "Whitefish Lodge & Suites",
        "Address": {
            "StateProvince": "CO"
        }
    },
    {
        "@search.score": 1.0,
        "HotelId": "7",
        "HotelName": "Countryside Resort",
        "Address": {
            "StateProvince": "CA "
        }
    },
...

hotels-sample 索引包含带有纬度和经度坐标的位置字段。 此示例使用 geo.distance 函数来筛选从起点开始,直到所提供的任意距离(以公里为单位)圆周范围内的文档。 可以调整查询 (10) 中的最后一个值,以缩小或放大查询的表面积。

POST /indexes/v/docs/search?api-version=2024-07-01
{
    "search": "*",
    "filter": "geo.distance(Location, geography'POINT(-122.335114 47.612839)') le 10",
    "select": "HotelId, HotelName, Address/City, Address/StateProvince",
    "count": true
}

对此查询的响应会返回距所提供坐标 10 公里内的所有酒店:

{
    "@odata.count": 3,
    "value": [
        {
            "@search.score": 1.0,
            "HotelId": "45",
            "HotelName": "Arcadia Resort & Restaurant",
            "Address": {
                "City": "Seattle",
                "StateProvince": "WA"
            }
        },
        {
            "@search.score": 1.0,
            "HotelId": "24",
            "HotelName": "Gacc Capital",
            "Address": {
                "City": "Seattle",
                "StateProvince": "WA"
            }
        },
        {
            "@search.score": 1.0,
            "HotelId": "16",
            "HotelName": "Double Sanctuary Resort",
            "Address": {
                "City": "Seattle",
                "StateProvince": "WA"
            }
        }
    ]
}

示例 7:使用 searchMode 的布尔值

简单语法支持字符形式 (+, -, |) 的布尔运算符,从而支持 AND、OR 和 NOT 查询逻辑。 布尔型搜索的行为符合预期,但有几个值得注意的例外情况。

在前面的示例中,引入了 searchMode 参数作为影响精准率和召回率的机制,其中 "searchMode": "any" 倾向于召回率(满足任一条件的文档被视为匹配),而“searchMode=all”倾向于精准率(文档必须匹配所有条件)。

在布尔搜索的上下文中,如果使用多个运算符堆叠查询并获取更广泛而不是更窄的结果,默认 "searchMode": "any" 可能会产生混淆。 在使用 NOT 时尤为如此,该运算符导致结果包括所有“不含”特定字词或短语的文档。

下面的示例进行了这方面的演示。 使用 searchMode (any) 运行以下查询时,返回了 42 个文档:其中有包含字词“restaurant”的文档,以及所有不带短语“air conditioning”的文档。

注意,布尔运算符 (-) 和短语“air conditioning”之间没有空格。

POST /indexes/hotels-sample-index/docs/search?api-version=2024-07-01
{
    "search": "restaurant -\"air conditioning\"",
    "searchMode": "any",
    "searchFields": "Tags",
    "select": "HotelId, HotelName, Tags",
    "count": true
}

更改为 "searchMode": "all" 会对条件产生累积影响并返回较小的结果集(7 个匹配项),其文档数是包含字词“restaurant”的文档减去包含短语“air conditioning”的文档之差。

现在,对此查询的响应应类似于下面的示例,为简洁起见只截取了一部分。

"@odata.count": 7,
"value": [
    {
        "@search.score": 2.5460577,
        "HotelId": "11",
        "HotelName": "Regal Orb Resort & Spa",
        "Tags": [
            "free wifi",
            "restaurant",
            "24-hour front desk service"
        ]
    },
    {
        "@search.score": 2.166792,
        "HotelId": "10",
        "HotelName": "Countryside Hotel",
        "Tags": [
            "24-hour front desk service",
            "coffee in lobby",
            "restaurant"
        ]
    },
...

示例 8:分页结果

前面的示例中说明了影响搜索结果组合的参数,包括确定结果中包含哪些字段的 select、排序顺序以及如何包含所有匹配项的计数。 本示例继续介绍用于搜索结果组合的分页参数,通过该参数,你可以确定任何给定页面中显示的批结果数。

默认情况下,搜索服务会返回前 50 个匹配项。 若要控制每个页面中的匹配数,请使用 top 定义批大小,然后使用 skip 来选取后续批。

下面的示例对“分级”字段(“分级”既可筛选又可排序)使用筛选器和排序顺序,因为这样可以更轻松地看到分页对排序结果的影响。 在常规的完全搜索查询中,最匹配的项由 @search.score 排名和分页。

POST /indexes/hotels-sample-index/docs/search?api-version=2024-07-01
{
    "search": "*",
    "filter": "Rating gt 4",
    "select": "HotelName, Rating",
    "orderby": "Rating desc",
    "top": "5",
    "count": true
}

查询找到了 21 个匹配的文档,但是因为指定了 top,所以响应只返回前五个匹配的文档,评级从 4.9 开始,到 4.7 结束时为“Lady of the Lake B & B”。

要获取后续 5 个文档,请跳过第一批:

POST /indexes/hotels-sample-index/docs/search?api-version=2024-07-01
{
    "search": "*",
    "filter": "Rating gt 4",
    "select": "HotelName, Rating",
    "orderby": "Rating desc",
    "top": "5",
    "skip": "5",
    "count": true
}

对第二批的响应将跳过前五个匹配项,并从“Pull'r Inn Motel”开始,返回后五个匹配项。 若要继续处理更多批,需将 top 保持为 5,然后在每个新请求上将 skip 增加 5(skip=5、skip=10、skip=15,依此类推)。

"value": [
    {
        "@search.score": 1.0,
        "HotelName": "Pull'r Inn Motel",
        "Rating": 4.7
    },
    {
        "@search.score": 1.0,
        "HotelName": "Sublime Cliff Hotel",
        "Rating": 4.6
    },
    {
        "@search.score": 1.0,
        "HotelName": "Antiquity Hotel",
        "Rating": 4.5
    },
    {
        "@search.score": 1.0,
        "HotelName": "Nordick's Motel",
        "Rating": 4.5
    },
    {
        "@search.score": 1.0,
        "HotelName": "Winter Panorama Resort",
        "Rating": 4.5
    }
]

后续步骤

现在,你已经使用了基本查询语法,可以尝试在代码中指定查询。 以下链接介绍了如何使用 Azure SDK 设置搜索查询。

可在以下链接中找到更多语法参考、查询体系结构和示例: