文本查询中的筛选器

筛选器提供基于值的条件,用于在执行查询之前包括或排除内容。 例如,基于日期、位置或语言包括或排除文档。 筛选器是在单个字段上指定的。 如果要在筛选器表达式中使用字段定义,则必须将字段定义属性为“filterable”。

使用 OData 筛选器表达式语法指定筛选器。 与全文搜索相反,仅当完全匹配时,筛选器才会成功。

使用筛选器的时机

筛选器在多种搜索体验中不可或缺,包括“附近查找”地理空间搜索、分面导航,以及仅显示允许用户查看的文档的安全筛选器。 如果实施其中任何一种体验,必须使用筛选器。 该筛选器会附加到提供地理位置坐标的搜索查询、用户选择的分面类别,或请求者的安全 ID。

常见方案包括:

  • 基于索引中的内容的切分搜索结果。 如果某个架构具有酒店位置、类别和便利设施,则可以创建一个筛选器,以显式匹配条件(在西雅图,在水上,看风景)。

  • 实现附带筛选依赖关系的搜索体验:

    • 分面导航使用筛选器传回用户选择的分面类别。
    • 地理空间搜索使用筛选器在“附近查找”应用和函数中传递当前位置的坐标,这些应用和函数匹配某一范围或距离。
    • 安全筛选器将安全标识符作为筛选条件进行传递,在索引中找到的匹配项充当代理,提供对文档的访问权限。
  • 执行“数字搜索”。 数字字段可检索并可显示在搜索结果中,但不可单独搜索(受全文搜索的限制)。 如果需要基于数字数据施加选择条件,请使用筛选器。

如何执行筛选器

在查询时,筛选器分析器会接受作为输入提供的条件、将表达式转换为树状表示的原子布尔表达式,然后基于索引中的可筛选字段评估筛选器树。

筛选是配合搜索发生的,限定要将哪些文档包含在下游处理流程中进行文档检索和相关性评分。 与搜索字符串搭配使用时,筛选器能够有效减小后续搜索操作的重调集。 如果单独使用(例如,在 search=* 中查询字符串为空时),筛选条件是唯一的输入。

定义筛选器

筛选器是 OData 表达式,如 Azure AI 搜索支持的筛选语法中所述。

可为每个搜索操作指定一个筛选器,但筛选器本身可以包含多个字段和多个条件,如果使用 ismatch 函数,则还可以包含多个全文搜索表达式。 在多部分筛选表达式中,可按任意顺序指定谓词(受运算符优先顺序规则的约束)。 如果尝试按特定的顺序重新排列谓词,性能不会有明显的提升。

筛选表达式的限制之一是请求的最大大小限制。 整个 POST 请求(包括筛选器)最大可为 16 MB;对于 GET 请求,最大可为 8 KB。 筛选表达式中的子句数也有限制。 根据经验,如果有数百个子句,则就存在达到限制的风险。 我们建议正确设计应用程序,使之不会生成大小不受限制的筛选器。

以下示例显示了多个 API 中的原型筛选器定义。

POST https://[service name].search.azure.cn/indexes/hotels/docs/search?api-version=2024-07-01
{
    "search": "*",
    "filter": "Rooms/any(room: room/BaseRate lt 150.0)",
    "select": "HotelId, HotelName, Rooms/Description, Rooms/BaseRate"
}
options = new SearchOptions()
{
    Filter = "Rating gt 4",
    OrderBy = { "Rating desc" }
};

筛选模式

以下示例演示了筛选器方案的多种使用模式。 有关更多思路,请参阅 OData 表达式语法 > 示例

  • 单独使用 $filter 而不使用查询字符串:如果筛选表达式能够完全限定所需的文档,则此模式很有效。 不使用查询字符串也就不会执行词法或语言分析、评分和排名。 请注意,搜索字符串只是一个星号,表示“匹配所有文档”。

    {
      "search": "*",
      "filter": "Rooms/any(room: room/BaseRate ge 60 and room/BaseRate lt 300) and Address/City eq 'Honolulu"
    }
    
  • 将查询字符串与 $filter 结合使用:让筛选器创建子集,让查询字符串提供字词输入,用于对筛选的子集进行全文搜索。 添加搜索词(“步行距离内的影院”)可以在结果中引入搜索分数,与搜索词最匹配的文档的排名较高。 将筛选器与查询字符串结合使用是最常见的使用模式。

    {
      "search": "walking distance theaters",
      "filter": "Rooms/any(room: room/BaseRate ge 60 and room/BaseRate lt 300) and Address/City eq 'Seattle'"
    }
    
    
  • 复合查询:使用“or”分隔查询,每个查询有自身的筛选条件(例如,'beagles' in 'dog' or 'siamese' in 'cat')。 以 or 合并的表达式将单独求值,响应中会发回与每个表达式匹配的文档的联合。 此使用模式是通过 search.ismatchscoring 函数实现的。 还可以使用非计分版本 search.ismatch

    # Match on hostels rated higher than 4 OR 5-star motels.
    $filter=search.ismatchscoring('hostel') and Rating ge 4 or search.ismatchscoring('motel') and Rating eq 5
    
    # Match on 'luxury' or 'high-end' in the description field OR on category exactly equal to 'Luxury'.
    $filter=search.ismatchscoring('luxury | high-end', 'Description') or Category eq 'Luxury'&$count=true
    

    还可以使用 and(而不是 or)通过包含筛选器的 search.ismatchscoring 来合并全文搜索,但这在功能上相当于在搜索请求中使用 search$filter 参数。 例如,以下两个查询生成相同的结果:

    $filter=search.ismatchscoring('pool') and Rating ge 4
    
    search=pool&$filter=Rating ge 4
    

