2016-11-16 122 views
1

Indexing Related Documents的示例II中,索引是通过作者按名称和书名构建的。相关实体如下所示:如何在Ravendb中以相反方向索引相关文档

public class Book { 
    public string Id { get; set; } 
    public string Name { get; set; } 
} 

public class Author { 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public IList<string> BookIds { get; set; } 
} 

I.e.只有Author拥有关于关系的信息。该信息用于构建所述索引。

但是,我将如何构建书籍的作者索引(假设一本书可能有多个作者)?

编辑:

书/作者的比喻只是到目前为止。我会让这更接近我的实际使用情况的一个例子:

假设我们有一些任务到绑定的位置:

public class Location { 
    public string Id { get; set; } 
    public double Latitude { get; set; } 
    public double Longitude { get; set; } 
} 

public class Task { 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public string LocationId { get; set; } 
    public Status TaskStatus { get; set; } 
} 

我有一个服务地点为GeoJSON的一个地图视图端点客户。我想根据与它们相关的任务的状态对位置进行着色。地图通常会显示500-2000个位置。

位置查询是作为流式查询实现的。

使用Ayende的初步答案显示的查询方法,我可能会做这样的事情:

foreach (var location in locationsInView) 
{ 
    var completedTaskIds = await RavenSession.Query<Task>() 
     .Where(t => t.LocationId == location.Id && t.TaskStatus == Status.Completed) 
     .ToListAsync(); 

    // 
    // Construct geoJson from location and completedTaskIds 
    // 
} 

这导致在500-2000查询正在对RavenDB,这看起来不正确执行。 这就是为什么我最初认为我需要一个索引来构建我的结果。

我已经读过RavenDB默认缓存所有内容,因此这可能不是问题。另一方面,在实施这种方法后,我得到一个错误(“...本次会话允许的最大请求数(30)...”)。

解决这个问题的好方法是什么?

+0

你能这样吗? '.Where(t => locationsInView.Any(x => x.Id == t.LocationId)&& ....'而不是foreach? – TryingToImprove

+0

我试过了。但是,不,我想因为Raven不能在内部执行任意C#,所以'locationsInView.Any(...)'不起作用 – AdamAL

回答

0

您可以使用multi map/reduce index来做到这一点。

关于感兴趣对象的所有真相源都被映射到一个通用对象类型(Result)。然后这个映射减少了Id的分组并保留了相关的部分,创建了关于每个对象的真值“合并”(在这种情况下为Book)。因此,使用Book/Author示例,其中几位作者可能对同一本书有所贡献,您可以执行以下操作。

请注意,映射和减少步骤必须输出相同类型的对象,这就是author.Id在作者映射期间被包装在列表中的原因。

Author.Name为简洁起见不包括在内,但可以按与Author.Id完全相同的方式包括在内。

public class BooksWithAuthors : AbstractMultiMapIndexCreationTask<BooksWithAuthors.Result> 
{ 
    public class Result 
    { 
     string Id; 
     string Title; 
     IEnumerable<string> AuthorIds; 
    } 

    public BooksWithAuthors() 
    { 
     AddMap<Book>(book => from book in books 
          select new 
          { 
           Id = book.Id, 
           Title = book.Title, 
           AuthorIds = null; 
          }); 

     AddMap<Author>(author => from author in authors 
           from bookId in author.bookIds 
           select new 
           { 
            Id = bookId, 
            Title = null, 
            AuthorIds = new List<string>(){ author.Id }; 
           }); 

     Reduce = results => from result in results 
          group result by result.Id 
          into g 
          select new 
          { 
           Id = g.Key, 
           Title = g.Select(r => r.Title).Where(t => t != null).First(), 
           AuthorIds = g.Where(r => r.AuthorIds != null).SelectMany(r => r.AuthorIds) 
          }; 
    } 
} 
1

你不能以这种方式编制索引。 但你也不需要。

如果您想查找作者的所有书籍,请加载作者,并获得完整列表。

+0

谢谢你的回答,Ayende!我可能不够具体,我已经更新了这个问题 – AdamAL

+0

我现在已经实现了一个索引akin到'LocationsWithTaskIds'使用multi-map/reduce索引,它似乎工作正常,但既然你说这是不可能的,我想知道你是否认为它是不好的做法,你能否详细说明一下? – AdamAL