对 SharePoint 中的搜索结果进行排序

概念性概述主题

在 SharePoint 中,使用查询对象模型,按排名、托管属性值、公式表达式或随机顺序,以编程方式对搜索结果进行排序。

可以通过四种方式在 SharePoint 中对搜索结果进行排序:

本文重点介绍了如何以编程方式对搜索结果进行排序。 若要了解如何使用 SharePoint 查询规则对搜索结果进行排序,请参阅下列文章:

如何在查询请求中指定排序

使用 Query 对象模型时,可以通过 KeywordQuery 类的 SortList 属性提供排序规范来选择排序条件。 SortList 属性的类型为 SortCollection,用于 Sort 对象集合。

Sort 对象定义对搜索结果进行排序的方法;它包含要对 (属性) 上的搜索结果进行排序的值,以及要对结果 (方向) 排序的方向。 Direction 的类型为 SortDirection(),可取值为 ascending 或 descending。

如果在 SortList 中有多个值,则会根据值出现的顺序执行排序。 也就是说,每个 Sort 对象表示一种排序顺序级别。 任何后续级别都不会更改前面级别区分的结果排序,但可能会影响与前面级别使用相同排序值的结果的内部排序。

除查询对象模型外,SharePoint 还提供搜索 REST 服务,可用于在客户端或移动应用中查询搜索索引。 搜索 REST 服务支持 HTTP POST 和 HTTP GET 请求。 有关如何为这些请求构建 URI 的详细信息,请参阅使用搜索 REST 服务进行查询

按排名对搜索结果进行排序

默认情况下,搜索结果按相关性级别进行排序。 也就是说,SharePoint 会将最相关的结果排在搜索结果集的首位。 如果按排名排序,始终按降序对结果进行排序。 但是,可以使用 SortDirection () 将排序顺序更改为升序。

还可以通过下列两种方式之一,影响查询字符串中的排名计算:

  • 通过使用 关键字查询语言 (KQL) 语法参考FAST 查询语言 (FQL) 语法参考 中的 XRANK 运算符。 如果满足特定的查询条件,您可以使用 XRANK 应用有条件的排名提升。

  • 通过为动态排名选择相关性权重。 使用 FQL 时,您可以为每个 STRING 运算符指定单个相关性权重。

按托管属性值对搜索结果进行排序

可以指定按一个或多个托管属性值进行搜索结果排序。 也就是说,SharePoint 会根据与查询匹配的所有结果执行排序。

可以根据文本属性和数值属性进行排序。 对于文本属性,排序依据为标准文本字符串排序。 相比之下,对于数值属性(包括类型为 DateTime 的托管属性),排序依据为数值。

示例

以下示例说明如何使用 Size 托管属性对搜索结果进行排序。


using (var context = new ClientContext("http://localhost"))
{
    var query = new KeywordQuery(context)
    {
        QueryText = "home"
    };
    query.SortList.Add("Size", SortDirection.Descending);

    var executor = new SearchExecutor(context);
    var results = executor.ExecuteQuery(query);

    context.ExecuteQuery();

    foreach (var result in results.Value[0].ResultRows)
    { 
        Console.WriteLine(result["Title"] + " Size:" + result["Size"]);
    }
}

或者,您可以使用搜索 REST API,通过在以下调用中使用 Size 属性来对搜索结果进行排序。


http://localhost/_api/search/query?querytext='home'&sortlist='size:descending'

按公式表达式对搜索结果进行排序

您可以基于使用数学公式创建排序值的排序规范指定搜索结果排序。

按公式排序功能是搜索结果的单级和多级排序功能的扩展。 此功能使您可以将公式而不是托管属性指定为排序条件。

通过使用按公式排序功能,您可以对查询结果中每个项目的一个或多个托管属性的执行执行数学运算。

下面是可以通过使用公式指定搜索结果排序来实施的示例:

  • 使用 K-近邻法算法对文档进行分类。

  • 使用欧几里得距离或曼哈顿距离计算地理距离。

  • 使用首选值,根据指定托管属性值距离首选值的距离对文档进行排序。

按公式排序功能不包括对统计动态排名参数的控制,例如术语频率和邻近度。

公式从左到右求值,并且使用标准数学运算符优先级。 也就是说,首先计算函数和附加说明的分组,然后执行乘法和除法运算,最后执行加法和减法运算。

重要

公式的最终结果必须在 32 位带符号整数的值范围中。 否则,排序可能不正确。

在查询中指定排序公式

必须在查询请求的排序规范中指定排序公式,而不是托管属性。

排序规范具有以下格式: [formula:<sort-formula>]

在 格式中, <sort-formula> 是排序公式表达式。

注意

方括号属于排序规范语法。

默认的排序方向为降序。 您也可以使用按升序值排序的公式,例如,如果公式指定一个地理距离。

以下代码示例说明如何使用查询对象模型,指定按使用升序排序顺序的公式进行排序。