与筛选相关的字段要求

在 REST API 中,默认为简单字段启用了可筛选性。 可筛选字段会增大索引大小;对于不打算真正在筛选器中使用的字段,请务必设置 "filterable": false。 有关字段定义设置的详细信息,请参阅创建索引

在 .NET SDK 中,可筛选性默认为“关”。 可以通过将相应 SearchField 对象的 IsFilterable 属性设置为 true,使某个字段可筛选。 在下一个示例中,该特性已在一个映射到索引定义的模型类的 Rating 属性中设置。

[SearchField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
public double? Rating { get; set; }

使现有字段可筛选

无法通过修改现有字段来使其可筛选。 为此需要添加新字段或重建索引。 有关重建索引或重新填充字段的详细信息,请参阅如何重建 Azure AI 搜索索引

文本筛选器基础知识

文本筛选器根据筛选器中提供的文本字符串匹配字符串字段:$filter=Category eq 'Resort and Spa'

与全文搜索不同,对于文本筛选器,不会执行词法分析或分词,因此,比较操作仅用于精确匹配。 例如,假设字段 f 包含“sunny day”,则 $filter=f eq 'sunny' 与条件不匹配,但 $filter=f eq 'sunny day' 匹配。

文本字符串区分大小写,这意味着文本筛选器默认区分大小写。 例如,$filter=f eq 'Sunny day' 将无法查找到“sunny day”。 但是,可使用规范化程序使其筛选不区分大小写。

基于文本进行筛选的方法

方法 说明 何时使用
search.in 根据字符串分隔列表匹配字段的函数。 建议用于安全筛选器,以及其中的许多原始文本值需要与某个字符串字段匹配的任何筛选器。 search.in 函数旨在提高速度,相比于显式使用 eqor 将字段与每个字符串进行比较,其速度要快得多。
search.ismatch 用于在同一个筛选表达式中将全文搜索操作与严格的布尔筛选操作混合使用的函数。 想要在一个请求中使用多种搜索-筛选组合时,请使用 search.ismatch(或其等效的评分函数 search.ismatchscoring)。 还可以使用该函数来构建 contains 筛选器,以根据较大字符串中的部分字符串进行筛选。
$filter=field operator string 由字段、运算符和值组成的用户定义的表达式。 想要在字符串字段与字符串值之间查找完全匹配项时,请使用此函数。

数字筛选器基础知识

在全文搜索的上下文中,数字字段不可搜索 (not searchable)。 只有字符串支持全文搜索。 例如,如果输入 99.99 作为搜索词,不会返回价格为 $99.99 的项, 而只会看到在文档字符串字段中包含数字 99 的项。 因此,如果使用了数字数据,则假设条件是要在范围、分面、组等筛选器中使用这些数据。

如果数字字段(价格、大小、SKU、ID)已标记为 retrievable,则包含这些字段的文档会在搜索结果中提供这些值。 此处的要点是,全文搜索本身不适用于数字字段类型。

后续步骤

首先,尝试在门户中使用“搜索浏览器”来提交包含 $filter 参数的查询。real-estate-sample 索引粘贴到搜索栏后,该索引会针对以下筛选的查询提供有趣的结果:

# Geo-filter returning documents within 5 kilometers of Redmond, Washington state
# Use $count=true to get a number of hits returned by the query
# Use $select to trim results, showing values for named fields only
# Use search=* for an empty query string. The filter is the sole input

search=*&$count=true&$select=description,city,postCode&$filter=geo.distance(location,geography'POINT(-122.121513 47.673988)') le 5

# Numeric filters use comparison like greater than (gt), less than (lt), not equal (ne)
# Include "and" to filter on multiple fields (baths and bed)
# Full text search is on John Leclerc, matching on John or Leclerc

search=John Leclerc&$count=true&$select=source,city,postCode,baths,beds&$filter=baths gt 3 and beds gt 4

# Text filters can also use comparison operators
# Wrap text in single or double quotes and use the correct case
# Full text search is on John Leclerc, matching on John or Leclerc

search=John Leclerc&$count=true&$select=source,city,postCode,baths,beds&$filter=city gt 'Seattle'

若要学习更多示例,请参阅 OData 筛选表达式语法 > 示例

另请参阅