Sitecore Search Predicate Builder 多关键字搜索,提升功能无法按预期工作
Sitecore Search Predicate Builder multiple keyword search with boosting not working as desired
我有包含以下字段的 sitecore 页面/lucene 文档:
- 标题
- 文件名
- 内容
- 文件内容
我正在为这些内容创建搜索并满足以下要求:
- 在 title 字段中包含整个短语的匹配应首先返回。
- 包含 文件名 字段中整个短语的匹配应返回第二个。
- 在 内容 中包含整个短语的匹配应排在第三位
- 包含 文件内容 中整个短语的匹配项应返回第四个
- 在标题字段中包含所有个关键字(以任何顺序排列)的匹配应返回第五
- 在 文件名字段 中包含 所有 个关键字(以任何顺序排列)的命中应返回第六个
- 包含全部 内容 中的关键字(以任何顺序排列)的命中应返回第七。
- 包含文件内容中所有个关键字(以任何顺序排列)的命中应返回第八。
这是我得到的:
public static Expression<Func<T, bool>> GetSearchTermPredicate<T>(string searchTerm)
where T : ISearchableItem
{
var actualPhrasePredicate = PredicateBuilder.True<T>()
.Or(r => r.Title.Contains(searchTerm).Boost(2f))
.Or(r => r.FileName.Contains(searchTerm).Boost(1.5f))
.Or(r => r.Content.Contains(searchTerm))
.Or(r => r.DocumentContents.Contains(searchTerm));
var individualWordsPredicate = PredicateBuilder.False<T>();
foreach (var term in searchTerm.Split(' '))
{
individualWordsPredicate
= individualWordsPredicate.And(r =>
r.Title.Contains(term).Boost(2f)
|| r.FileName.Contains(term).Boost(1.5f)
|| r.Content.Contains(term)
|| r.DocumentContents.Contains(term));
}
return PredicateBuilder.Or(actualPhrasePredicate.Boost(2f),
individualWordsPredicate);
}
实际的短语部分似乎效果不错。首先返回标题中包含完整短语的匹配项。但是,如果我从短语中间删除一个词,则不会返回任何结果。
即我有一个标题为 "The England football team are dreadful" 的页面,但是当我使用 "The football team are dreadful" 进行搜索时,它找不到该页面。
注意:页面可以附加文档,所以我也想提升文件名,但不要像页面标题那样高。
我设法让它与以下内容一起工作:
public static Expression<Func<T, bool>> GetSearchTermPredicate<T>(string searchTerm)
where T : ISearchableItem
{
var actualPhraseInTitlePredicate = PredicateBuilder.True<T>()
.And(r => r.Title.Contains(searchTerm));
var actualPhraseInFileNamePredicate = PredicateBuilder.True<T>()
.And(r => r.FileName.Contains(searchTerm));
var actualPhraseInContentPredicate = PredicateBuilder.True<T>()
.And(r => r.Content.Contains(searchTerm));
var actualPhraseInDocumentPredicate = PredicateBuilder.True<T>()
.And(r => r.DocumentContents.Contains(searchTerm));
var terms = searchTerm.Split(' ');
var titleContainsAllTermsPredicate = PredicateBuilder.True<T>();
foreach (var term in terms)
titleContainsAllTermsPredicate
= titleContainsAllTermsPredicate.And(r => r.Title.Contains(term).Boost(2f));
var fileNameAllTermsContains = PredicateBuilder.True<T>();
foreach (var term in terms)
fileNameAllTermsContains
= fileNameAllTermsContains.And(r => r.FileName.Contains(term));
var contentContainsAllTermsPredicate = PredicateBuilder.True<T>();
foreach (var term in terms)
contentContainsAllTermsPredicate
= contentContainsAllTermsPredicate.And(r => r.Content.Contains(term));
var documentContainsAllTermsPredicate = PredicateBuilder.True<T>();
foreach (var term in terms)
documentContainsAllTermsPredicate
= documentContainsAllTermsPredicate.And(r => r.DocumentContents.Contains(term));
var predicate = actualPhraseInTitlePredicate.Boost(3f)
.Or(actualPhraseInFileNamePredicate.Boost(2.5f))
.Or(actualPhraseInContentPredicate.Boost(2f))
.Or(actualPhraseInDocumentPredicate.Boost(1.5f))
.Or(titleContainsAllTermsPredicate.Boost(1.2f))
.Or(fileNameAllTermsContains.Boost(1.2f))
.Or(contentContainsAllTermsPredicate)
.Or(documentContainsAllTermsPredicate);
return predicate;
}
显然代码要多一些,但我认为分离谓词对于提升有效工作更有意义。
之前代码的主要问题有两个:
PredicateBuilder.Or(actualPhrasePredicate.Boost(2f), individualWordsPredicate)
似乎不包括被 Or'd 的谓词。在对生成的连接谓词执行 .ToString()
时,表达式不包含 individualWordsPredicate
的任何内容
- 修复后还是不行,这是因为我用的是
PredicateBuilder.False<T>()
作为individualWordsPredicate
。当查看表达式时,它基本上产生 (False AND Field.Contains(keyword))
当然永远不会计算为真。使用 .True<T>()
解决了这个问题。
我有包含以下字段的 sitecore 页面/lucene 文档:
- 标题
- 文件名
- 内容
- 文件内容
我正在为这些内容创建搜索并满足以下要求:
- 在 title 字段中包含整个短语的匹配应首先返回。
- 包含 文件名 字段中整个短语的匹配应返回第二个。
- 在 内容 中包含整个短语的匹配应排在第三位
- 包含 文件内容 中整个短语的匹配项应返回第四个
- 在标题字段中包含所有个关键字(以任何顺序排列)的匹配应返回第五
- 在 文件名字段 中包含 所有 个关键字(以任何顺序排列)的命中应返回第六个
- 包含全部 内容 中的关键字(以任何顺序排列)的命中应返回第七。
- 包含文件内容中所有个关键字(以任何顺序排列)的命中应返回第八。
这是我得到的:
public static Expression<Func<T, bool>> GetSearchTermPredicate<T>(string searchTerm)
where T : ISearchableItem
{
var actualPhrasePredicate = PredicateBuilder.True<T>()
.Or(r => r.Title.Contains(searchTerm).Boost(2f))
.Or(r => r.FileName.Contains(searchTerm).Boost(1.5f))
.Or(r => r.Content.Contains(searchTerm))
.Or(r => r.DocumentContents.Contains(searchTerm));
var individualWordsPredicate = PredicateBuilder.False<T>();
foreach (var term in searchTerm.Split(' '))
{
individualWordsPredicate
= individualWordsPredicate.And(r =>
r.Title.Contains(term).Boost(2f)
|| r.FileName.Contains(term).Boost(1.5f)
|| r.Content.Contains(term)
|| r.DocumentContents.Contains(term));
}
return PredicateBuilder.Or(actualPhrasePredicate.Boost(2f),
individualWordsPredicate);
}
实际的短语部分似乎效果不错。首先返回标题中包含完整短语的匹配项。但是,如果我从短语中间删除一个词,则不会返回任何结果。
即我有一个标题为 "The England football team are dreadful" 的页面,但是当我使用 "The football team are dreadful" 进行搜索时,它找不到该页面。
注意:页面可以附加文档,所以我也想提升文件名,但不要像页面标题那样高。
我设法让它与以下内容一起工作:
public static Expression<Func<T, bool>> GetSearchTermPredicate<T>(string searchTerm)
where T : ISearchableItem
{
var actualPhraseInTitlePredicate = PredicateBuilder.True<T>()
.And(r => r.Title.Contains(searchTerm));
var actualPhraseInFileNamePredicate = PredicateBuilder.True<T>()
.And(r => r.FileName.Contains(searchTerm));
var actualPhraseInContentPredicate = PredicateBuilder.True<T>()
.And(r => r.Content.Contains(searchTerm));
var actualPhraseInDocumentPredicate = PredicateBuilder.True<T>()
.And(r => r.DocumentContents.Contains(searchTerm));
var terms = searchTerm.Split(' ');
var titleContainsAllTermsPredicate = PredicateBuilder.True<T>();
foreach (var term in terms)
titleContainsAllTermsPredicate
= titleContainsAllTermsPredicate.And(r => r.Title.Contains(term).Boost(2f));
var fileNameAllTermsContains = PredicateBuilder.True<T>();
foreach (var term in terms)
fileNameAllTermsContains
= fileNameAllTermsContains.And(r => r.FileName.Contains(term));
var contentContainsAllTermsPredicate = PredicateBuilder.True<T>();
foreach (var term in terms)
contentContainsAllTermsPredicate
= contentContainsAllTermsPredicate.And(r => r.Content.Contains(term));
var documentContainsAllTermsPredicate = PredicateBuilder.True<T>();
foreach (var term in terms)
documentContainsAllTermsPredicate
= documentContainsAllTermsPredicate.And(r => r.DocumentContents.Contains(term));
var predicate = actualPhraseInTitlePredicate.Boost(3f)
.Or(actualPhraseInFileNamePredicate.Boost(2.5f))
.Or(actualPhraseInContentPredicate.Boost(2f))
.Or(actualPhraseInDocumentPredicate.Boost(1.5f))
.Or(titleContainsAllTermsPredicate.Boost(1.2f))
.Or(fileNameAllTermsContains.Boost(1.2f))
.Or(contentContainsAllTermsPredicate)
.Or(documentContainsAllTermsPredicate);
return predicate;
}
显然代码要多一些,但我认为分离谓词对于提升有效工作更有意义。
之前代码的主要问题有两个:
PredicateBuilder.Or(actualPhrasePredicate.Boost(2f), individualWordsPredicate)
似乎不包括被 Or'd 的谓词。在对生成的连接谓词执行.ToString()
时,表达式不包含individualWordsPredicate
的任何内容
- 修复后还是不行,这是因为我用的是
PredicateBuilder.False<T>()
作为individualWordsPredicate
。当查看表达式时,它基本上产生(False AND Field.Contains(keyword))
当然永远不会计算为真。使用.True<T>()
解决了这个问题。