如何使用 .NET 中的 NEST 库在 ElasticSearch 中创建带有索引的文档?

分享于2022年07月17日 c# elasticsearch nest 问答
【问题标题】:如何使用 .NET 中的 NEST 库在 ElasticSearch 中创建带有索引的文档?(How to create document with an index in ElasticSearch using NEST library in .NET?)
【发布时间】:2022-01-21 03:46:38
【问题描述】:

我第一次尝试在 C# 中使用弹性搜索,我正在尝试创建一个类似于 sql 中的一行的文档。

据我了解,索引类似于表格,文档是一行。我尝试使用 CreateDocumentAsync 方法,但它没有任何参数可以传入索引,所以我不确定如何创建具有特定索引的文档。我不能使用默认索引,因为我们的产品可以有很多索引。首先,我检查索引是否存在,如果不存在,则创建索引,然后创建文档

这里有一些代码

public async Task CreateDocumentAndIndex(T document, string index) where T : class
{
    CreateResponse response = new(); 
    if (_client.Indices.Exists(index).Exists)
    {
        response = await _client.CreateDocumentAsync(document);
    }
    else
    {
        await _client.IndexAsync(document, idx => idx.Index(index));
        response = await _client.CreateDocumentAsync(document);
    }         
    return response;
}

现在要使用它,我有一个调用此方法的函数

var response = await elasticSearchClient.CreateDocumentAndIndex(eventData,"test");

但它在尝试创建文档时给了我一个错误。在弹性搜索中创建行/文档时有没有办法传入索引

  • 如果您能将错误信息提供给我们,将会非常有帮助。

【解决方案1】:

问题标记为 elasticsearch-5 ,因此假设您使用的是NEST 5.6.6,可以在创建文档的同时指定索引

var client = new ElasticClient();

var createResponse = await client.CreateAsync(new { foo = "bar" }, c => c
    .Index("my-index") // index
    .Type("_doc") // document type
    .Id("1") // document id
);

编辑:

由于您使用的是 Elasticsearch 6.3.0,您 必须 使用最新的 NEST 6.x 客户端,在撰写本文时为 6.8.10 。在 NEST 6.8.10 中,创建文档 API 调用如下

private static void Main()
{
    var pool = new SingleNodeConnectionPool(new Uri($"http://localhost:9200"));
    var settings = new ConnectionSettings(pool)
        .DisableDirectStreaming()
        .PrettyJson()
        .DefaultTypeName("_doc") // doc types are gone in future versions, so best to index with this default doc type name
        .OnRequestCompleted(LogToConsole);
        
    var client = new ElasticClient(settings);
    
    if (client.IndexExists("my-index").Exists) 
    {
        client.DeleteIndex("my-index");
    }

    var document = new MyDocument
    {
        Foo = "Bar",
        Baz = 1
    };

    var createResponse = client.Create(document, c => c
        .Index("my-index") // index
        .Id("1") // document id
    );
    
    var returnedDocument = client.Get("1", g => g.Index("my-index"));
}

public class MyDocument
{
    public string Foo { get; set; }
    
    public int Baz { get; set; }
}

private static void LogToConsole(IApiCallDetails callDetails) 
{
    if (callDetails.RequestBodyInBytes != null)
    {
        var serializer = new JsonSerializer();
        var jObjects = new List();
        using (var sr = new StringReader(Encoding.UTF8.GetString(callDetails.RequestBodyInBytes)))
        using (var jsonTextReader = new JsonTextReader(sr))
        {
            jsonTextReader.SupportMultipleContent = true;
            while (jsonTextReader.Read())
                jObjects.Add((JObject)JObject.ReadFrom(jsonTextReader));
        }

        var formatting = jObjects.Count == 1
            ? Newtonsoft.Json.Formatting.Indented
            : Newtonsoft.Json.Formatting.None;
        var json = string.Join("\n", jObjects.Select(j => j.ToString(formatting)));
        Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri} \n{json}");
    }
    else
    {
        Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri}");
    }

    Console.WriteLine();

    if (callDetails.ResponseBodyInBytes != null)
    {
        Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
                 $"{Encoding.UTF8.GetString(callDetails.ResponseBodyInBytes)}\n" +
                 $"{new string('-', 30)}\n");
    }
    else
    {
        Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
                 $"{new string('-', 30)}\n");
    }
}

将以下内容记录到控制台

PUT http://localhost:9200/my-index/_doc/1/_create?pretty=true
{
  "foo": "Bar",
  "baz": 1
}

Status: 201
{
  "_index" : "my-index",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

------------------------------

GET http://localhost:9200/my-index/_doc/1?pretty=true

Status: 200
{
  "_index" : "my-index",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "foo" : "Bar",
    "baz" : 1
  }
}

------------------------------

  • 这里的文档ID是什么?我正在创建一个文档,那么我怎样才能获得这个 ID?我正在为所有要使用的类创建一个通用方法,所以我不知道文档或对象的主键是什么
  • 我在这里没有类型选项,如果我删除类型,我会收到错误文档映射无法以_开头我使用的是 Elastic Search .NET 7.16
  • @LearnAspNet 你用的是什么版本的 NEST 和什么版本的 Elasticsearch? Create API 需要为文档提供 id - 如果您需要 Elasticsearch 在文档被索引时为文档生成 id,请使用 Index API(或批量文档的索引操作的 Bulk API)
  • .NEST 7.16.0 和 Elastic Search 6.3.0
  • 就像我说的那样,它不起作用。它说 CreateDescriptor 不包含类型的定义,也没有接受“类型”的可访问扩展方法。我也没有文件的ID。我希望在特定索引下创建文档