如何在Ravendb中反向索引相关文档
How to index related documents in reverse direction in Ravendb
在 Indexing Related Documents 的示例 II 中,索引是按作者姓名和书名建立的。相关实体如下所示:
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; }
}
即只有 Author
包含有关关系的信息。此信息用于构建所述索引。
但是我如何按作者构建书籍索引(假设一本书可能有多个作者)?
编辑:
book/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; }
}
我有一个端点将 Locations 作为 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
//
}
这导致针对 RavenDB 执行了 500-2000 个查询,这似乎不正确。
这就是为什么我最初认为我需要一个索引来构建我的结果。
我后来读到 RavenDB 默认缓存所有内容,所以这可能不是问题。另一方面,实施此方法后,我收到错误消息(“...此会话允许的最大请求数 (30)...”)。
解决这个问题的好方法是什么?
您不能以这种方式为它们编制索引。
但你也不需要。
如果您想查找某位作者的所有书籍,请加载该作者并获得完整列表。
您可以使用 multi map/reduce index 来完成此操作。
有关感兴趣对象的所有真实来源都映射到一个通用对象类型 (Result
)。然后,此映射按 Id 减少分组并仅保留相关部分,从而创建关于每个对象的 "merge" 个真相(在本例中为 Book
)。因此,使用 Book/Author 示例,其中多个作者可能对同一本书做出了贡献,您可以执行如下操作。
请注意,map 和 reduce 步骤必须输出相同类型的对象,这就是为什么 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)
};
}
}
在 Indexing Related Documents 的示例 II 中,索引是按作者姓名和书名建立的。相关实体如下所示:
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; }
}
即只有 Author
包含有关关系的信息。此信息用于构建所述索引。
但是我如何按作者构建书籍索引(假设一本书可能有多个作者)?
编辑:
book/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; }
}
我有一个端点将 Locations 作为 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
//
}
这导致针对 RavenDB 执行了 500-2000 个查询,这似乎不正确。 这就是为什么我最初认为我需要一个索引来构建我的结果。
我后来读到 RavenDB 默认缓存所有内容,所以这可能不是问题。另一方面,实施此方法后,我收到错误消息(“...此会话允许的最大请求数 (30)...”)。
解决这个问题的好方法是什么?
您不能以这种方式为它们编制索引。 但你也不需要。
如果您想查找某位作者的所有书籍,请加载该作者并获得完整列表。
您可以使用 multi map/reduce index 来完成此操作。
有关感兴趣对象的所有真实来源都映射到一个通用对象类型 (Result
)。然后,此映射按 Id 减少分组并仅保留相关部分,从而创建关于每个对象的 "merge" 个真相(在本例中为 Book
)。因此,使用 Book/Author 示例,其中多个作者可能对同一本书做出了贡献,您可以执行如下操作。
请注意,map 和 reduce 步骤必须输出相同类型的对象,这就是为什么 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)
};
}
}