1

我使用的术语“子文档”与存储在集合属性中的对象松散相关。鉴于这两个类:

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<Bar> Bars { get; set; }
}

public class Bar
{
    public string Name { get; set; }
    public string Description { get; set; }
    public string SomeString { get; set; }
    public int SomeInt { get; set; }
}

我想查询名称或描述属性中包含“玫瑰”一词的酒吧。请注意,Bars 存储在 Foo 中。

这是一个双重问题:

  1. 可以对 Foo 类型的集合使用查询以返回 Bars(“子文档”)吗?我想收集名称中有“玫瑰”的酒吧,应该跳过其他酒吧。我不希望返回 Foos(聚合根)。
  2. 如果是这样,如何通过全文搜索来做到这一点?

关于#1,我知道在 MongoDB 中这样的事情是不可能的,我要么必须单独存储 Foo 和 Bar,要么查询 Foos,其中任何 Bars 的名称中有“玫瑰”,然后在客户端上做一些事情. 但是 RavenDB 有 Live Projections / TransformResults,所以我认为这可能是可能的。

4

1 回答 1

2

您可以使用索引将每个 Bar 的副本存储在字段存储中,所以是的 - 它可以完成。但是您应该确保您了解这样做的影响。

通常,当您从 raven 查询时,索引仅用于确定哪些文档被发回。文档本身不是来自索引,而是来自文档存储。文档存储有 ACID 保证——这意味着无论索引的状态如何,您都将始终获得文档的最新副本。如果您从索引条目或索引字段存储中进行投影,那么您返回的值与索引本身一样陈旧。

假设您不断更新条形图,并且在索引赶上您上次更新之前进行搜索。您可以取回包含旧数据的 Bar。因此,您需要在结果中权衡数据的潜在陈旧性,可能使用其中一种WaitForNonStaleResultsAsOf...自定义项 - 如果您有大量写入操作,这将减慢搜索结果的返回速度。

public class Foos_BarsByName
    : AbstractIndexCreationTask<Foo, Foos_BarsByName.Result>
{
    public class Result
    {
        public string Name { get; set; }
        public Bar Bar { get; set; }
    }

    public Foos_BarsByName()
    {
        Map = foos => from foo in foos
                      from bar in foo.Bars
                      select new
                      {
                          bar.Name,
                          Bar = bar
                      };

        Index(x => x.Name, FieldIndexing.Analyzed);
        Index(x => x.Bar, FieldIndexing.No);
        Store(x => x.Bar, FieldStorage.Yes);
    }
}

var results = session.Query<Foos_BarsByName.Result, Foos_BarsByName>()
                     .Customize(x => x.WaitForNonStaleResultsAsOfNow())
                     .Search(x => x.Name, "roses")
                     .Select(x => x.Bar);

另一种处理方法可能是让所有 Foos 都回来,然后在客户端拉出您感兴趣的 Bars。至少,一切都来自文档存储:

public class Foos_BarsByName
    : AbstractIndexCreationTask<Foo, Foos_BarsByName.Result>
{
    public class Result
    {
        public string Name { get; set; }
    }

    public Foos_BarsByName()
    {
        Map = foos => from foo in foos
                      from bar in foo.Bars
                      select new
                      {
                          bar.Name
                      };

        Index(x => x.Name, FieldIndexing.Analyzed);
    }
}

var results = session.Query<Foos_BarsByName.Result, Foos_BarsByName>()
                     .Search(x => x.Name, "roses")
                     .As<Foo>()
                     .AsEnumerable()
                     .SelectMany(x => x.Bars)
                     .Where(x => x.Name.IndexOf("roses",
                                     StringComparison.CurrentCultureIgnoreCase)
                                     != -1)

.AsEnumerable()将强制执行 linq-to-raven 查询,使后面的一切都发生在客户端的 linq-to-objects 中。

当然,如果您正在执行比使用 c# 字符串函数表达的更高级的搜索,那么您将无法采用第二种方法。

于 2012-12-14T17:01:14.233 回答