【问题标题】:How do you configure Lucene in Sitecore to only index the latest version of an item on the master db?如何在 Sitecore 中配置 Lucene 以仅索引主数据库上项目的最新版本?
【发布时间】:2012-11-22 00:24:33
【问题描述】:

我认识到这是网络数据库上的一个有争议的问题,所以这个问题适用于主数据库......

我在 Sitecore 6.4.1 中设置了一个自定义索引,如下所示:

<index id="search_content_US" type="Sitecore.Search.Index, Sitecore.Kernel">
    <param desc="name">$(id)</param>
    <param desc="folder">_search_content_US</param>
    <Analyzer ref="search/analyzer" />
    <locations hint="list:AddCrawler">
        <search_content_home type="Sitecore.Search.Crawlers.DatabaseCrawler, Sitecore.Kernel">
            <Database>master</Database>
            <Root>/sitecore/content/usa home</Root>
            <Tags>home content</Tags>
        </search_content_home>
    </locations>
</index>

我这样查询索引(我正在使用 techphoria414 的 SortableIndexSearchContext 来自这个答案:How to sort/filter using the new Sitecore.Search API):

private SearchHits GetSearchResults(SortableIndexSearchContext searchContext, string searchTerm)
    {
        CombinedQuery query = new CombinedQuery();
        query.Add(new FullTextQuery(searchTerm), QueryOccurance.Must);
        return searchContext.Search(query, Sort.RELEVANCE);
    }

...

SearchHits hits = GetSearchResults(searchContext, searchTerm);

hits 是我的索引中搜索命中的集合。当我遍历 hits 时,我可以看到 Sitecore 中有许多相同项目的重复项,每个版本的项目 1 个。

然后我执行以下操作以获得SearchResultCollection

SearchResultCollection results = hits.FetchResults(0, hits.Length);

这会将所有重复项组合成一个 SearchResult 对象。此对象表示特定项目的 1 个版本,并有一个名为 SubResults 的属性,它是代表所有其他项目版本的 SearchResults 的集合。

这是我的问题:

SearchResult 所代表的项目版本不是项目的当前发布版本!它似乎是一个随机选择的版本(无论哪种搜索方法在索引中首先出现)。不过,最新版本包含在 SubResults 集合中。

例如:

SearchResult
 |
 |- Version 8 // main result
 ...
 |- SubResults
      |
      |- Version 9 // latest version
      |- Version 3
      |- Version 5
      ... // all versions in random order

如何防止在主数据库上发生这种情况?通过阻止 Lucene 索引项目的旧版本,或者通过对结果集进行一些操作以从 SubResults 获取最新版本?

顺便说一句,为什么 Lucene 还要费心索引旧版本的项目呢?由于旧版本不可见,这对于在您的网站上搜索内容肯定没有意义吗?

