Elasticsearch + NEST:如何将多个字段映射到 .NET 字典中<string, object>

Elasticsearc + NEST: How to map multiple fields into a .NET Dictionary<string, object>

我正在开发一个包含 MongoDB 和 Elasticsearch 的示例项目。经过长时间的研究,我选择 Mongo-Connector 在 MongoDB 和 Elasticsearch 之间进行同步。它们之间的同步已经正常工作了。

我在 MongoDB 中插入了很多文档。基本上文档参考了"Person"。该文档具有以下基本 json 结构:

{
  "Id": "5a308536-0bd9-47e6-8bdb-438dafd0488c",
  "Name": "Seal",
  "ExtraElements": {
     "DateofBirth": "2001-12-27T03:41:30.333Z",
     "Age": 56,
     "Gender": "F"
  }
}

上面的 json 映射到这个 .net class

public class Person
{
    public string Id { get; set; }

    public string Name { get; set; }

    public Dictionary<string, object> ExtraElements { get; set; }
}

如你所见,"ExtraElements" 是一个存储 N 个字段的字典。我们需要这个,因为我们不知道我们会有多少字段。

当我在我的 Mongo 数据库中插入一个 json 时,它被映射到具有以下结构的文档中:

Person
  Id
  Name
  DateofBirth
  ...
  ...

使用 Mongo-Connector 并正常工作,当我在 MongoDB 上插入第一个文档时,相同的文档也被插入到 Elasticsearch 上。因为我没有类型,所以它是使用动态映射即时创建的。在 Elasticsearch 上创建的映射是这样的:

{
  "repository" : {
  "mappings" : {
  "Person" : {
    "properties" : {
      "DateofBirth" : {
         "type" : "date",
         "format" : "dateOptionalTime"
      },
      "Age" : {
        "type" : "long"
      },
      "Gender" : {
        "type": "string"
      }
      "Name" : {
        "type" : "string"
      }
    }
  }
}

} }

如您所见,ExtraElements 字段创建为 "flat" 文档,或者所有字段都在同一个 "level" 中,这意味着没有嵌套类型。

我现在的问题是:我正在使用 NEST 在 Elasticsearch 上查询,但是当我这样做时,我只得到 Id 和 Name 值,ExtraElements 字典为空。我是不是在 Elasticsearch 上做错了映射?在 c# 或 NEST 中有没有办法映射这个?

我想出了问题所在。

问题是数据在我的 MongoDB 中的保存方式。 "ExtraElements" 字典被内联保存,而不是作为我的意图的对象。由于 Mongo 连接器简单复制数据,相同的结构被保存在我的 Elasticsearch 中。

在深入阅读 C# 驱动程序文档后,我找到了这个解决方案:

C#Class:

public class Person
{
    public ObjectId Id { get; set; }

    public string Name { get; set; }

    public BsonDocument Metadata { get; set; }

    [BsonIgnore]
    public Dictionary<string, object> ExtraElements { get; set; }
}

在此之后:Mixing Static and Dynamic Data 我创建了一个 BsonDocument 并维护了 ExtraElements 词典。词典现在标记为 "ignored"。 API 控制器中的用法示例是:

public void Post(Person obj)
{
   obj.Metadata = new BsonDocument(obj.ExtraElements.DeserializeMongoObject())
   personBusiness.Save(obj);
}

DeserializeMongoObject() 是一位同事创建的用于 "handle" 多层对象嵌套的扩展方法。如果不使用它,它适用于一个 "level" 但如果在 ExtraElements 中有嵌套对象,它会保存为一个没有值的数组。

将扩展方法与 BsonDocument 结合使用,我在 MongoDB:

中得到了这个结果

在没有使用它的情况下,我得到了这个:(不知道为什么..)

扩展方法代码为:

public static Dictionary<string, object> DeserializeMongoObject(this Dictionary<string, dynamic> dictionary)
    {
        if (dictionary.Count > 0)
        {
            for (int i = 0, length = dictionary.Count; i < length; i++)
            {
                if (dictionary[dictionary.ElementAt(i).Key].GetType().ToString() == "Newtonsoft.Json.Linq.JObject")
                {
                    dictionary[dictionary.ElementAt(i).Key] = Newtonsoft.Json.JsonConvert.DeserializeObject<IDictionary<string, object>>(dictionary.ElementAt(i).Value.ToString());
                    dictionary[dictionary.ElementAt(i).Key] = DeserializeMongoObject(dictionary[dictionary.ElementAt(i).Key]);
                }
            }
        }

        return dictionary;
    }