版本详情:我正在使用 Sitecore 7.5 build 141003,使用 Solr v4.7 作为搜索引擎/索引服务器。我还使用标准 Sitecore Solr 提供程序,没有自定义索引器。
目标目标:我使用 Sitecore ContentSearch LINQ 和 PredicateBuilder 来编译一些灵活的嵌套查询。目前,我需要在特定的“根项目”中搜索,同时排除名称中带有“文件夹”的模板,还排除路径中带有“/testing”的项目。在某些情况下,“根项”可能不止一项,路径也可能包含(目前只是“/testing”)。在这些情况下,想法是使用 PredicateBuilder 构建一个外部“AND”谓词与内部“ OR 用于多个“根项目”和路径排除。
Problem:目前,我正在处理有关这些谓词/条件的嵌套顺序和优先级的问题。我一直在测试几种方法和组合,但我不断遇到的问题是 !TemplateName.Contains 和 Item["_fullpath"].Contains 优先于 Paths.Contains,最终每次都会产生 0 个结果。
我正在使用 Search.log 检查查询输出,并且我一直在手动测试 Solr 管理员,对其运行查询以比较结果。下面,您将找到我使用 Sitecore Linq 尝试过的组合示例,以及它们为 Solr 生成的查询。
原始代码示例:
使用根项目列表进行原始测试
// sometimes will be 1, sometimes will be multiple
var rootItems = new List<ID> { pathID }; // simplified to 1 item for now
var query = context.GetQueryable<SearchResultItem>();
var folderFilter = PredicateBuilder.True<SearchResultItem>().And(i => !i.TemplateName.Contains("folder") && !i["_fullpath"].Contains("/testing"));
var pathFilter = PredicateBuilder.False<SearchResultItem>();
pathFilter = rootItems.Aggregate(pathFilter, (current, id) => current.Or(i => i.Paths.Contains(id)));
folderFilter = folderFilter.And(pathFilter);
query.Filter(folderFilter).GetResults();
查询输出:(-_templatename:(*folder*) AND -_fullpath:(*/testing*)) AND _path:(730c169987a44ca7a9ce294ad7151f13)
正如您在上面的输出中看到的,两个“不包含”过滤器周围有一组内部括号,该括号优先于路径过滤器。当我在 Solr 管理中运行这个精确查询时,它返回 0 个结果。但是,如果我删除内部括号,使其成为单个“AND”集,它将返回预期的结果。
我使用 PredicateBuilder 的不同组合和方法进一步测试了这一点,每种组合都会产生相同的查询。我什至尝试向我的主查询对象添加两个单独的过滤器(“query.Filter(pred1).Filter(pred2)”),它会产生相同的输出。
其他代码示例:
Alt. 1- 直接将“Paths.Contains”添加到文件夹过滤器
var query = context.GetQueryable<SearchResultItem>();
var folderFilter = PredicateBuilder.True<SearchResultItem>().And(i => !i.TemplateName.Contains("folder") && !i["_fullpath"].Contains("/testing"));
folderFilter = folderFilter.And(i => i.Paths.Contains(pathID));
query.Filter(folderFilter).GetResults();
查询输出:(-_templatename:(*folder*) AND -_fullpath:(*/testing*)) AND _path:(730c169987a44ca7a9ce294ad7151f13)
Alt 2- 两个谓词连接到第一个
var query = context.GetQueryable<SearchResultItem>();
var folderFilter = PredicateBuilder.True<SearchResultItem>().And(i => !i.TemplateName.Contains("folder") && !i["_fullpath"].Contains("/testing"));
var pathFilter = PredicateBuilder.False<SearchResultItem>().Or(i => i.Paths.Contains(pathID));
folderFilter = folderFilter.And(pathFilter);
query.Filter(folderFilter).GetResults();
查询输出:(-_templatename:(*folder*) AND -_fullpath:(*/testing*)) AND _path:(730c169987a44ca7a9ce294ad7151f13)
Alt 3- 两个“内部”谓词,一个用于“Not”,一个用于连接到外部谓词的“Paths”
var query = context.GetQueryable<SearchResultItem>();
var folderFilter = PredicateBuilder.True<SearchResultItem>().And(i => !i.TemplateName.Contains("folder") && !i["_fullpath"].Contains("/testing"));
var pathFilter = PredicateBuilder.False<SearchResultItem>().Or(i => i.Paths.Contains(pathID));
var finalPredicate = PredicateBuilder.True<SearchResultItem>().And(folderFilter).And(pathFilter);
query.Filter(finalPredicate).GetResults();
查询输出:(-_templatename:(*folder*) AND -_fullpath:(*/testing*)) AND _path:(730c169987a44ca7a9ce294ad7151f13)
结论:最终,我正在寻找一种方法来控制这些嵌套查询/条件的优先级,或者如何构建它们以将路径放在前面,然后将“Not”过滤器放在后面。如前所述,在某些情况下,我们将拥有多个“根项目”和多个路径排除,我需要查询更像这样的内容:
(-_templatename:(*folder*) AND -_fullpath:(*/testing*) AND
(_路径:(730c169987a44ca7a9ce294ad7151f13)或
_路径:(12c1aa7f60fa4e8d9f0a983bbbb40d8b)))
OR
(-_templatename:(*folder*) AND -_fullpath:(*/testing*) AND
(_路径:(730c169987a44ca7a9ce294ad7151f13)))
当我直接在 Solr 管理中运行这些查询时,这两个查询都会返回我期望/需要的结果。但是,我似乎无法想出使用 Sitecore ContentSearch Linq 以这种方式输出查询的方法或操作顺序。
还有其他人有我如何实现这一目标的经验吗?根据建议,如果我可以将其与 IQueryable 结合起来以调用“GetFacets”和“GetResults”,我也愿意在不使用 Sitecore Linq 的情况下组装这部分查询。
Update:我没有包括我所做的所有修订,因为这样可能会杀了我多久。也就是说,我确实在原始示例(顶部)的基础上尝试了另一种细微的变化,其结果与其他示例类似:
var folderFilter = PredicateBuilder.True<SearchResultItem>().And(i => !i.TemplateName.Contains("folder")).And(i => !i["_fullpath"].Contains("/testing"));
var rootItems = new List<ID> { pathID, path2 };
// or paths separately
var pathFilter = PredicateBuilder.False<SearchResultItem>();
pathFilter = rootItems.Aggregate(pathFilter, (current, id) => current.Or(i => i.Paths.Contains(id)));
var finalPredicate = folderFilter.And(pathFilter);
var query = context.GetQueryable<SearchResultItem>();
query.Filter(finalPredicate).GetResults();
查询输出:((-_templatename:(*folder*) AND -_fullpath:(*/testing*)) AND (_path:(730c169987a44ca7a9ce294ad7151f13) OR _path:(12c1aa7f60fa4e8d9f0a983bbbb40d8b)))
导致问题的仍然是“_templatename”和“_fullpath”条件周围的内括号。
Thanks.