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

时间:2011-08-17 20:30:31

标签: nosql ravendb

我正在使用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方法时会观察到相同的结果。这似乎与this discussion类似,但我无法实施建议的解决方案。具体来说,在创建建议的索引后,我不知道如何查询它。

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

修改

我仍然无法查询复合类型集合上的多个值。相反,我更改了模型,以便spec / value组合是一个连接的字符串,这样specs集合就是一个字符串数组。这可以通过多个值来查询:

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

作为参考,使用MongoDB及其multikeys索引功能时,原始模型和查询有效。 MongoDB的一个非常令人惊讶的问题是count()操作是slow for index queries。这种类型的查询对于分页是必不可少的,虽然可以缓存计数,但我想要一个解决方案,它提供了开箱即用的功能。此外,我的另一个要求是能够为任意产品集合聚合规范组(例如,获取给定类别中产品的所有规范/值组合的集合)。在MongoDB中,这可以使用他们的MapReduce功能来实现,但是MapReduce操作的结果是静态的,并且必须在源数据更改时手动更新,而RavenDB在后台自动更新MapReduce索引。因此,即使在RavenDB中声明MapReduce索引比在MongoDB IMO中更加繁琐,自动后台更新也远远超过了长镜头的缺点。我将查看CouchDB,因为他们的观点也会自动更新,但它们似乎是按需更新,而不是在后台自动更新,不确定这是否会成为问题。

3 个答案:

答案 0 :(得分:3)

我尝试了不同的东西,也无法使其发挥作用。您尝试执行的特定查询由RavenDB(版本426)解析为此Lucene查询:

“{(姓名:颜色和价值:红色)和(姓名:国家和价值:美国)}”这解释了为什么没有结果。

在Google上搜索主题后,我发现了这篇文章:Lucene Query Syntax

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

答案 1 :(得分:3)

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

答案 2 :(得分:1)

我已经稍微更改了模型,并且能够使用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文档中创建字段。