Nest 无法处理 EF6/MVC5 的大型数据库模型

Nest can't cope with a big database model with EF6/MVC5

我得到了一个数据库,应该可以对其进行基本的 CRUD 操作。这是通过使用 .NET 4.5/MVC5 和 EF6 快速完成的。这意味着数据库优先方法。

新要求:(弹性)搜索。

为自定义 class 创建索引(未链接到模型中的其他索引)时,一切正常。当我使用带有很多外键的 class 时,一切都停止了。数据库由 100 个表组成,有 400 多个外键。

我认为问题可能是循环引用(客户有 n 个合同,其中有对客户的引用,其中有一个合同列表,......你明白了)。最终我得到一个 OutOfMemory 异常,一切都崩溃了。

代码:

public static Uri node;
public static ConnectionSettings settings;
public static ElasticClient client;

public ActionResult TestIndex()
    {
        node = new Uri("http://localhost:9200");
        settings = new ConnectionSettings(node, defaultIndex: "crudapp");
        client = new ElasticClient(settings);

        var indexSettings = new IndexSettings();
        indexSettings.NumberOfReplicas = 1;
        indexSettings.NumberOfShards = 1;

        //The next line causes the OutOfMemoryException
        client.CreateIndex(c => c.Index("crudapp")
                                 .InitializeUsing(indexSettings)
                                 .AddMapping<Customer>(map => map.MapFromAttributes(maxRecursion: 1)));


        foreach (Customer c in db.Customer.Where(a => a.Active == true))
            client.Index(c);

        return View("Index");
    }

如何告诉 Nest 停止递归或不使用某些对象?

示例 classes:

    public partial class Customer
    {
        public Customer()
        {
            this.CustomerContract = new HashSet<CustomerContract>();
        }

        public int Customerid { get; set; }
        public string CustomerName { get; set; }
        public string Description { get; set; }
        public bool Active { get; set; }

        public virtual ICollection<CustomerContract> CustomerContract { get; set; }
    }

    public partial class CustomerContract
    {
        public CustomerContract()
        {
            this.Host = new HashSet<Host>();
        }

        public int CustomerContractid { get; set; }
        public string CustomerContractName { get; set; }
        public string Description { get; set; }
        public int CustomerID { get; set; }
        public bool Active { get; set; }

        public virtual Customer Customer { get; set; }
        public virtual ICollection<Host> Host { get; set; }
    }

OutOfMemoryException 几乎可以肯定来自 Customer 对象的 JSON 序列化。因此,问题不是 NEST 或 Elasticsearch 功能之一,而是 JSON.NET 功能。

您可以通过以下两种方式之一处理此问题:

1.有选择地序列化大对象

This article by the author of JSON.NET discusses reducing the size of objects. You might furnish properties with the JsonIgnoreAttribute property to instruct the serializer to ignore certain properties. Or an implementation of IContractResolver 可能对 EF 对象的定义影响较小(特别是考虑到它们是数据库优先生成的),但我不确定这是否可以与 NEST 结合使用对 JSON.NET.

的依赖

如果您没有办法处理 NEST 对 JSON.NET 的依赖,您总是可以找到另一种方法来序列化您的对象和 "go raw",方法是使用 Elasticsearch.NET 语法代替NEST(本质上建立在 Elasticsearch.NET 之上)。因此,不要调用 ElasticClient.Index(..),而是调用 ElasticClient.Raw.Index(..),其中 body 参数是您希望的对象的 JSON 字符串表示(您自己构造的)索引。

2。将大对象投影到较小的数据传输对象

不要索引 Customer 对象,而是仅将要索引的属性映射到以 Elasticsearch 架构/文档类型为目标的数据传输对象 (DTO)。

foreach (Customer c in db.Customer.Where(a => a.Active == true))
    client.Index(new MyElasticsearchTypes.Customer()
        {
            CustomerId = c.CustomerId,
            CustomerName = c.CustomerName,
            Description = c.Description
        });

在 C# 中,对于如何处理此类 DTO 的创建,您有很多选择,包括:

  1. 具有手动映射的显式类型对象(如我的示例)。
  2. 使用 AutoMapper.
  3. 等映射工具的显式类型对象
  4. 动态对象。

扁平设计

请注意,使用 Elasticsearch 并不是简单地将数据放入 "the index"。您需要从 "documents" 的角度开始思考,并在您尝试为来自关系数据库的数据建立索引时理解这意味着什么。 Elasticsearch 指南文章 Data In, Data Out is a good place to start reading. Another article called Managing relations inside Elasticsearch 与您的情况特别相关:

At it's heart, Elasticsearch is a flat hierarchy and trying to force relational data into it can be very challenging. Sometimes the best solution is to judiciously choose which data to denormalize, and where a second query to retrieve children is acceptable