using (var context = new ClientContext("http://localhost"))
{
    var query = new KeywordQuery(context)
    {
        QueryText = "home"
    };
    query.SortList.Add("[formula:abs(2000-size)]", SortDirection.Ascending);

    var executor = new SearchExecutor(context);
    var results = executor.ExecuteQuery(query);

    context.ExecuteQuery();

    foreach (var result in results.Value[0].ResultRows)
    { 
        Console.WriteLine(result["Title"]);
    }
}

或者,您可以使用搜索 REST API,通过在以下调用中使用 Size 属性来对搜索结果进行排序。


http://localhost/_api/search/query?querytext='home'&amp;sortlist='[formula:abs(2000-size)]:ascending'

在排序公式中使用托管属性

可以对类型为 IntegerDecimalDatetime() 的托管属性的值应用排序公式。 必须为搜索架构中的指定托管属性启用排序。

对于 类型为 Decimal 的更多托管属性,该值将乘以 10^ (十进制数字) 在公式计算中使用。

对于类型为 Datetime () ] (/previous-versions/office/developer/sharepoint-2010/ms500214 (v%3Doffice.14) ) 的托管属性,该值将转换为自 BC 29000 年 1 月 1 日起的 100 纳秒数,然后再用于公式计算。 一年有 366 天。

排序公式表达式

表 1 列出了您可以用于排序公式表达式的函数。 表达式不能包含空格。

表 1. 排序公式表达式的函数

函数 说明
+
指定加法。
-
指定减法。
*
指定乘法。
/
指定除法。
注意:默认情况下,除数为零会导致异常抛出,进而导致查询返回错误。 使用 errtolast 运算符,可以避免生成查询错误,而是将失败项放在结果集末尾。
rank
表示某个项目的动态排名的特殊关键字。
示例: abs(rank-100) 将使用与排名值 100 之间的距离作为排序条件。
[0-9.]+
指定可以指定为整数或双精度值的数字。
示例:503、3.14、5.4352262
[a-z0-9]+]
指定任何未被识别为函数名称的字符顺序将作为托管属性名称。 您必须为搜索架构中的指定托管属性启用排序。
示例:您必须在启用排序的前提下定义名为 height 的托管属性。 这将使您可以使用"height"作为公式中的一个表达式。 公式将使用 height 托管属性的值。
( and )
用于分组计算,以确保优先级正确。
示例:4*(3+2)
sqrt(n)
n 的平方根。
exp(n)
相当于 pow(2.71828182846,n) 的指数函数。
log(n)
n 的自然对数。
abs(n)
n 的绝对值。
ceil(n)
n 的上限。 也就是说,如果 n 不是整数,则向上舍入到下一个整数。 如果 n 是整数,便会使用 n
floor(n)
n 的下限。 也就是说,如果 n 不是整数,请向下舍入到下一个整数。 如果 n 是整数,便会使用 n
round(n)
n 到最接近的整数的舍入。 亦称为“银行进位法”或“向偶数进位”。
sin(n)
n 弧度的正弦值。
cos(n)
n 弧度的余弦值。
tan(n)
n 弧度的正切值。
asin(n)
n 的反正弦值(以弧度为单位)。
acos(n)
n 的反正弦值(以弧度为单位)。
atan(n)
n 的反正切值(以弧度为单位)。
pow(x,y)
将 x 的值提升到 y 的幂。
注意y 的值必须是实数。
atan2(y,x)
正向 x 轴和指定的笛卡儿坐标 (x,y) 之间的角度的两参数反正切(以弧度为单位)。
bucket(b,n1,n2,…)
可用于为表达式的指定值分布区范围提供离散值的运算符。
表达式 b 可以是一个托管属性或任何其他公式表达式。 参数 n1、n2、... 表示数值阈值。 可以指定任意数目的桶阈值。
注意:必须按以下顺序 n1 < n2 < n3 < ...n1 >= 0排列参数 n1、n2、n3... 输入表达式 b 的给定值会向下舍入为给定的最近数字阈值。 如果低于指定阈值下限,生成的值为零。
errtolast(x)
可用于控制如何处理公式异常的运算符; x 可以是任何公式表达式。 如果此公式表达式的计算导致结果集中某个项目出现数学异常,例如除以零,这些项目将出现在排序列表的末尾,不论指定的排序方向是什么。

按公式排序的性能特征

使用排序公式表示将对结果集中的所有匹配项应用公式计算。 这意味着查询性能影响将取决于与查询匹配的项数。

具有很多运算符的长公式需要的处理时间比短公式更多。

将按公式排序用于地理距离

可以使用按公式排序功能以应用基于距离的分级。 这将需要您包含表示每个项的纬度和经度的托管属性。

例如,您可以使用下列标准公式之一:

  • 曼哈顿距离

  • 欧几里得距离(请参见示例 2)

  • 半正矢公式

重要

使用 DecimalFloat 类型的托管属性来表示纬度值和经度值。

示例

下列示例说明了如何使用查询对象模型指定排序公式。

示例 1.height 托管属性最接近 20 的项目放在结果列表顶部。


