在 RavenDB 中通过多个值查询子集合

发布于 2024-11-30 06:26:06 字数 2034 浏览 0 评论 0原文

我正在使用 RavenDB build 371,并且有以下模型:

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

class ProductSpec {
 public string Name { get; set; }
 public string Value { get; set; }
}

我希望能够查询具有一组规格的产品。按单个规格查询时:

session.Query<Product>()
 .Where(product => product.Specs.Any(spec => spec.Name == "Color" && spec.Value == "Red"))
 .ToList();

返回预期结果,但是添加附加规格谓词时:

session.Query<Product>()
 .Where(product => product.Specs.Any(spec => spec.Name == "Color" && spec.Value == "Red"))
 .Where(product => product.Specs.Any(spec => spec.Name == "Country" && spec.Value == "US"))
 .ToList();

即使第一个查询返回的结果包含规格名称“Country”和规格值“US”的产品,也不会返回任何结果。使用 LuceneQuery 方法时会观察到相同的结果。这似乎与 此讨论但是我无法实施建议的解决方案。具体来说,创建建议的索引后,我不知道如何查询它。

RavenDB 如何支持这种类型的查询?

编辑

我仍然无法查询复合类型集合上的多个值。相反,我更改了模型,使规格/值组合成为一个连接字符串,从而使规格集合成为字符串数组。这可以通过多个值进行查询:

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

作为参考,原始模型和查询在使用 MongoDB 及其 多键索引功能。 MongoDB 的一个非常令人惊讶的问题是 count() 操作索引查询速度很慢。这种类型的查询对于分页至关重要,尽管可以缓存计数,但我想要一个开箱即用的解决方案。此外,我的另一项要求是能够聚合任意产品集合的规格组(例如,获取给定类别中产品的所有规格/值组合的集合)。在 MongoDB 中,这可以使用 MapReduce 功能来实现,但是 MapReduce 操作的结果是静态的,当源数据发生变化时必须手动更新,而 RavenDB 在后台自动更新 MapReduce 索引。因此,尽管在 RavenDB 中声明 MapReduce 索引在 IMO 中比在 MongoDB 中更麻烦,但自动后台更新远远超过了缺点。我将查看 CouchDB 因为它们的视图也会自动更新,尽管看起来它们是按需更新的,而不是自动在后台运行,不确定这是否会成为问题。

I'm using RavenDB build 371 and I have the following model:

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

class ProductSpec {
 public string Name { get; set; }
 public string Value { get; set; }
}

I would like to be able to query for products which have a set of specs. When querying by a single spec:

session.Query<Product>()
 .Where(product => product.Specs.Any(spec => spec.Name == "Color" && spec.Value == "Red"))
 .ToList();

The expected results are returned, however when an additional spec predicate is added:

session.Query<Product>()
 .Where(product => product.Specs.Any(spec => spec.Name == "Color" && spec.Value == "Red"))
 .Where(product => product.Specs.Any(spec => spec.Name == "Country" && spec.Value == "US"))
 .ToList();

no results are returned even though the results returned by the first query contain products with spec name "Country" and spec value "US". The same outcome is observed when using the LuceneQuery method. This seems to be a similar issue to this discussion however I was unable to implement to suggested solution. Specifically, after creating the suggested index, I don't know how to query it.

How can I support this type of query in RavenDB?

EDIT

I still can't query on multiple values on a collection of compound types. Instead, I changed the model so that a spec/value combination is a concatenated string such that the specs collection is an array of strings. This can be queried by multiple values:

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

For reference, the original model and query works when using MongoDB with their multikeys index feature. The very surprising problem with MongoDB is that the count() operation is slow for index queries. This type of query is essential for pagination and although count can be cached I would like a solution which provides this out of the box. Also, one other requirement I have is the ability to aggregate spec groups for arbitrary collections of products (for example, to get a collection of all spec/value combinations for products in a given category). In MongoDB this can be achieved using their MapReduce functionality, however the results of a MapReduce operation are static and must be manually updated when the source data changes whereas RavenDB updates MapReduce indexes automatically in the background. So, even though declaring MapReduce indexes in RavenDB is more cumbersome than it is in MongoDB IMO, the automatic background updating outweighs the drawbacks by a long shot. I will be looking at CouchDB as their views are also updated automatically, though it appears they are updated on demand, not automatically in the background, not sure if this will be an issue.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无尽的现实 2024-12-07 06:26:06

