2

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

  • 如果嵌套结构/集合的属性被分离到索引的各个字段(单个集合)中,则AND在过滤嵌套结构/集合的 2+ 个属性时使用该条件是不可能的。
  • 扇出索引复杂度(参见示例),这使得任何解决方案运行速度都过慢。

给定以下持久模型:

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

可能的用例:

  • 获取包含特定用户和日期范围的“合同”一词的所有文档
  • 按用户最后一次修改对包含单词“contract”的文档进行排序。

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

4

2 回答 2

2

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

解决方案

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)关于该主题的讨论。

于 2018-07-08T03:03:02.540 回答
0

在索引定义中使用以下 RQL:

from doc in docs.Documents
from modification in doc.RecentModifications 
select new {
    modification.UserId,
    modification.Timestamp
}

注意:'UserId' & 'timestamp' 在底层索引条目中没有分开。

因此,对 UserId='A' AND Timestamp='2018-01-01' 组合进行过滤返回用户 'A' 在 '2018-01-01' 上修改的记录。

另请参阅扇出索引

注意2:“标题”也可以使用以下方法进行索引和搜索:

from doc in docs.Documents
from modification in doc.RecentModifications 
select new {
    doc.Title,
    modification.UserId,
    modification.Timestamp
}

因此,每个生成的“索引条目”都将像以前一样包含“用户 ID”“时间戳”,以及相关的“标题”

于 2018-06-06T14:24:45.833 回答