加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

nosql – 查询产品目录RavenDB存储,以便在任意产品集合上进行规

发布时间:2020-12-13 13:29:44 所属栏目:百科 来源:网络整理
导读:这是 this问题中概述的项目的延续. 我有以下型号: class Product { public string Id { get; set; } public string[] Specs { get; set; } public int CategoryId { get; set; }} “Specs”数组存储由特殊字符连接的产品规范名称值对.例如,如果产品的颜色为
这是 this问题中概述的项目的延续.

我有以下型号:

class Product {
  public string Id { get; set; }
  public string[] Specs { get; set; }
  public int CategoryId { get; set; }
}

“Specs”数组存储由特殊字符连接的产品规范名称值对.例如,如果产品的颜色为蓝色,则spec字符串将为“Color~Blue”.以这种方式表示规范允许查询具有由查询指定的多个规范值的产品.我想支持两个主要查询:

>获取给定类别的所有产品.
>获取具有一组指定规格的给定类别中的所有产品.

这适用于RavenDB.但是,除了满足给定查询的产品之外,我还想返回一个结果集,其中包含查询指定的产品集的所有规范名称 – 值对.规范名称 – 值对应按规范的名称和值进行分组,并包含具有给定规范名称 – 值对的产品计数.对于查询#1,我创建了以下map reduce index:

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

然后,我可以查询此索引并获取给定类别中的所有规范名称 – 值对.我遇到的问题是获得相同的结果集,但是对于一个按类别和一组规范名称 – 值对过滤的查询.使用SQL时,可以通过按类别和规范筛选的一组产品进行分组来获得此结果集.一般来说,这种类型的查询很昂贵,但是当按类别和规格进行过滤时,产品集通常很小,但不足以容纳单个页面 – 它们可能包含多达1000个产品.作为参考,MongoDB支持group方法,可用于实现相同的结果集.这将执行ad hoc分组服务器端,并且性能可以接受.

如何使用RavenDB获取此类结果集?

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

例如,请查看this fastener category page.用户可以通过选择属性来过滤其选择.选择属性后,它会缩小产品选择范围并在新产品集中显示属性.这种类型的交互通常称为faceted search.

编辑

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

编辑2

似乎RavenDB也支持faceted search(当然这是有道理的,Lucene就像Solr一样存储索引).我将探索这个并发布更新.

编辑3

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

解决方法

我已经使用 RavenDB faceted search实现了这个功能,但是我对 FacetedQueryRunner进行了一些更改以支持启发式优化.启发式是,在我的情况下,facet仅显示在叶子类别中.这是一个合理的约束,因为根类别和内部类别之间的导航可以通过搜索或子类别列表来驱动.

现在给定约束我为每个叶子类别存储一个FacetSetup文档,其ID类似于“facets / category_123”.当存储构面设置文档时,我可以访问构面名称以及类别中包含的构面值(或范围).因此,我可以在FacetSetup文档中的每个Facet的Ranges集合中存储所有可用的构面值,但构面模式仍然是FacetMode.Default.

Here are对FacetedQueryRunner的更改.具体而言,优化检查以查看给定构面是否存储范围,在这种情况下,它返回用于搜索的那些值,而不是获取与给定构面相关联的索引中的所有项.在大多数情况下,这将显着减少所需的Lucene搜索次数,因为给定类别中的可用构面值是整个索引中构面值的子集.

可以进行的下一个优化是,如果原始查询仅按类别ID进行过滤,则FacetSetup文档也可以实际存储计数.实现此目的的一种方法是将计数附加到Ranges集合中的每个facet值,然后向FacetSetup文档添加一个布尔值以指示附加计数.现在这个facet查询基本上会返回FacetSetup文档中的值 – 无需查询.

现在考虑的是保持FacetSetup文档是最新的,但无论哪种方式都需要这样做.除此优化之外,还可以使用缓存,我相信Solr采用的方法是分面搜索.

此外,如果FacetSetup文档自动与产品集合同步,那将是很好的,因为它们实际上是对最初按类别ID分组的产品集合的聚合MapReduce操作的结果,然后是构面的名称,然后是值.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读