本部分通过示例扩展了分面导航配置,这些示例展示了基本用法和其他情境。
facetable 字段在索引中定义,但 facet 参数和表达式在查询请求中定义。 如果有具有可分面字段的索引,可以尝试对现有索引使用分面 层次结构、 分面聚合和 分面筛选器 等新的预览功能。
facet 参数和语法
根据 API,分面查询通常是应用于搜索结果的分面表达式数组。 每个 facet 表达式都包含一个 facetable 字段名称,可以选择后跟逗号分隔的名称值对列表。
- 分面查询是包含分面属性的查询请求。
-
可分面字段 是在搜索索引中定义的一个字段,该字段具有
facetable
属性。 - count 是搜索结果中找到的每个方面的匹配项数。
下表介绍了示例中使用的分面参数。
分面参数 | DESCRIPTION | 用法 | 示例: |
---|---|---|---|
count |
每个结构的最大 facet 术语数。 | 整数。 默认值为 10。 没有上限,但较高的值会降低性能,尤其是在分面字段包含大量唯一术语时。 这由 facet 查询分布在各个分片上的方式所导致。 可以将 count 设置为零或者设置为大于或等于 facetable 字段中唯一值的数量,以获取所有分片的准确计数。 折衷方案是增加延迟。 |
Tags,count:5 会将分面导航响应限制在包含最多分面计数的 5 个分面组内,但这些可以按任何顺序排列。 |
sort |
确定 facet 存储桶的顺序。 | 有效值为 count ,, -count value 。 -value 可使用 count 按从大到小的顺序列出 facet。 用于 -count 按升序排序(从小到大)。 可使用 value 按 facet 值以升序对字母数字进行排序。 使用 -value 按值降序排序。 |
"facet=Category,count:3,sort:count" 获取在搜索结果中排名前三的 facet 存储桶,在每个类别中按匹配项数量降序排列。 如果前三类是“Budget”、“Extended-Stay”和“Luxury”,而“Budget”有 5 个命中数,“Extended-Stay”有 6 个,而“Luxury”有 4 个,则 facet 存储桶将按“Extended-Stay”、“Budget”、“Luxury”的顺序排列。 另一个示例是"facet=Rating,sort:-value" 。 它为所有可能的排名生成 facet,按值降序排序。 如果排名是从 1 到 5,则 facet 的排序顺序为 5、4、3、2、1,而不考虑每个排名与多少文档匹配。 |
values |
提供 facet 标签的值。 | 设置为竖线分隔数字或 Edm.DateTimeOffset 值,用于指定分面项值的动态组。 这些值必须按顺序按升序列出才能获取预期结果。 |
"facet=baseRate,values:10 | 20" 生成三个 facet 存储桶:一个用于基准费率 0 到(但不包括)10,一个用于 10 到(但不包括)20,一个用于 20 和更高。 字符串 "facet=lastRenovationDate,values:2024-02-01T00:00:00Z" 生成两个 facet 存储桶:一个用于在 2024 年 2 月之前翻新的酒店,一个用于在 2024 年 2 月 1 日或以后翻新的酒店。 |
interval |
为可分组为间隔的 facet 提供间隔序列。 | 数字或分钟、小时、日、周、月、季度、年等日期时间值的整数间隔大于零。 |
"facet=baseRate,interval:100" 基于大小 100 的基准费率排名生成 facet 存储桶。 如果基准费率全部在 60 美元和 600 美元之间,则有用于 0-100、100-200、200-300、300-400、400-500 和 500-600 的 facet 存储桶。 字符串 "facet=lastRenovationDate,interval:year" 为酒店翻新的每个年份生成一个 facet 存储桶。 |
timeoffset |
指定设置时间边界时要考虑的 UTC 时间偏移量。 | 设置为 ([+-]hh:mm, [+-]hhmm, or [+-]hh )。 如果使用 timeoffset 参数,则必须将其与间隔选项组合在一起,并且仅当应用于 Edm.DateTimeOffset 类型的字段时。 |
"facet=lastRenovationDate,interval:day,timeoffset:-01:00" 使用从 01:00:00 UTC(目标时区的午夜)开始的日边界。 |
count
和 sort
可以在同一方面规范中组合,但不能与 interval
或 values
组合。
interval
和 values
不能组合在一起。
未指定 timeoffset
时,日期时间的间隔分面将基于 UTC 时间计算。 例如, "facet=lastRenovationDate,interval:day"
日边界从 00:00:00 UTC 开始。
基本 facet 示例
以下 facet 查询适用于酒店示例索引。 可以在搜索资源管理器中使用 JSON 视图 粘贴 JSON 查询。 有关如何入门的帮助,请参阅向搜索结果添加分面导航。
第一个查询检索 Categories、Ratings、Tags 以及 baseRate 值在特定范围内时的房间的 facet。 请注意,最后一个 facet 位于 Rooms 集合的子字段上。 facet 是对父文档 (Hotels) 进行计数,而不是中间子文档 (Rooms),因此响应会确定每个定价类别中有房间的酒店数量。
POST /indexes/hotels-sample-index/docs/search?api-version=2025-03-01-Preview
{
"search": "ocean view",
"facets": [ "Category", "Rating", "Tags", "Rooms/BaseRate,values:80|150|220" ],
"count": true
}
第二个示例使用筛选器在用户选择“Rating 3”和“Motel”类别后缩小先前分面查询结果的范围。
POST /indexes/hotels-sample-index/docs/search?api-version=2025-03-01-Preview
{
"search": "water view",
"facets": [ "Tags", "Rooms/BaseRate,values:80|150|220" ],
"filter": "Rating eq 3 and Category eq 'Motel'",
"count": true
}
第三个示例设置查询中返回的唯一术语的上限。 默认值为 10,但可以使用 facet 属性上的 count 参数增加或减少此值。 此示例返回城市 facet,限制为 5。
POST /indexes/hotels-sample-index/docs/search?api-version=2025-03-01-Preview
{
"search": "view",
"facets": [ "Address/City,count:5" ],
"count": true
}
本示例显示了“Category”、“Tags”和“Rating”三个 facet,对“Tags”应用计数覆盖,对“Rating”应用范围覆盖,此外,在索引中它们以双精度数存储。
POST https://{{service_name}}.search.azure.cn/indexes/hotels/docs/search?api-version={{api_version}}
{
"search": "*",
"facets": [
"Category",
"Tags,count:5",
"Rating,values:1|2|3|4|5"
],
"count": true
}
对于每个分面导航树,默认限制是查询找到的前 10 个分面实例。 此默认值对导航结构有意义,因为它可使值列表保持在合理的大小。 可通过向“count”分配某个值来替代默认值。 例如,"Tags,count:5"
可将“Tags”部分下的 tag 数减少到前五位。
仅对于 Numeric 和 DateTime 值,可以在分面字段上显式设置值(例如,facet=Rating,values:1|2|3|4|5
),以便将结果划分为连续的范围,可以是基于数值的范围,也可以是时间段。 或者,也可以添加“interval”,如 facet=Rating,interval:1
。
通过以下方式生成每个范围:使用 0 作为起点、使用列表中的某个值作为终结点,并剪裁上一个范围以创建离散间隔。
不同值示例
可以构建一个查询,该查询将返回每个 facetable 字段中唯一值的计数。 本示例构建了一个空查询或非限定查询("search": "*"
),该查询与所有文档匹配,但通过将 top
设置为零,仅获取计数,没有具体结果。
为了简洁起见,此查询仅包含两个在酒店示例索引中标记为 facetable
的字段。
POST https://{{service_name}}.search.azure.cn/indexes/hotels/docs/search?api-version={{api_version}}
{
"search": "*",
"count": true,
"top": 0,
"facets": [
"Category", "Address/StateProvince""
]
}
此查询的结果如下所示:
{
"@odata.count": 50,
"@search.facets": {
"Address/StateProvince": [
{
"count": 9,
"value": "WA"
},
{
"count": 6,
"value": "CA "
},
{
"count": 4,
"value": "FL"
},
{
"count": 3,
"value": "NY"
},
{
"count": 3,
"value": "OR"
},
{
"count": 3,
"value": "TX"
},
{
"count": 2,
"value": "GA"
},
{
"count": 2,
"value": "MA"
},
{
"count": 2,
"value": "TN"
},
{
"count": 1,
"value": "AZ"
}
],
"Category": [
{
"count": 13,
"value": "Budget"
},
{
"count": 12,
"value": "Suite"
},
{
"count": 7,
"value": "Boutique"
},
{
"count": 7,
"value": "Resort and Spa"
},
{
"count": 6,
"value": "Extended-Stay"
},
{
"count": 5,
"value": "Luxury"
}
]
},
"value": []
}
facet 层次结构示例
注释
此功能目前处于公开预览状态。 此预览版未随附服务级别协议,建议不要用于生产工作负载。 某些功能可能不受支持或者受限。 有关详细信息,请参阅适用于 Azure 预览版的补充使用条款。
从 2025-03-01 预览版 REST API 开始,并在 Azure 门户中提供,您可以使用 >
和 ;
运算符来配置分面层次结构。
Operator | DESCRIPTION |
---|---|
> |
嵌套(分层)运算符表示父子关系。 |
; |
分号运算符表示同一嵌套级别的多个字段,这些字段都是同一父级的子级。 父级只能包含一个字段。 父字段和子字段必须是 facetable 。 |
分面表达式中包含分面层次结构时的操作顺序如下:
- 用于分隔分面字段参数的选项运算符(如逗号
,
),例如在Rooms/BaseRate,values
中的逗号 - 括号,例如括住
(Rooms/BaseRate,values:50 ; Rooms/Type)
的那些。 - 嵌套运算符(尖括号
>
) - 追加运算符(分号
;
)在本部分的第二个示例"Tags>(Rooms/BaseRate,values:50 ; Rooms/Type)"
中演示,其中两个子面为标签父节点的同级。
请注意,括号是在嵌套和追加操作之前处理的:A > B ; C
与 A > (B ; C)
不同。
分面层次结构有几个示例。 第一个示例是只返回几个文档的查询,这有助于查看完整响应。 facet 是对父文档 (Hotels) 进行计数,而不是中间子文档 (Rooms),因此响应结果确定的是每个 facet 存储桶中有房间的酒店数量。
POST /indexes/hotels-sample-index/docs/search?api-version=2025-03-01-Preview
{
"search": "ocean",
"facets": ["Address/StateProvince>Address/City", "Tags>Rooms/BaseRate,values:50"],
"select": "HotelName, Description, Tags, Address/StateProvince, Address/City",
"count": true
}
此查询的结果如下所示。 两家酒店都有游泳池。 对于其他标签,只有一家酒店提供便利设施。
{
"@odata.count": 2,
"@search.facets": {
"Tags": [
{
"value": "pool",
"count": 2,
"@search.facets": {
"Rooms/BaseRate": [
{
"to": 50,
"count": 0
},
{
"from": 50,
"count": 2
}
]
}
},
{
"value": "air conditioning",
"count": 1,
"@search.facets": {
"Rooms/BaseRate": [
{
"to": 50,
"count": 0
},
{
"from": 50,
"count": 1
}
]
}
},
{
"value": "bar",
"count": 1,
"@search.facets": {
"Rooms/BaseRate": [
{
"to": 50,
"count": 0
},
{
"from": 50,
"count": 1
}
]
}
},
{
"value": "restaurant",
"count": 1,
"@search.facets": {
"Rooms/BaseRate": [
{
"to": 50,
"count": 0
},
{
"from": 50,
"count": 1
}
]
}
},
{
"value": "view",
"count": 1,
"@search.facets": {
"Rooms/BaseRate": [
{
"to": 50,
"count": 0
},
{
"from": 50,
"count": 1
}
]
}
}
],
"Address/StateProvince": [
{
"value": "FL",
"count": 1,
"@search.facets": {
"Address/City": [
{
"value": "Tampa",
"count": 1
}
]
}
},
{
"value": "HI",
"count": 1,
"@search.facets": {
"Address/City": [
{
"value": "Honolulu",
"count": 1
}
]
}
}
]
},
"value": [
{
"@search.score": 1.6076145,
"HotelName": "Ocean Water Resort & Spa",
"Description": "New Luxury Hotel for the vacation of a lifetime. Bay views from every room, location near the pier, rooftop pool, waterfront dining & more.",
"Tags": [
"view",
"pool",
"restaurant"
],
"Address": {
"City": "Tampa",
"StateProvince": "FL"
}
},
{
"@search.score": 1.0594962,
"HotelName": "Windy Ocean Motel",
"Description": "Oceanfront hotel overlooking the beach features rooms with a private balcony and 2 indoor and outdoor pools. Inspired by the natural beauty of the island, each room includes an original painting of local scenes by the owner. Rooms include a mini fridge, Keurig coffee maker, and flatscreen TV. Various shops and art entertainment are on the boardwalk, just steps away.",
"Tags": [
"pool",
"air conditioning",
"bar"
],
"Address": {
"City": "Honolulu",
"StateProvince": "HI"
}
}
]
}
第二个示例对上一个示例进行了扩展,展示了具有多个子项的多个顶级 facet。 请注意,分号(;
)运算符用于分隔每个子项。
POST /indexes/hotels-sample-index/docs/search?api-version=2025-03-01-Preview
{
"search": "+ocean",
"facets": ["Address/StateProvince > Address/City", "Tags > (Rooms/BaseRate,values:50 ; Rooms/Type)"],
"select": "HotelName, Description, Tags, Address/StateProvince, Address/City",
"count": true
}
为简洁起见,对部分响应进行了删减,显示了带有房间基准费率和类型的子级 facet 的 Tags。 在酒店示例索引中,匹配的两家酒店 +ocean
都有每种类型的房间和一个游泳池。
{
"@odata.count": 2,
"@search.facets": {
"Tags": [
{
"value": "pool",
"count": 2,
"@search.facets": {
"Rooms/BaseRate": [
{
"to": 50,
"count": 0
},
{
"from": 50,
"count": 2
}
],
"Rooms/Type": [
{
"value": "Budget Room",
"count": 2
},
{
"value": "Deluxe Room",
"count": 2
},
{
"value": "Standard Room",
"count": 2
},
{
"value": "Suite",
"count": 2
}
]
}}]},
...
}
最后一个示例显示了影响嵌套级别的括号优先规则。 假设要按此顺序返回 facet 层次结构。
Address/StateProvince
Address/City
Category
Rating
若要返回此层次结构,请创建一个查询,其中类别和分级是地址/城市下的同级。
{
"search": "beach",
"facets": [
"Address/StateProvince > (Address/City > (Category ; Rating))"
],
"select": "HotelName, Description, Tags, Address/StateProvince, Address/City",
"count": true
}
如果去掉最内侧的括号,Category 和 Rating 将不再具有相同优先级,因为优先级规则规定运算符 >
比 ;
的优先级更高。
{
"search": "beach",
"facets": [
"Address/StateProvince > (Address/City > Category ; Rating)"
],
"select": "HotelName, Description, Tags, Address/StateProvince, Address/City",
"count": true
}
顶级父级仍然是 Address/StateProvince,但现在 Address/City 和 Rating 处于同一级别。
Address/StateProvince
Rating
Address/City
Category
facet 筛选示例
注释
此功能目前处于公开预览状态。 此预览版未随附服务级别协议,建议不要用于生产工作负载。 某些功能可能不受支持或者受限。 有关详细信息,请参阅适用于 Azure 预览版的补充使用条款。
从 2025-03-01 预览版 REST API 开始,您可以通过 Azure 门户访问并配置分面筛选器。
通过 facet 筛选,可以将返回的 facet 值限制为符合指定正则表达式的值。 两个新参数接受一个应用到分面字段的正则表达式:
-
includeTermFilter
将分面值筛选为与正则表达式匹配的值 -
excludeTermFilter
将分面值筛选为与正则表达式不匹配的值
如果 facet 字符串同时满足这两个条件,则 excludeTermFilter
优先,因为先用 includeTermFilter
评估存储桶字符串集,然后用 excludeTermFilter
排除。
仅返回与正则表达式匹配的分面值。 可以将这些参数与其他分面选项(例如,count
sort
和分层分面)组合在字符串字段上。
由于正则表达式嵌套在 JSON 字符串值内,因此必须转义双引号 ("
) 和反斜杠 (\
) 字符。 正则表达式本身由正斜杠 (/
) 分隔。 有关转义模式的详细信息,请参阅 正则表达式搜索。
以下示例展示了如何转义正则表达式中的特殊字符,例如反斜杠、双引号或正则表达式语法字符。
{
"search": "*",
"facets": ["name,includeTermFilter:/EscapeBackslash\\\OrDoubleQuote\\"OrRegexCharacter\\(/"]
}
下面是一个与 Budget 和 Extended-Stay 酒店匹配的 facet 筛选器示例,其中 Rating 是每个酒店类别的子项。
POST /indexes/hotels-sample-index/docs/search?api-version=2025-03-01-Preview
{
"search": "*",
"facets": ["(Category,includeTermFilter:/(Budget|Extended-Stay)/)>Rating,values:1|2|3|4|5"],
"select": "HotelName, Category, Rating",
"count": true
}
以下示例是一个缩写的响应(为了简洁起见,省略酒店文档)。
{
"@odata.count": 50,
"@search.facets": {
"Category": [
{
"value": "Budget",
"count": 13,
"@search.facets": {
"Rating": [
{
"to": 1,
"count": 0
},
{
"from": 1,
"to": 2,
"count": 0
},
{
"from": 2,
"to": 3,
"count": 4
},
{
"from": 3,
"to": 4,
"count": 5
},
{
"from": 4,
"to": 5,
"count": 4
},
{
"from": 5,
"count": 0
}
]
}
},
{
"value": "Extended-Stay",
"count": 6,
"@search.facets": {
"Rating": [
{
"to": 1,
"count": 0
},
{
"from": 1,
"to": 2,
"count": 0
},
{
"from": 2,
"to": 3,
"count": 4
},
{
"from": 3,
"to": 4,
"count": 1
},
{
"from": 4,
"to": 5,
"count": 1
},
{
"from": 5,
"count": 0
}
]
}
}
]
},
"value": [ ALL 50 HOTELS APPEAR HERE ]
}
facet 聚合示例
注释
此功能目前处于公开预览状态。 此预览版未随附服务级别协议,建议不要用于生产工作负载。 某些功能可能不受支持或者受限。 有关详细信息,请参阅适用于 Azure 预览版的补充使用条款。
从 2025-03-01-preview REST API 开始,可以在 Azure 门户中聚合 facet。
分面聚合允许从分面值计算指标。 聚合功能可与现有的 facet 选项一起使用。 唯一支持的指标是 sum
。 将 metric: sum
添加到数值 facet 中将聚合每个存储桶中所有的值。
如果文档包含该字段的 null,则可以添加要使用的默认值: "facets": [ "Rooms/SleepsCount, metric: sum, default:2"]
如果房间的 Rooms/SleepsCount 字段有 null 值,将使用默认值替代缺失值。
您可以对数值数据类型的任何可分面字段(矢量和地理坐标除外)求和。
下面是使用 hotels-sample-index 的示例。 Room/SleepsCount 字段可分面且具有数值,因此我们选择此字段来演示总和。 如果我们对该字段求和,就会获得整个酒店的住宿计数。 请注意,facet 是对父文档 (Hotels) 进行计数,而不是中间子文档 (Rooms),因此响应结果对整个酒店所有房间的 SleepsCount 进行求和。 在此查询中,我们将添加一个筛选器,以便只对一家酒店的 SleepsCount 求和。
POST /indexes/hotels-sample-index/docs/search?api-version=2025-03-01-Preview
{
"search": "*",
"filter": "HotelId eq '41'",
"facets": [ "Rooms/SleepsCount, metric: sum"],
"select": "HotelId, HotelName, Rooms/Type, Rooms/SleepsCount",
"count": true
}
查询的响应可能如以下示例所示。 风洋模型总共可容纳 40 名客人。
{
"@odata.count": 1,
"@search.facets": {
"Rooms/SleepsCount": [
{
"sum": 40.0
}
]
},
"value": [
{
"@search.score": 1.0,
"HotelId": "41",
"HotelName": "Windy Ocean Motel",
"Rooms": [
{
"Type": "Suite",
"SleepsCount": 4
},
{
"Type": "Deluxe Room",
"SleepsCount": 2
},
{
"Type": "Budget Room",
"SleepsCount": 2
},
{
"Type": "Budget Room",
"SleepsCount": 2
},
{
"Type": "Suite",
"SleepsCount": 2
},
{
"Type": "Standard Room",
"SleepsCount": 2
},
{
"Type": "Deluxe Room",
"SleepsCount": 2
},
{
"Type": "Suite",
"SleepsCount": 2
},
{
"Type": "Suite",
"SleepsCount": 4
},
{
"Type": "Standard Room",
"SleepsCount": 4
},
{
"Type": "Standard Room",
"SleepsCount": 2
},
{
"Type": "Deluxe Room",
"SleepsCount": 2
},
{
"Type": "Suite",
"SleepsCount": 2
},
{
"Type": "Standard Room",
"SleepsCount": 2
},
{
"Type": "Deluxe Room",
"SleepsCount": 2
},
{
"Type": "Deluxe Room",
"SleepsCount": 2
},
{
"Type": "Standard Room",
"SleepsCount": 2
}
]
}
]
}
后续步骤
重新访问工具和 API 的 分面导航配置 ,并查看有关在代码中使用分面的 最佳做法 。
建议 C#: 向 Web 应用添加搜索功能,这是一种包括表示层代码的分面导航示例。 此示例还包括筛选器、建议和自动完成。 它对呈现层使用 JavaScript 和 React。