ElasticSearch更新到子文档而不更新父文档

时间:2017-01-26 21:01:54

标签: c# elasticsearch nest

当子文档的属性发生变化时,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客户端。

1 个答案:

答案 0 :(得分:1)

你做的不太对劲。

  1. 在映射中,您将Child属性设置为嵌套类型,但随后将parentchild都编入索引。

    嵌套类型在嵌套的类型上建立索引,也就是说,表示Child上的parent属性的json被索引为父级的一部分json文件。

    Elasticsearch中可能有一个Parent/Child relationship,其中包含许多子项的父项,这听起来像您需要在模型中反转父/子角色才能使用。

  2. 在建立索引之后,您将获得parent文档的来源,更改父级的子级名称,但随后更新已编入索引的子文档,不带使用孩子更新parent

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

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

    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; } 
    }