我尝试过不同的事情,但也无法使其发挥作用。您尝试执行的特定查询由 RavenDB(版本 426)解析为以下 Lucene 查询:

“{(Name:Color AND Value:Red) AND (Name:Country AND Value:US)}”,这解释了为什么您会得到没有结果。

在谷歌搜索这个主题后,我发现了这篇文章: Lucene 查询语法

答案中建议了不同的解决方法。希望这会有所帮助。不过我自己也很好奇,如果这真的不可能的话。

I have tried different things, and could not make it work either. The specific query you are trying to execute is resolved to this Lucene query by RavenDB (in version 426):

"{(Name:Color AND Value:Red) AND (Name:Country AND Value:US)}" which explains why you get no result.

After googling on the subject, I found this post: Lucene Query Syntax

Different workarounds are suggested among the answers. Hope this will help. Im rather curious myself though, if this really isn't possible.

鸩远一方 2024-12-07 06:26:06

根据 build 717,您可以使用 Matt Warren 完成的新 .Intersect() 功能来执行此操作。看看这里:http://issues.hibernatingrhinos.com/issue/RavenDB-51

As per build 717 you can do this using the new .Intersect() feature that has been done by Matt Warren. Take a look here: http://issues.hibernatingrhinos.com/issue/RavenDB-51

浅语花开 2024-12-07 06:26:06

我对模型进行了一些更改,并且能够使用 AbstractIndexCreationTask 中的 Project 方法获得所需的结果。这是(简化的)数据模型:

public class Product
{
    public string Id { get; set; }
    public int CategoryId { get; set; }
    public int TotalSold { get; set; }
    public Dictionary<string, string> Specs { get; set; }
}

这是索引定义:

public class Products_ByCategoryIdAndSpecs_SortByTotalSold : AbstractIndexCreationTask<Product>
{
    public Products_ByCategoryIdAndSpecs_SortByTotalSold()
    {
        this.Map = products => from product in products
                               select new
                               {
                                   product.CategoryId,
                                   _ = Project(product.Specs, spec => new Field("Spec_" + spec.Key, spec.Value, Field.Store.NO, Field.Index.ANALYZED)),
                                   product.TotalSold
                               };
    }
}

然后我可以像这样查询:

    var results = session.Advanced.LuceneQuery<Product, Products_ByCategoryIdAndSpecs_SortByTotalSold>()
        .WhereEquals("CategoryId", 15920)
        .AndAlso().WhereEquals("Spec_Class", "3A")
        .AndAlso().WhereEquals("Spec_Finish", "Plain")
        .OrderBy("-TotalSold")
        .ToList(); 

这将返回类别“15920”中的产品,其“Class”规格值为“3A”和“Finish”规格“Plain”的价值按销售总量降序排列。

关键是使用 Project 方法,该方法基本上在 Lucene 文档中为每个规范名称-值对创建字段。

I've changed the model a bit and was able to achieve the desired result using the Project method in AbstractIndexCreationTask. This is the (simplified) data model:

public class Product
{
    public string Id { get; set; }
    public int CategoryId { get; set; }
    public int TotalSold { get; set; }
    public Dictionary<string, string> Specs { get; set; }
}

This is the index definition:

public class Products_ByCategoryIdAndSpecs_SortByTotalSold : AbstractIndexCreationTask<Product>
{
    public Products_ByCategoryIdAndSpecs_SortByTotalSold()
    {
        this.Map = products => from product in products
                               select new
                               {
                                   product.CategoryId,
                                   _ = Project(product.Specs, spec => new Field("Spec_" + spec.Key, spec.Value, Field.Store.NO, Field.Index.ANALYZED)),
                                   product.TotalSold
                               };
    }
}

Then I can query like so:

    var results = session.Advanced.LuceneQuery<Product, Products_ByCategoryIdAndSpecs_SortByTotalSold>()
        .WhereEquals("CategoryId", 15920)
        .AndAlso().WhereEquals("Spec_Class", "3A")
        .AndAlso().WhereEquals("Spec_Finish", "Plain")
        .OrderBy("-TotalSold")
        .ToList(); 

This will return the products in category "15920" which have a "Class" spec value of "3A" and a "Finish" spec value of "Plain" sorted in descending order by the total units sold.

The key was using the Project method which basically creates fields in the Lucene document for each spec name-value pair.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文