使用 NEST 索引动态对象

Posted

技术标签:

【中文标题】使用 NEST 索引动态对象【英文标题】:Index a dynamic object using NEST 【发布时间】:2014-11-04 20:48:51 【问题描述】:

我正在构建一个 API 应用程序,该应用程序本质上允许用户构建一个文档,该文档可以按照他们想要的方式进行结构化,并将存储在 Elasticsearch 中。本质上,我为用户提供了一个简单的界面来访问我们的 Elasticsearch 实例。我试图使实现尽可能简单。这是我目前正在处理的问题。

预期主体的对象:

public class DocumentModel

    public string Index  get; set; 
    public string Type  get; set; 
    public string Id  get; set; 
    [ElasticProperty(Type = FieldType.Nested)]
    public dynamic Document  get; set; 

简单实现:

[HttpPost]
[Route("")]
public IHttpActionResult Post(DocumentModel document)

    Uri nodeLocation = new Uri("http://localhost:9200");
    IConnectionPool connectionPool = new SniffingConnectionPool(new List<Uri>  nodeLocation );
    ConnectionSettings settings = new ConnectionSettings(connectionPool);
    ElasticClient esClient = new ElasticClient(settings);

    IIndexResponse result = esClient.Index(document, i => i
        .Index(document.Index)
        .Type(document.Type)
        .Id(document.Id));

    return Ok(result.IsValid);

这很好用,但它在源中包含索引、类型和 ID。我真正想做的只是在索引时提供这三个信息,但实际上只是索引 document.Document,它是动态类型的。但是,这似乎与 Nest 不一致,因为它会在 IDE 和编译时引发错误:

“匿名函数或方法组不能用作动态绑定操作的组成值”

“不能使用 lambda 表达式作为动态调度操作的参数,除非先将其转换为委托或表达式树类型”。

我怎样才能只索引document.Document?有没有比使用动态类型更好的方法来处理未知结构的传入 JSON 文档?

【问题讨论】:

【参考方案1】:

有几种方法可以做到这一点。

尝试将文档作为动态类型进行索引是行不通的,但您可以通过 IndexRequest 对象将其作为对象进行索引。

dynamic dynamicDoc = new  /*fill in document format here*/ ;
ElasticClient esClient = new ElasticClient(esSettings);

IndexRequest<object> request = new IndexRequest<object>(dynamicDoc)

    Index = "someindex",
    Type = "SomeType",
    Id = "someid"
;

esClient.Index<object>(request);

或者如果批量处理文件

List<dynamic> Documents = new List<dynamic>();
//Populate Documents

BulkDescriptor descriptor = new BulkDescriptor();
foreach(var doc in Documents)

    descriptor.Index<object>(i => i
        .Index("someindex")
        .Type("SomeType")
        .Id("someid")
        .Document(doc));


esClient.Bulk(descriptor);

NEST(或更准确地说,Elasticsearch.Net)还有一个附加到 ElasticClient 类的 .Raw 方法变体,它可以索引原始 JSON。使用 Raw.Index() 让我们做这样的事情:

string documentJson = JsonConvert.SerializeObject(document.Document);

ElasticsearchResponse<string> result = esClient.Raw.Index(document.Index, document.Type, document.Id, documentJson);

响应的类型描述符是您期望响应的类型(字符串表示您将拥有一个序列化的 json 响应,您可以对其进行反序列化并执行某些操作)。这使我们能够回避整个对象类型问题,并且 NEST 完全按照预期将文档索引到 Elasticsearch 中。

【讨论】:

我希望 Raw.Index 在新索引中保留旧索引中的父子关系 作为dynamic 的替代品,我使用了Dictionary&lt;string, object&gt; 或从类继承。警告:如果您从Dictionary 继承,NEST 将不会自动映射文档上的其他属性(而是将它们放入字典中)。这也适用于变量属性:公共属性进入 POCO 属性,变量属性进入 Data 属性(类型为 Dictionary&lt;string,object&gt;)。这种批量方法易于使用。不要忘记获取对Bulk 的调用结果以检查.Errors 等! dynamic document = JsonConvert.DeserializeObject&lt;dynamic&gt;(jsonString);转换的动态类型不能直接工作。这是reason,NEST.JsonNetSerializer 是解决方案。这是如何实现solution

以上是关于使用 NEST 索引动态对象的主要内容,如果未能解决你的问题,请参考以下文章

使用 NEST 2.x 使用多字段映射语法创建索引

Nest.js - 在猫鼬模式中创建索引

如何使用 NEST 更新 ElasticSearch 索引中的现有文档?

使用 NEST C# 在弹性搜索中使用多个索引进行全文搜索

NEST 批量插入后等待服务器完成索引

使用 Elasticsearch NEST C# 索引 Json 文档