当使用IndexMany

时间:2019-07-11 09:34:11

标签: c# elasticsearch nest

我正在努力解决问题。我正在构建一个我们在Elastic中为资产编制索引的应用程序。 资产的性质非常动态,因为它们包含客户端元数据,这在客户端之间是不同的。

因此,该索引是根据C#中的动态列表构建的。这实际上就像一种魅力。问题是,使用C#接口时,我无法控制Elastic中的_id属性。这意味着当我更新文档时,不是更新正确的文档,而是制作了新的副本。

我的代码如下:

List<dynamic> assets = new List<dynamic>();
var settings1 = new ConnectionSettings(
    new Uri("http://localhost:9200")
    ).DefaultIndex("assets");

var client = new ElasticClient(settings1);

//assets is build here

var indexResponse = client.Indices.Create("assets");
var BulkResponse = client.IndexMany(assets);

这实际上有效,并且索引几乎按我期望的那样建立。即使我在动态对象上有一个名为Id的属性,也无法正确推断出该属性,这意味着将为文档提供由Elastic决定的_Id。因此,下次我使用相同的ID运行此代码时,会创建一个新文档,而不是对其进行更新。

我一直在搜寻高空,但似乎找不到一个好的解决方案。我尝试过的一件事是:

var bulkResponse = client.Bulk(bd => bd.IndexMany(assets, (descriptor, s) => descriptor.Id(s.Id)));

但是这引发了我无法在.net内核中捕获的错误。这实际上适用于Elastic上的较低版本,但似乎已被7.2和7.0.1的C#接口所破坏。

非常感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

代替使用git add --patch类型,您可以创建基于字典的自定义类型,例如:

dynamic

并按以下方式使用它:

    public class DynamicDocument : Dictionary<string, object>
    {
        public string Id => this["id"]?.ToString();
    }

输出:

class Program
{
    public class DynamicDocument : Dictionary<string, object>
    {
        public string Id => this["id"]?.ToString();
    }

    static async Task Main(string[] args)
    {
        var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
        var connectionSettings = new ConnectionSettings(pool);
        connectionSettings.DefaultIndex("documents");

        var client = new ElasticClient(connectionSettings);

        await client.Indices.DeleteAsync("documents");
        await client.Indices.CreateAsync("documents");

        var response = await client.IndexAsync(
            new DynamicDocument
            {
                {"id", "1"}, 
                {"field1", "value"}, 
                {"field2", 1}
            }, descriptor => descriptor);

        //will update document with id 1 as it's already exists
        await client.IndexManyAsync(new[]
        {
            new DynamicDocument
            {
                {"id", "1"},
                {"field1", "value2"},
                {"field2", 2}
            }
        }); 

        await client.Indices.RefreshAsync();

        var found = await client.GetAsync<DynamicDocument>("1");

        Console.WriteLine($"Id: {found.Source.Id}");
        Console.WriteLine($"field1: {found.Source["field1"]}");
        Console.WriteLine($"field2: {found.Source["field2"]}");
    }
}

已通过Elasticsearch 7.2.0和NEST 7.0.1测试。

希望有帮助。

答案 1 :(得分:2)

要允许以下内容正常工作

var bulkResponse = client.Bulk(bd => bd.IndexMany(assets, (descriptor, s) => descriptor.Id(s.Id)));

您只需要将Id类型转换为原来的类型。例如,如果它是string

var client = new ElasticClient();

var assets = new dynamic[] 
{
    new { Id = "1", Name = "foo" },
    new { Id = "2", Name = "bar" },
    new { Id = "3", Name = "baz" },     
};

var bulkResponse = client.Bulk(bd => bd.IndexMany(assets, (descriptor, s) => descriptor.Id((string)s.Id)));

这是运行时限制。