如何获得solr结果中的facet范围?

假设我在Solr中有一个名为price的字段,我将该字段刻面。 我希望将facets作为值的范围(例如:0-100,100-500,500-1000等)。 怎么做?

我可以预先指定范围,但我也想知道是否可以根据文档中的值自动计算范围(比如5个值)?

要回答第一个问题,可以使用通用构面查询支持来获取构面范围。 这是一个例子:

http://localhost:8983/solr/select?q=video&rows=0&facet=true&facet.query=price:[*+TO+500]&facet.query=price:[500+TO+*] 

至于你的第二个问题(自动建议方面范围),这还没有实现。 有人认为,这种查询最好在您的应用程序上实现,而不是让Solr“猜测”最佳方面范围。

以下是关于该主题的一些讨论:

我已经研究了如何计算产品价格范围的合理动态方面。 该解决方案涉及一些文档的预处理和一些查询结果的后处理,但它只需要一个查询到Solr,甚至应该在旧版本的Solr上工作,如1.4。

提交前汇总价格

首先,在提交文档之前,将价格四舍五入到最近的“精确圆面边界”并将其存储在“rounded_price”字段中。 用户喜欢他们的方面看起来像“250-500”而不是“247-483”,并且四舍五入也意味着你可以获得数百个价格方面而不是数百万个。 通过一些努力,可以将以下代码推广到任何价格范围内:

  public static decimal RoundPrice(decimal price) { if (price < 25) return Math.Ceiling(price); else if (price < 100) return Math.Ceiling(price / 5) * 5; else if (price < 250) return Math.Ceiling(price / 10) * 10; else if (price < 1000) return Math.Ceiling(price / 25) * 25; else if (price < 2500) return Math.Ceiling(price / 100) * 100; else if (price < 10000) return Math.Ceiling(price / 250) * 250; else if (price < 25000) return Math.Ceiling(price / 1000) * 1000; else if (price < 100000) return Math.Ceiling(price / 2500) * 2500; else return Math.Ceiling(price / 5000) * 5000; } 

允许的价格为1,2,3,......,24,25,30,35,......,95,100,110,......,240,250,275,300,325,......,975,1000等。

了解所有方面的价格

其次,在提交查询时,请求按价格排序的舍入价格的所有方面: facet.field=rounded_price 。 由于四舍五入,你最多可以获得几百个方面。

将相邻小平面组合成更大的小平面

第三,在得到结果后,用户只想看到3到7个方面,而不是数百个方面。 因此,将相邻小平面组合成几个大小平面(称为“分段”),试图在每个分段中获得大致相同数量的文档。 以下相当复杂的代码执行此操作,返回适合执行范围查询的(开始,结束,计数)元组。 如果价格被四舍五入到最近的边界,则返回的计数将是正确的:

  public static List> CombinePriceFacets(int nSegments, ICollection> prices) { var ranges = new List>(); int productCount = prices.Sum(p => p.Value); int productsRemaining = productCount; if (nSegments < 2) return ranges; int segmentSize = productCount / nSegments; string start = "*"; string end = "0"; int count = 0; int totalCount = 0; int segmentIdx = 1; foreach (KeyValuePair price in prices) { end = price.Key; count += price.Value; totalCount += price.Value; productsRemaining -= price.Value; if (totalCount >= segmentSize * segmentIdx) { ranges.Add(new Tuple(start, end, count)); start = end; count = 0; segmentIdx += 1; } if (segmentIdx == nSegments) { ranges.Add(new Tuple(start, "*", count + productsRemaining)); break; } } return ranges; } 

按选定方面筛选结果

第四,假设(“250”,“500”,38)是结果段之一。 如果用户选择“$ 250到$ 500”作为filter,只需执行过滤查询fq=price:[250 TO 500]

可能有一个更好的Solr特定的答案,但我直接使用Lucene,因为你没有得到太大的牵引力,我会采取刺。 在那里,我将创建一个填充Filter ,其中FilteredQuery包装原始Query 。 然后我会为感兴趣的领域获得FieldCache 。 枚举filter的bitset中的命中,并为每次命中,从字段高速缓存中获取字段的值,并将其添加到SortedSet。 当你获得所有的命中时,将集合的大小除以你想要的范围数量(根据用户界面的人数,五到七个是一个很好的数字),而不是单值约束,你的方面将是是一个范围查询,具有每个子集的下限和上限。

我建议为少量值使用一些特殊情况逻辑; 很明显,如果你只有四个不同的值,那么尝试从它们中进行5个范围的改进是没有意义的。 低于某个阈值(比如3 *您理想的范围数),您只需显示正面而不是范围。