【问题标题】:Nest can't cope with a big database model with EF6/MVC5Nest 无法使用 EF6/MVC5 处理大型数据库模型
【发布时间】:2015-04-10 17:13:39
【问题描述】:

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

新要求:(弹性)搜索。

为自定义类创建索引时(未链接到模型中的其他类),一切都很好。当我使用一个有很多外键的类时,事情就停止了。该数据库由 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 停止递归或不使用某些对象?

示例类:

    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; }
    }

【问题讨论】:

    标签: c# entity-framework elasticsearch asp.net-mvc-5 nest


    【解决方案1】:

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

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

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

    JSON.NET 的作者This article 讨论了减小对象的大小。您可以使用JsonIgnoreAttribute property 提供属性以指示序列化程序忽略某些属性。或者IContractResolver 的实现可能对 EF 对象的定义影响较小(特别是考虑到它们是数据库首先生成的),但我不确定这是否可以与 NEST 对 JSON 的依赖结合使用.NET。

    如果您没有办法处理 NEST 对 JSON.NET 的依赖,您总能找到另一种方法来序列化您的对象并使用 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. 动态对象。

    扁平化设计

    请注意,使用 Elasticsearch 并不是简单地将数据放入“索引”。您需要从“文档”的角度开始思考,并在尝试对来自关系数据库的数据进行索引时了解这意味着什么。 Elasticsearch 指南文章Data In, Data Out 是开始阅读的好地方。另一篇名为Managing relations inside Elasticsearch 的文章与您的情况特别相关:

    从本质上讲,Elasticsearch 是一个扁平的层次结构,试图将关系数据强制加入其中可能非常具有挑战性。有时最好的解决方案是明智地选择要对哪些数据进行非规范化,以及在哪里可以接受第二个查询来检索子项

    【讨论】:

      猜你喜欢
      • 2015-10-14
      • 1970-01-01
      • 2010-09-15
      • 1970-01-01
      • 2015-03-30
      • 2013-11-11
      • 1970-01-01
      • 2017-10-12
      • 1970-01-01
      相关资源
      最近更新 更多