【问题标题】:ElasticSearch update to child document not updating parent documentElasticSearch 更新到子文档而不更新父文档
【发布时间】:2017-01-27 08:58:46
【问题描述】:

当子文档的属性发生变化时,ElasticSearch 中是否有办法自动更新所有父文档?也许我在跟踪我是如何使用 ElasticSearch 的。代码:

        var child = new Child
        {
            Id = Guid.NewGuid(),
            Name = "Child"
        };

        var parent = new Parent
        {
            Id = Guid.NewGuid(),
            Name = "Parent",
            Child = child
        };

        var nestedResponse = client.CreateIndex("index", i => i
            .Mappings(m => m
                .Map<Parent>(map => map
                    .AutoMap()
                    .Properties(ps => ps
                        .Nested<Child>(n => n
                            .Name(p => p.Child)
                            .AutoMap()
                        )
                    )
                )
            )
        );

        var indexResult = client.Index<Parent>(parent);
        indexResult = client.Index<Child>(child);

        var reloadedParent = client.Get<Parent>(parent.Id.ToString()).Source;
        var childName = reloadedParent.Child.Name;
        child.Name = "child changed";
        var updateRequest = new UpdateRequest<Child, Child>("index", typeof(Child), child.Id);
        updateRequest.Doc = child;

        var reindexResult = client.Update<Child>(updateRequest);

        var reloadedParentAfterChildChange = client.Get<Parent>(parent.Id.ToString()).Source;
        var childChangedName = reloadedParentAfterChildChange.Child.Name;

        Assert.AreEqual(child.Name, childChangedName);

    }
}

public class Parent
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Child Child { get; set; }
}

public class Child
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

孩子可以属于许多不同的父母。有什么方法可以将子项的更改传播给包含子项的所有父项?我正在使用来自 c# 的 Nest 客户端。

【问题讨论】:

    标签: c# elasticsearch nest


    【解决方案1】:

    你所做的并不完全正确。

    1. 在映射中,您将Child 属性设置为嵌套类型,然后同时索引parentchild

      嵌套类型在它所嵌套的类型上进行索引,即表示parent 上的Child 属性的json 被索引为父json 文档的一部分。

      在 Elasticsearch 中可以有一个 Parent/Child relationship 一个父级到多个子级,听起来您需要在模型中反转父/子角色才能使用。

    2. 在建立索引之后,您获得了parent 文档的来源,在父级上更改了子级的子级名称,然后更新您已索引的子级文档,没有更新@987654329 @孩子。

      许多文档可以具有相同的嵌套文档值,但这些文档之间不会有任何关系,因此更新值需要对每个文档进行更新。这可以通过Update By Query API 完成。

    这里有一个例子来演示;在生产环境中,您可能不想禁用直接流式传输、注销所有请求/响应、每次操作后调用刷新等。

    void Main()
    {
        var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
        var defaultIndex = "default-index";
        var connectionSettings = new ConnectionSettings(pool)
                .DefaultIndex(defaultIndex)
                .PrettyJson()
                .DisableDirectStreaming()
                .OnRequestCompleted(response =>
                    {
                        // log out the request
                        if (response.RequestBodyInBytes != null)
                        {
                            Console.WriteLine(
                                $"{response.HttpMethod} {response.Uri} \n" +
                                $"{Encoding.UTF8.GetString(response.RequestBodyInBytes)}");
                        }
                        else
                        {
                            Console.WriteLine($"{response.HttpMethod} {response.Uri}");
                        }
    
                        Console.WriteLine();
    
                        // log out the response
                        if (response.ResponseBodyInBytes != null)
                        {
                            Console.WriteLine($"Status: {response.HttpStatusCode}\n" +
                                     $"{Encoding.UTF8.GetString(response.ResponseBodyInBytes)}\n" +
                                     $"{new string('-', 30)}\n");
                        }
                        else
                        {
                            Console.WriteLine($"Status: {response.HttpStatusCode}\n" +
                                     $"{new string('-', 30)}\n");
                        }
                    });
    
        var client = new ElasticClient(connectionSettings);
    
        if (client.IndexExists(defaultIndex).Exists)
            client.DeleteIndex(defaultIndex);
    
        var child = new Child
        {
            Id = Guid.NewGuid(),
            Name = "Child"
        };
    
        var parent = new Parent
        {
            Id = Guid.NewGuid(),
            Name = "Parent",
            Child = child
        };
    
        var anotherParent = new Parent
        {
            Id = Guid.NewGuid(),
            Name = "Another Parent",
            Child = child
        };
    
        var nestedResponse = client.CreateIndex(defaultIndex, i => i
            .Mappings(m => m
                .Map<Parent>(map => map
                    .AutoMap()
                    .Properties(ps => ps
                        .String(s => s
                            .Name(nn => nn.Id)
                            .NotAnalyzed()
                        )
                        .Nested<Child>(n => n
                            .Name(p => p.Child)
                            .AutoMap()
                            .Properties(p => p
                                .String(s => s
                                    .Name(nn => nn.Id)
                                    .NotAnalyzed()
                                )
                            )
                        )
                    )
                )
            )
        );
    
        var indexResult = client.Index<Parent>(parent);
        indexResult = client.Index<Parent>(anotherParent);
    
        var fetchedParent = client.Get<Parent>(parent.Id).Source;
        var fetchedAnotherParent = client.Get<Parent>(anotherParent.Id).Source;
    
        client.Refresh(defaultIndex);
    
        var update = client.UpdateByQuery<Parent>(u => u
            .Query(q => q
                .Nested(n => n
                    .Path(p => p.Child)
                    .Query(qq => qq
                        .Term(t => t.Child.Id, child.Id)
                    )
                )
            )
            .Script("ctx._source.child.name='New Child Name'")
            .Conflicts(Conflicts.Abort)
            .WaitForCompletion()
            .Refresh()
        );
    
        fetchedParent = client.Get<Parent>(parent.Id).Source;
        fetchedAnotherParent = client.Get<Parent>(anotherParent.Id).Source;
    }
    
    
    public class Parent
    {
        public Guid Id { get; set; }
    
        public string Name { get; set; }
    
        public Child Child { get; set;} 
    }
    
    public class Child
    {
        public Guid Id { get; set; }
    
        public string Name { get; set; } 
    }
    

    【讨论】:

    • 谢谢,这行得通……当孩子可以属于不同类型的父母时,这有点混乱……就像客户可以属于一个项目、一个订单等
    • Elasticsearch 非常适合用于搜索、分析和大规模处理大数据,并具有出色的性能。但是,它不是关系数据存储,因此可能需要重新设计数据建模方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-06
    • 2018-01-31
    • 2019-10-13
    • 1970-01-01
    • 1970-01-01
    • 2015-07-29
    相关资源
    最近更新 更多