Nosql 查询产品目录RavenDB store以获取任意产品集合上的规范聚合

Nosql 查询产品目录RavenDB store以获取任意产品集合上的规范聚合,nosql,ravendb,faceted-search,Nosql,Ravendb,Faceted Search,这是上述项目的延续 我有以下型号: class Product { public string Id { get; set; } public string[] Specs { get; set; } public int CategoryId { get; set; } } “Specs”数组存储由特殊字符连接的产品规格名称-值对。例如,如果产品颜色为蓝色,则规格字符串将为“Color~ blue”。以这种方式表示规范允许查询具有由查询指定的多个规范值的产品。我想支持两个主要问题

这是上述项目的延续

我有以下型号:

class Product {
  public string Id { get; set; }
  public string[] Specs { get; set; }
  public int CategoryId { get; set; }
}
“Specs”数组存储由特殊字符连接的产品规格名称-值对。例如,如果产品颜色为蓝色,则规格字符串将为“Color~ blue”。以这种方式表示规范允许查询具有由查询指定的多个规范值的产品。我想支持两个主要问题:

  • 获取给定类别中的所有产品
  • 获取给定类别中具有一组指定规格的所有产品
  • 这对RavenDB很有效。但是,除了满足给定查询的产品之外,我还想返回一个结果集,其中包含查询指定的产品集的所有规范名称-值对。等级库名称-值对应按等级库的名称和值分组,并包含具有给定等级库名称-值对的产品计数。对于查询#1,我创建了以下map reduce索引:

    class CategorySpecGroups {
        public int CategoryId { get; set; }
        public string Spec { get; set; }
        public int Count { get; set; }
    }
    
    
    public class SpecGroups_ByCategoryId : AbstractIndexCreationTask<Product, CategorySpecGroups>
    {
        public SpecGroups_ByCategoryId()
        {
            this.Map = products => from product in products
                                   where product.Specs != null
                                   from spec in product.Specs
                                   select new
                                   {
                                       CategoryId = product.CategoryId,
                                       Spec = spec,
                                       Count = 1
                                   };
    
            this.Reduce = results => from result in results
                                     group result by new { result.CategoryId, result.Spec } into g
                                     select new
                                     {
                                         CategoryId = g.Key.CategoryId,
                                         Spec = g.Key.Spec,
                                         Count = g.Sum(x => x.Count)
                                     };
        }
    }
    
    class categorityspecgroup{
    public int CategoryId{get;set;}
    公共字符串规范{get;set;}
    公共整数计数{get;set;}
    }
    公共类SpecGroups\u ByCategoryId:AbstractIndexCreationTask
    {
    公共SpecGroups_ByCategoryId()
    {
    this.Map=products=>来自产品中的产品
    其中product.Specs!=null
    来自product.Specs中的spec
    选择新的
    {
    CategoryId=product.CategoryId,
    Spec=Spec,
    计数=1
    };
    this.Reduce=results=>from result in results
    按新的{result.CategoryId,result.Spec}将结果分组到g中
    选择新的
    {
    CategoryId=g.Key.CategoryId,
    Spec=g.Key.Spec,
    Count=g.Sum(x=>x.Count)
    };
    }
    }
    
    然后,我可以查询这个索引并获得给定类别中的所有规范名称-值对。我遇到的问题是获得相同的结果集,但对于一个同时按类别和一组规范名称-值对进行过滤的查询。使用SQL时,通过对一组按类别和规格筛选的产品进行分组,可以获得此结果集。一般来说,这种类型的查询成本很高,但在按类别和规格进行筛选时,产品集通常很小,但不足以容纳一个页面—它们最多可以包含1000个产品。作为参考,MongoDB支持一种方法,可用于实现相同的结果集。这将在服务器端执行临时分组,并且性能是可接受的

    如何使用RavenDB获得这种类型的结果集

    一个可能的解决方案是获取查询的所有产品并在内存中执行分组,另一个选项是如上所述创建一个mapreduce索引,尽管这样做的挑战是推断可以为给定类别进行的所有可能的规范选择,此外,这种类型的索引可能会在大小上爆炸

    举个例子,看一看。用户可以通过选择属性来过滤其选择。选择一个属性时,它会缩小产品的选择范围,并在新产品集中显示属性。这种类型的交互通常称为

    编辑

    同时,我将尝试使用一种解决方案,因为它们支持开箱即用的分面搜索

    编辑2

    RavenDB似乎也支持(这当然是有道理的,索引是由Lucene像Solr一样存储的)。我将对此进行探索并发布更新

    编辑3


    RavenDB faceted搜索功能按预期工作。我为每个类别ID存储一个facet设置文档,用于计算给定类别内查询的facet。我现在面临的问题是性能。对于包含4500个不同类别的500k产品的集合,会产生4500个方面设置文档,按类别id进行的查询在同时查询方面时大约需要16秒,在不查询方面时大约需要0.05秒。测试的特定类别包含约6k个产品、23个不同的方面和2k个不同的方面名称范围组合。在查看中的代码之后,facets查询将针对每个方面名称值组合生成Lucene查询以获得计数,同时针对每个方面名称生成一个查询以获得术语。该实现的一个问题是,它将检索给定facet名称的所有不同术语,而不考虑查询,这在大多数情况下将显著减少facet的术语数量,从而减少Lucene查询的数量。在这里提高性能的一种方法是为每个方面设置文档存储一个MapReduce计算结果集(如上所示),然后在进一步按方面过滤时查询该结果集以获得所有不同的术语。但是,总体性能可能仍然太慢。

    我已经使用实现了此功能,但是我做了一些更改以支持启发式优化。启发是,在我的例子中,面只显示在叶类别中。这是一个合理的约束,因为根类别和内部类别之间的导航可以由搜索或子类别列表驱动

    现在给定约束条件,我为每个叶类别存储一个FacetSetup文档,Id类似于“facets/category_123”。存储刻面设置文档时,我可以访问刻面名称以及刻面值(或范围)