using (var context = new ClientContext("http://localhost"))
{
    var query = new KeywordQuery(context)
    {
        QueryText = "home"
    };
    query.SortList.Add("[formula:abs(20-height)]", SortDirection.Ascending);

    var executor = new SearchExecutor(context);
    var results = executor.ExecuteQuery(query);

    context.ExecuteQuery();

    foreach (var result in results.Value[0].ResultRows)
    { 
        Console.WriteLine(result["Title"]);
    }
}

或者,您也可以通过以下调用,使用搜索 REST API 将 height 托管属性最接近 20 的项目放在结果列表顶部。


http://localhost/_api/search/query?querytext='home'&amp;sortlist='[formula:abs(20-height)]:ascending

示例 2. 例如,根据托管属性 纬度经度高度中提供的位置信息,按给定位置 (用户的位置) 按 true 3-D 欧氏距离排序。 以下公式提供三维欧氏距离,假定基准位置为 50/100/200 (纬度/经度/高度) 。

sqrt(pow(50-latitude,2)+pow(100-longitude,2)+pow(200-height,2))

如果要应用基于距离的排序 (不将距离与公式) 中的其他参数组合在一起,则可以删除 sqrt() 该组件,因为它不会更改排序顺序;但它可以提高查询性能。

using (var context = new ClientContext("http://localhost"))
{
    var query = new KeywordQuery(context)
    {
        QueryText = "home"
    };
    query.SortList.Add("[formula:pow(50-latitude,2)+pow(100-longitude,2)+pow(200-height,2)]", SortDirection.Ascending);

    var executor = new SearchExecutor(context);
    var results = executor.ExecuteQuery(query);

    context.ExecuteQuery();

    foreach (var result in results.Value[0].ResultRows)
    { 
        Console.WriteLine(result["Title"]);
    }
}

示例 3. 将大小的值舍入到存储桶,将值向下舍入到下列值之一:0、5、15、50、100;最大的值优先排序。


using (var context = new ClientContext("http://localhost"))
{
    var query = new KeywordQuery(context)
    {
        QueryText = "home"
    };
    query.SortList.Add("[formula:bucket(size,5,15,50,100)]", SortDirection.Ascending);

    var executor = new SearchExecutor(context);
    var results = executor.ExecuteQuery(query);

    context.ExecuteQuery();

    foreach (var result in results.Value[0].ResultRows)
    { 
        Console.WriteLine(result["Title"]);
    }
}

按随机顺序对搜索结果进行排序

您可以应用查询结果的随机排序,或者将随机组件添加到结果排序中。

随机排序规范采用以下格式: [random:seed=<seed>:hashfield=<managed property>]

注意

方括号属于排序规范语法。

表 2 介绍了随机排序规范参数。

表 2. 随机排序规范的参数

参数 说明 必需
Seed
随机值生成的种子。
种子值将输入到一个函数中以生成随机数字。 此随机数用于最终排序。仅使用 种子 选项将提供随机排序的查询结果集。 同一查询(如果使用同一种子)的排序顺序在更新索引后可能会发生变化。

Hashfield
用作随机生成的哈希值的托管属性。 可以使用此参数来确保同一查询(如果使用同一种子)的排序顺序在更新索引后不会变化。
托管属性的类型必须为 Integer ,并且必须是 Sortable () 。 可以使用随机值或唯一值填充此托管属性(例如,使用项处理阶段填充的序列号)。

通过为相同查询提供相同的种子,项目将按相同的顺序表示。 这使您能够在分页浏览搜索结果时保持相同的随机顺序。 如果想要在两次查询之间意外发生索引更新时保持相同的随机顺序,请使用 hashfield 参数。

示例

下列示例说明了如何使用查询对象模型指定随机排序。

示例 1. 按随机顺序对整个结果集进行排序。


using (var context = new ClientContext("http://localhost"))
{
    var query = new KeywordQuery(context)
    {
        QueryText = "home"
    };
    query.SortList.Add("[random:seed=5432]", SortDirection.Ascending);

    var executor = new SearchExecutor(context);
    var results = executor.ExecuteQuery(query);

    context.ExecuteQuery();

    foreach (var result in results.Value[0].ResultRows)
    { 
        Console.WriteLine(result["Title"]);
    }
}

或者,您可以通过以下调用,使用搜索 REST API 按随机顺序对整个结果集进行排序。


http://localhost/_api/search/query?querytext='home'&amp;sortlist='[random:seed=5432]:ascending

示例 2. 按随机顺序对整个结果集进行排序。 对使用相同种子的相同查询保持相同的随机顺序,即使发生索引切换也是如此。 名为 hashvalue 的自定义托管属性必须在搜搜架构中可用,并且对所有索引项目填充随机或连续的数字值。

using (var context = new ClientContext("http://localhost"))
{
    var query = new KeywordQuery(context)
    {
        QueryText = "home"
    };
    query.SortList.Add("[random:seed=6543:hashfield=hashvalue]", SortDirection.Ascending);

    var executor = new SearchExecutor(context);
    var results = executor.ExecuteQuery(query);

    context.ExecuteQuery();

    foreach (var result in results.Value[0].ResultRows)
    { 
        Console.WriteLine(result["Title"]);
    }
}

另请参阅