我可以使用全文搜索在RavenDB中查询和检索集合属性的成员吗?

时间:2012-12-14 14:16:41

标签: full-text-search nested ravendb

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

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

我想在Name或Description属性中查询名称为“roses”的Bars。请注意,条形图存储在Foo中。

这是一个双重问题:

  1. 可以在Foo类型的集合上使用查询来返回Bars(“子文档”)吗?我想得到一个名字中有“玫瑰”的酒吧集合,其他酒吧应该被跳过。我不希望Foos(聚合根)返回。
  2. 如果是这样,如何使用全文搜索?
  3. 关于#1,我知道MongoDB中不可能有这样的东西,我要么必须单独存储Foo和Bar,要么查询Foos,其中任何一个Bars在名称中都有“玫瑰”,然后对它做一些事情在客户端上。但是RavenDB有Live Projections / TransformResults,所以我认为这也许是可能的。

1 个答案:

答案 0 :(得分:2)

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

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

假设您不断更新Bars,并在索引赶上上次更新之前进行搜索。你可以找回一个有旧数据的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#字符串函数表达更高级的搜索,那么您将无法采用第二种方法。