【问题讨论】:

    标签: c# search lucene indexing sitecore


    【解决方案1】:

    如果您让 Lucene 在您的 Web 数据库中搜索而不是在 Master 中搜索,它应该只索引最后发布的版本。

    <Database>web</Database>
    

    【讨论】:

    • 谢谢,@Martijn,我猜这对我们的实时站点来说是个好消息,但是您知道如何让它在我们的主数据库上工作吗?我们需要本地的功能来进行测试和我们的内容编辑器。我们有一个 CM 和一个 CD 服务器。
    • 嗨@theyetiman,现在我没有开箱即用的解决方案,我应该深入研究它。我会看看我是否有时间......
    • 只是想补充一点,web 数据库只有项目的最新版本(只要您不直接在该数据库中工作)。发布不会对项目进行版本化,只需应用最新的可发布版本
    【解决方案2】:

    虽然我还没有想出确切的答案(阻止 Lucene 在 ma​​ster db 上索引旧版本),但我想出了一个可以接受的解决方法...

    当 Lucene 从索引返回其结果时,每个 hit 都有一个名为 "_id" 的字段,其格式如下(同一项目的 3 个版本,其中最后一个数字是版本):

    "CCB75380-4E9A-4921-99EC-65E532E330FF%en%1"
    "CCB75380-4E9A-4921-99EC-65E532E330FF%en%2"
    "CCB75380-4E9A-4921-99EC-65E532E330FF%en%3"
    ...
    

    我目前按Sort.RELEVANCE 排序,这是默认设置。如果我们在索引中只有一个项目的版本,这很好,但有几个几乎相同的版本,它们都有相同的相关性分数,Lucene 只是按任何顺序将它们搅出。 Sitecore 然后获取项目版本的第一个实例(即使它是旧的)。

    解决方案是指定一个辅助排序字段。在searchContext.Search()方法中,可以传递一个自定义的Sort对象。

    searchContext.Search(query, new Sort(...));
    

    通过首先按 Lucene 内置的 Sort.RELEVANCE 排序,然后按索引中的 id 字段(降序)排序,我可以确保 Sitecore 看到的第一个 hit 将是最新版本,而不仅仅是随机的:

    searchContext.Search(query, new Sort
                                (
                                    new SortField[2] 
                                    {
                                        SortField.FIELD_SCORE, // equivalent to Sort.RELEVANCE
                                        new SortField("_id",SortField.STRING, true) // sort by _id, descending
                                    }
                                )
    );
    

    SortField参数如下:

    SortField(string fieldName, int type, bool reverse)
    

    这种方法已经解决了我的问题,但是如果有人真的可以找出如何只索引最新版本,请回答!

    【讨论】:

      【解决方案3】:

      虽然yetiman 提供的解决方案通过使用调整的排序机制是一种有趣的方法,但当两个版本的Lucene 结果分数往往不同时,它并不能提供完美的解决方案。例如。在分数为 0.7 的 v1 和分数为 0.5 的 v2 中,他的解决方案仍将返回项目的第一个版本。 (至少在我的测试中。)

      经过更多挖掘,最明显的解决方案显然在于实现您自己的Sitecore.Pipelines.Search.SearchSystemIndex 并使用该Sitecore.Pipelines.Search.SearchSystemIndex 而不是默认值。如果您使用 ILSpy 或类似工具反编译该代码,您会注意到 Process 方法底部的以下内容:

      foreach (SearchResult current in searchHits.FetchResults(0, searchHits.Length)){
        // ...
      }
      

      每个这样的SearchResult 实际上都是分组依据,其中从 Lucene 返回的第一个结果(因此得分最高的结果)是主要结果。通过每个实例的Subresults 属性可以访问同一项目的其他版本(以及其他语言)的命中;或null(如果没有)。

      根据您的要求,您可以调整课程的这一部分以满足您的需求。

      【讨论】:

      • 谢谢瑞恩。这看起来很有趣,但我认为@Andrew Burgess 的答案可能更容易实现。
      【解决方案4】:

      您可以实现一个覆盖以下内容的自定义爬虫:

      public class IndexCrawler : DatabaseCrawler
      {
          protected override void IndexVersion(Item item, Item latestVersion, Sitecore.Search.IndexUpdateContext context)
          {
              if (item.Versions.Count > 0 && item.Version.Number != latestVersion.Version.Number)
                  return;
      
              base.IndexVersion(item, latestVersion, context);
          }
      }
      

      这确保只有最新版本的项目进入您的索引,因此将是唯一从所述索引中拉出的项目

      当然,您需要更新配置文件以设置正确的索引类型

      【讨论】:

      • 谢谢@Andrew - 这看起来就是这样。我还没有机会实现它,但是当我这样做时,如果它成功了,我会将其标记为答案。
      • 想在这里见到你,伯吉斯先生。这个答案只是帮助了我:)
      【解决方案5】:

      Sitecore 7 中,向索引添加了一个字段 _latestversion,其中包含最新版本的“1”(其他版本的值为空)。

      【讨论】:

      • 这是个好消息!遗憾的是我们还没有使用 Sitecore 7,但知道它非常有用。谢谢。
      【解决方案6】:

      我最终从上述答案中找到了一个替代解决方案,

      从架构上讲,我认为这个问题的理想解决方案是使用更高级别的自定义代码过滤掉旧版本的结果,而不是完全从主数据库索引中删除它们。您不想管理 sitecore 旨在解决手头问题的方式。

      使用以下谓词过滤掉旧版本并仅检索最新版本

      predicate.And(item=>item[Sitecore.ContentSearch.BuiltinFields.LatestVersion].Equals("1"));
      

      希望这对某人有所帮助!

      【讨论】:

        猜你喜欢
        • 2016-03-17
        • 2012-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-13
        • 1970-01-01
        • 2010-09-12
        • 1970-01-01
        相关资源
        最近更新 更多