首页 > 解决方案 > RavenDb 索引对嵌套结构/集合的属性进行过滤和排序(扇出索引)

问题描述

我正在寻找一种创建静态索引的方法,以便为嵌套结构(对象集合)中的属性值组合以及结构容器提供过滤/排序查询。由于以下原因,这似乎并非微不足道:


给定以下持久模型:

public class Document
{
    public string Title { get; set; }

    public List<UserChange> RecentModifications { get; set; }
}

在哪里

public class UserChange
{
    public string UserId { get; set; }
    public DateTime Timestamp { get; set; }
}

问题:如何构建索引Document以通过所有字段的组合进行过滤/排序TitleUserIdTimestamp

可能的用例:


PS我知道可以通过重构持久性模型来绕过索引限制 - 在文档中存储最近修改的文档的结构User,但它会施加一些其他限制,我想避免这些限制。

标签: c#indexingnosqlravendbravendb4

解决方案


该问题可以通过使用带有动态字段的索引来解决。它允许保持逻辑数据结构并避免创建扇出索引

解决方案

Document为上述集合创建以下索引:

public class MyIndex : AbstractIndexCreationTask<Document, DocumentIndDto>
{
    public MyIndex()
    {
        // Add fields that are used for filtering and sorting
        Map = docs =>
            from e in docs
            select new
            {
                Title = e.Title, 
                _ = e.RecentModifications.Select( x => CreateField ($"{nameof(Document.RecentModifications)}_{x.UserId}", x.Timestamp))
            };
    }
}

public class DocumentIndDto
{
    public string Title { get; set; }
    public Dictionary<string,DateTime> RecentModifications { get; set; }
}

MyIndex点赞查询

var q = s.Query<DocumentIndDto, MyIndex>()
                .Where(p => p.Title == "Super" && p. RecentModifications["User1"] < DateTime.Now);

解释

具有动态字段的指定索引将为每条记录生成额外的字段和术语,格式如下:

RecentModifications_User1 = '2018-07-01';
RecentModifications_User2 = '2018-07-02';

格式很重要,因为当您在高级查询(如 )中使用字典时myDic[key],它会myDic_key在生成的 RQL 中转换为。因此,它将允许我们在查询中使用这些字段。

如果您使用通常Query而不是DocumentQuery(请参阅文档)进行查询,那么您需要适当的数据类型才能使 LINQ 工作。为此,我创建了DocumentIndDto类,其中我的RecentModifications已成为字典,因此我可以在高级查询中使用它并获得正确的 RQL,例如

from index 'MyIndex' where Title = $p0 and RecentModifications_User1 = $p1

有关更多详细信息,请参阅我与 Oren Eini(又名 Ayende Rahien)关于该主题的讨论。


推荐阅读