Sitecore Search Predicate Builder具有增强功能的多个关键字搜索无法正常工作 [英] Sitecore Search Predicate Builder multiple keyword search with boosting not working as desired

查看:90
本文介绍了Sitecore Search Predicate Builder具有增强功能的多个关键字搜索无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有具有以下字段的站点核心页面/lucene文档:

I have sitecore pages / lucene documents with the following fields:

  • 标题
  • 文件名
  • 内容
  • 文件内容

我正在搜索这些文件,并且具有以下要求:

I'm creating a search for these and have the following requirements:

  • 应该首先返回在 title 字段中包含整个短语的匹配项.
  • filename 字段中包含整个短语的命中应返回第二个.
  • content 中包含整个短语的命中应返回第三
  • 在文件内容中包含整个短语的命中应返回第四
  • title字段中包含 all 个关键字(任意顺序)的命中应返回第五个
  • filename字段中包含 all 个关键字(任意顺序)的命中应返回第六个
  • content 中包含 all 个关键字(任意顺序)的命中应返回第七个.
  • 文件内容中包含 all 个关键字(任意顺序)的命中应返回第八.
  • Hits containing the whole phrase in the title field should be returned first.
  • Hits containing the whole phrase in the filename field should be returned second.
  • Hits containing the whole phrase in the content should be returned third
  • Hits containing the whole phrase in the file contents should be returned fourth
  • Hits containing all of the keywords (in any order) in the title field should be returned fifth
  • Hits containing all of the keywords (in any order) in the filename field should be returned sixth
  • Hits containing all of the keywords (in any order) in the content should be returned seventh.
  • Hits containing all of the keywords (in any order) in the file contents should be returned eighth.

这就是我所拥有的:

    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 actual phrase part seems to work well. Hits with the full phrase in the title are returned first. However, if I remove a word from the middle of the phrase, no results are returned.

即我有一个标题为英格兰足球队令人恐惧"的页面,但是当我搜索英格兰足球队令人恐惧"时,找不到该页面.

i.e. I have a page with a title "The England football team are dreadful", but when I search with "The football team are dreadful", it doesn't find the page.

注意:页面上可以附加文档,所以我也想增加文件名,但不如页面标题那么高.

Note: pages can have documents attached to them, so I want to boost the filenames too but not as highly as the page title.

推荐答案

我设法将其与以下各项配合使用:

I managed to get this to work with the following:

    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;
    }

显然有很多代码,但是我认为分离谓词对于提高工作效率更有意义.

It's obviously quite a bit more code, but I think separating the predicates makes more sense for boosting to work effectively.

先前代码的主要问题有两个方面:

The main issue with the previous code was two fold:

  1. PredicateBuilder.Or(actualPhrasePredicate.Boost(2f), individualWordsPredicate)似乎不包含谓词Or'd.在结果联接谓词上执行.ToString()时,该表达式不包含individualWordsPredicate
  2. 的任何内容
  3. 修复后,它仍然不起作用,这是因为我在individualWordsPredicate中使用了PredicateBuilder.False<T>().当看表达式时,它基本上是产生(False AND Field.Contains(keyword)),当然,它永远不会评估为true.使用.True<T>()修复此问题.
  1. PredicateBuilder.Or(actualPhrasePredicate.Boost(2f), individualWordsPredicate) doesn't seem to include the predicate being Or'd. When doing a .ToString() on the resulting joined predicate, the expression didn't contain anything for the individualWordsPredicate
  2. After fixing that it still didn't work, and this was because I was using PredicateBuilder.False<T>() for the individualWordsPredicate. When looking at the expression it was basically producing (False AND Field.Contains(keyword)) which of course will never evaluate to true. Using .True<T>() fixed this.

这篇关于Sitecore Search Predicate Builder具有增强功能的多个关键字搜索无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