如何在solr结果中获得小平面范围?提交前四舍五入价格全面了解四舍五入的价格将相邻的小平面合并为更大的刻面按所选分面筛选结果

2022-09-03 12:28:14

假设我在Solr中有一个名为价格的字段,并且我有该字段的分面。我想将分面作为值的范围(例如:0-100,100-500,500-1000等)。怎么办?

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


答案 1

若要回答第一个问题,可以使用通用分面查询支持获取分面范围。下面是一个示例:

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

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

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


答案 2

我已经弄清楚了如何计算产品价格范围的合理动态方面。该解决方案涉及对文档的一些预处理和对查询结果的一些后处理,但它只需要对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<Tuple<string, string, int>> CombinePriceFacets(int nSegments, ICollection<KeyValuePair<string, int>> prices)
    {
        var ranges = new List<Tuple<string, string, int>>();
        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<string, int> price in prices)
        {
            end = price.Key;
            count += price.Value;
            totalCount += price.Value;
            productsRemaining -= price.Value;
            if (totalCount >= segmentSize * segmentIdx)
            {
                ranges.Add(new Tuple<string, string, int>(start, end, count));
                start = end;
                count = 0;
                segmentIdx += 1;
            }
            if (segmentIdx == nSegments)
            {
                ranges.Add(new Tuple<string, string, int>(start, "*", count + productsRemaining));
                break;
            }
        }
        return ranges;
    }

按所选分面筛选结果

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


推荐