我已经获得了一个数据库,可以根据该数据库进行基本的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; }
}
答案 0 :(得分:2)
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(基本上构建于-top of Elasticsearch.NET)。因此,不要调用ElasticClient.Index(..)
,而是调用ElasticClient.Raw.Index(..)
,其中body
参数是您要索引的对象的JSON字符串表示形式(属于您自己的构造)。 / p>
<强> 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的创建,包括:
平面设计
请注意,使用Elasticsearch并不是简单地将数据放入“索引”中。您需要从“文档”开始思考,并在尝试索引来自关系数据库的数据时意味着什么。 Elasticsearch指南文章Data In, Data Out是一个开始阅读的好地方。另一篇名为Managing relations inside Elasticsearch的文章与您的情况特别相关:
在它的核心,Elasticsearch是一个扁平的层次结构,并试图强制关系数据进入它可能是非常具有挑战性的。有时最好的解决方案是明智地选择要反规范化的数据,以及可以接受第二个检索子项的查询