如何在Sitecore中配置Lucene以仅索引主数据库上项目的最新版本?

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

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

 $(id) _search_content_US    master /sitecore/content/usa home home content    

我像这样查询索引(我从这个答案中使用了techphoria414的SortableIndexSearchContext : 如何使用新的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的属性,该属性是SearchResult的集合,表示所有其他项目版本。

这是我的问题:

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

例如:

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

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

顺便说一句,为什么Lucene还要为旧版本的商品编制索引呢? 当然,这对于在您的网站上搜索内容毫无意义,因为旧版本不可见?

您可以实现覆盖以下内容的自定义搜寻器:

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

这样可以确保只有最新版本的项目才会进入您的索引,因此它将成为拉出所述索引的唯一项目

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

Sitecore 7中 ,字段_latestversion被添加到索引中,包含最新版本的“1”(其他版本具有空值)。

如果您让Lucene在您的Web数据库而不是Master中进行搜索,则它应该只索引上一个发布的版本。

 web 

尽管由他们提供的解决方案,通过使用调整后的排序机制,是一种有趣的方法,但是当两个版本的Lucene结果得分趋于不同时,它不能提供完美的解决方案。 例如,在得分为0.7的v1和得分为0.5的v2之外,他的解决方案仍将返回该项目的第一个版本。 (至少在我的测试中。)

经过一些挖掘,最明显的解决方案显然是实现自己的Sitecore.Pipelines.Search.SearchSystemIndex并使用那个而不是默认的。 如果使用ILSpy或类似方法对该代码进行反编译,您将在Process方法的底部注意到以下内容:

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

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

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

虽然我还没有弄清楚确切的答案(阻止Lucene索引主数据库上的旧版本)我已经提出了一个可接受的解决办法……

当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看到的第一个匹配将是最新版本而不仅仅是随机版本:

 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) 

这种方法解决了我的问题,但如果有人能真正找到如何只索引最新版本,请回答!