SharePoint 中的查询优化
了解如何在处理搜索查询和结果时,以编程方式使用 SharePoint 查询精简功能。
查询精简功能可用于为最终用户提供与查询相关的精简选项。 借助这些功能,最终用户可以使用针对结果计算出的精简数据,向下钻取搜索结果。 精简数据是由索引组件计算得出,依据是针对搜索查询的所有结果聚合的托管属性统计信息。
通常,查询细化用于与索引项(如项目中出现的创建日期、作者或文件类型)关联的元数据。 通过使用细化选项,你可以优化查询以仅显示特定时段内创建的项,或仅显示特定文件类型的项。
在查询对象模型中使用精简条件
查询细化所涉及的两类查询:
- 可以通过向最终用户的查询添加精简条件规范,请求在搜索结果中返回 一组精简条件 。 细化规格是 Refiners 属性的输入。 此查询针对搜索索引运行。 搜索结果由相关结果和细化数据组成。
- 你可以通过创建精简的查询使用细化数据深入了解搜索结果。 将 RefinementFilters 属性添加到查询中,以便最终搜索结果既满足最终用户的原始查询文本的要求,也满足精简数据中所选优化选项的要求。
以下各部分详细说明这些步骤,并提供代码示例。
使用精简条件规格将精简条件添加到最终用户的查询中
可以使用 KeywordQuery 类的 Refiners 属性指定请求的查询精简条件。 请使用以下语法指定请求的查询精简条件:
<refiner>[,<refiner>]*
每个 refiner
都具有以下格式:
<refiner-name>[(parameter=value[,parameter=value]*)]?
其中:
<refiner-name>
是与精简条件关联的托管属性的名称。 在搜索架构中必须将此托管属性设置为 Refinable 或 Sortable 。parameter=value
对的可选列表指定已命名精简条件的非默认配置值。 如果精简条件的参数未在括号中列出,搜索架构配置会提供默认设置。 表 1 列出了parameter=value
对可能的值。
注意
指定精简条件时,至少必须指定托管属性 refiner-name
。
示例
Refiners = "FileType"
或者你还可以使用高级语法调整精简条件设置:
Refiners = "FileType,Write(discretize=manual/2013-01-01/2013-08-22/2013-09-15/2013-09-21/2013-09-22),companies"
表 1:精简条件参数列表
参数 | 说明 |
---|---|
deephits |
替换作为精简条件计算基数的默认点击量。 如果生成精简条件,则将计算查询的所有结果。 正常情况下,使用此参数将提升搜索性能。 语法 deephits=<integer value> 示例 price(deephits=1000) 注意:此限制适用于每个索引分区。 由于跨搜索分区进行聚合,因此计算出的实际命中数会大于此值。 |
discretize |
指定数字精简条件的自定义间隔(精简量化)。 语法 discretize=manual/<threshold>/<threshold>[/<threshold>]* 示例 write(discretize=manual/2013-01-01/2013-08-22/2013-09-15/2013-09-21/2013-09-22) <threshold> 属性指定每个精简量化的阈值。 在指定的第一个阈值下面有一个针对所有内容的时间间隔,每个连续阈值间有一个时间间隔,最后一个阈值上面也有一个针对所有内容的时间间隔。 对于类型 DateTime 的精简条件,按照以下 ISO 8601 兼容的格式之一指定阈值:
|
sort |
定义量化在字符串精简条件内的排序方式。 语法 sort=<property>/<direction> 这些属性执行以下操作:
sort=name/ascending 默认值:frequency/descending |
filter |
定义 String 类型精简条件中的量化在返回到客户端之前是如何进行筛选的。 语法 filter=<bins>/<freq>/<prefix>[<levels>] 这些属性执行以下操作:
|
cutoff |
限制必须针对深入字符串精简条件转移和处理的数据。 你可以仅将精简条件配置为返回相关度最高的值(箱)。 注意:此截止筛选在每个索引分区内执行。 这不同于仅执行结果端筛选的 filter 参数。 可以结合使用这两个参数。 语法 cutoff=<frequency>/<minbins>/<maxbins> 这些属性执行以下操作:
|
示例:添加精简条件
以下 CSOM 示例说明如何以编程方式请求三个精简条件: FileType、 Write 和 Companies。 Write 代表项目最后修改日期,并使用高级语法返回固定大小日期/时间箱。
using (var context = new ClientContext("http://<serverName>/<siteCollectionPath>"))
{
var query = new KeywordQuery(context)
{
QueryText = "home",
Refiners = "FileType,Write(discretize=manual/2013-01-01/2013-08-22/2013-09-
15/2013-09-21/2013-09-22),companies"
};
var executor = new SearchExecutor(context);
var results = executor.ExecuteQuery(query);
context.ExecuteQuery();
ResultTable relevantResultsTable = results.Value[0];
ResultTable refinerResultsTable = results.Value[1];
Console.WriteLine(refinerResultsTable.RowCount + " refinement options:");
foreach (var refinementOption in refinerResultsTable.ResultRows)
{
Console.WriteLine("RefinerName: '{0}' RefinementName: '{1}'
RefinementValue: '{2}' RefinementToken: '{3}' RefinementCount: '{4}'",
refinementOption["RefinerName"],
refinementOption["RefinementName"],
refinementOption["RefinementValue"],
refinementOption["RefinementToken"],
refinementOption["RefinementCount"]
);
}
}
了解搜索结果中的精简数据
如果已在查询中为托管属性启用查询优化,则查询结果包含细化数据(拆分为精简箱)。此数据位于 ResultTableCollection 内的 RefinementResults 表 ( RefinementResults ) 中。 一个优化箱表示托管属性的特定值或值范围。 RefinementResults 表每个精简箱包含一行,并包含表 2 中指定的列。
表 2:为细化箱返回的数据
参数 | 说明 |
---|---|
RefinerName | 查询精简条件的名称。 |
RefinementName | 表示细化箱的字符串。 如果要在搜索结果页面上向用户呈现精简选项,则通常使用此字符串通。 |
RefinementValue | 表示细化的特定于实现的格式化字符串。 为调试返回此数据,且客户端通常不需要此数据。 |
RefinementToken | 表示在执行精简的查询时使用 RefinerName 的细化箱。 |
RefinementCount | 此细化箱的结果计数。 此数据表示搜索结果中的项目(包括副本)数量,该值为针对此细化箱给定托管属性的值。 |
示例:精简数据
下面的表 3 包含两行精简数据。 第一行是索引项的精简数据,其中文件类型为 HTML。 第二行是索引项的精简数据,其中最后修改时间为 2013/09/21 到 2013/09/22。
表 3:精简数据的格式和内容
RefinerName | RefinementName | RefinementValue | RefinementToken | RefinementCount |
---|---|---|---|---|
FileType | Html | Html | "????68746d6c" | 50553 |
写入 | 从 2013-09-21T00:00:00Z 到 2013-09-22T00:00:00Z | 从 2013-09-21T00:00:00Z 到 2013-09-22T00:00:00Z | range(2013-09-21T00:00:00Z, 2013-09-22T00:00:00Z) | 37 |
创建精简的查询
搜索结果表示字符串值或值范围形式的精简选项。 每个字符串值或数值范围称为细化箱,每个细化箱具有一个关联的 RefinementToken 值。 精简选项与 RefinerName 值提供的托管属性关联。
连接 RefinementToken 和 RefinerName 值以创建 refinement filter 字符串。 此字符串表示一个筛选器,该筛选器可用于将搜索结果项限制为仅包含这样的项目:项目中的托管属性具有细化箱中的值。 简言之:
refinement filter = <RefinerName>:<RefinementToken>
可以通过将精简筛选器添加到 KeywordQuery 类的 RefinementFilters 属性,为优化查询提供一个或多个精简筛选器。 通过多个精简筛选器,你可以提供对搜索结果的深入了解,并在多值属性中应用细化。 例如,你可以将查询优化到具有两个作者(每个作者由细化箱表示)的项目,排除仅包含其中一个作者的项目。
示例 1:创建 HTML 文件类型的精简查询
下面的 CSOM 示例展示了如何以编程方式执行精简,将搜索结果限制为 HTML 文件类型。 如示例:精简数据中所述,与此精简选项相关的精简数据将 RefinerName 设置为 Filetype,将 RefinementToken 设置为“????68746d6c”。
using (var context = new ClientContext("http://<serverName>/<siteCollectionPath>"))
{
var query = new KeywordQuery(context)
{
QueryText = "home"
};
query.RefinementFilters.Add("FileType:\\"????68746d6c\\"");
var executor = new SearchExecutor(context);
var results = executor.ExecuteQuery(query);
context.ExecuteQuery();
ResultTable relevantResultsTable = results.Value[0];
var resultCount = 1;
foreach (var relevantResult in relevantResultsTable.ResultRows)
{
Console.WriteLine("Relevant result number {0} has file type {1}.",
resultCount, relevantResult["FileType"]);
resultCount++;
}
}
示例 2:使用以前获取的精简数据创建精简查询
以下 CSOM 示例显示如何使用精简条件规格运行查询,以创建后续用于执行细化的精简数据。 此示例模拟最终用户选择第一个精简选项的过程。
using (var context = new ClientContext("http://<serverName>/<siteCollectionPath>"))
{
// Step 1: Run the query with refiner spec to provide refinement data in search result
var query = new KeywordQuery(context)
{
QueryText = "home",
Refiners = "FileType,Write(discretize=manual/2013-01-01/2013-08-22/2013-09-15/2013-09-21/2013-09-22),companies"
};
Console.WriteLine("Run query '{0}' with refiner spec '{1}'.", query.QueryText, query.Refiners);
var executor = new SearchExecutor(context);
var results = executor.ExecuteQuery(query);
context.ExecuteQuery();
// The query has been run and we can now look at the refinement data, to view the
// refinement options
ResultTable relevantResultsTable = results.Value[0];
ResultTable refinerResultsTable = results.Value[1];
Console.WriteLine("Got back {0} refinement options in the result:",
refinerResultsTable.RowCount);
foreach (var refinementOption in refinerResultsTable.ResultRows)
{
Console.WriteLine("RefinerName: '{0}' RefinementName: '{1}'
RefinementValue: '{2}' RefinementToken: '{3}' RefinementCount: '{4}'",
refinementOption["RefinerName"],
refinementOption["RefinementName"],
refinementOption["RefinementValue"],
refinementOption["RefinementToken"],
refinementOption["RefinementCount"]
);
}
// Step 2: Run the refined query with refinement filter to drill down into
// the search results. This example uses the first refinement option in the refinement
// data, if available. This simulates an end user selecting this refinement option.
var refinementOptionArray = refinerResultsTable.ResultRows.ToArray();
if (refinementOptionArray.Length > 0)
{
var firstRefinementOption = refinementOptionArray[6];
// Construct the refinement filter by concatenation
var refinementFilter = firstRefinementOption["RefinerName"] + ":" +
firstRefinementOption["RefinementToken"];
var refinedQuery = new KeywordQuery(context)
{
QueryText = query.QueryText
};
refinedQuery.RefinementFilters.Add(refinementFilter);
refinedQuery.SelectProperties.Add("FileType");
refinedQuery.SelectProperties.Add("Write");
refinedQuery.SelectProperties.Add("Companies");
Console.WriteLine("Run query '{0}' with refinement filter '{1}'",
refinedQuery.QueryText, refinementFilter);
var refinedResults = executor.ExecuteQuery(refinedQuery);
context.ExecuteQuery();
ResultTable refinedRelevantResultsTable = refinedResults.Value[0];
var resultCount = 1;
foreach (var relevantResult in refinedRelevantResultsTable.ResultRows)
{
Console.WriteLine("Relevant result number {0} has FileType='{1}',
Write='{2}', Companies='{3}'",
resultCount,
relevantResult["FileType"],
relevantResult["Write"],
relevantResult["Companies"]
);
resultCount++;
}
}
}