我已经获得了一个数据库,可以根据该数据库进行基本的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; }
}
最佳答案 OutOfMemoryException几乎肯定来自Customer对象的JSON序列化.因此,问题不是NEST或Elasticsearch功能,而是JSON.NET功能.
您可以通过以下两种方式之一处理此问题:
1.有选择地序列化大对象
This article由JSON.NET的作者讨论减少对象的大小.您可以使用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的创建,包括:
>带有手动映射的显式类型对象(如我的示例).
>使用映射工具(如AutoMapper)显式输入对象.
>动态对象.
平面设计
请注意,使用Elasticsearch并不是简单地将数据放入“索引”中.您需要从“文档”开始思考,并在尝试索引来自关系数据库的数据时意味着什么. Elasticsearch指南文章Data In, Data Out是一个开始阅读的好地方.另一篇名为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