C# 实体框架将数千个对象转移到弹性搜索

C# 实体框架将数千个对象转移到弹性搜索,c#,entity-framework,nest,C#,Entity Framework,Nest,我正在创建一个web应用程序,它将在世界上每个城镇、地区和国家拥有一个数据库,以便将其他对象映射到一个位置。作为应用程序的一部分,我希望用户能够搜索一个地方,为此,我使用弹性搜索对所有内容进行索引。为了与弹性搜索交互,我正在使用NEST 我有以下代码: public void RefreshLocationIndex() { int count; using (var dbContext = new ModelContext()) { IndexMany(

我正在创建一个web应用程序,它将在世界上每个城镇、地区和国家拥有一个数据库,以便将其他对象映射到一个位置。作为应用程序的一部分,我希望用户能够搜索一个地方,为此,我使用弹性搜索对所有内容进行索引。为了与弹性搜索交互,我正在使用NEST

我有以下代码:

public void RefreshLocationIndex()
{
    int count;
    using (var dbContext = new ModelContext())
    {
        IndexMany(dbContext.Countries, "Country");
    }

    using (var dbContext = new ModelContext())
    {
        count = dbContext.Regions.AsNoTracking().Count();
    }
    for (var i = 0; i <= count; i += BATCH_SIZE)
    {
        using (var innerContext = new ModelContext())
        {
            IndexMany(innerContext.Regions.OrderBy(t => t.RegionID).Skip(i).Take(BATCH_SIZE),
                    "Region");
        }
    }


    using (var dbContext = new ModelContext())
    {
        count = dbContext.Towns.AsNoTracking().Count();
    }
    for (var i = 0; i <= count; i += BATCH_SIZE)
    {
        using (var innerContext = new ModelContext())
        {
            IndexMany(innerContext.Towns.AsNoTracking().OrderBy(t => t.TownID).Skip(i).Take(BATCH_SIZE), "Town");
        }
    }
}

public void IndexMany(IQueryable<Entity> objects, string type)
{
    var itemCount = objects.Count();
    if (itemCount > 0)
    {
        SearchClient.Instance.IndexManyAsync(objects, SearchClient.Instance.Settings.DefaultIndex, type);
    }
}
public void RefreshLocationIndex()
{
整数计数;
使用(var dbContext=newmodelcontext())
{
IndexMany(dbContext.Countries,“国家”);
}
使用(var dbContext=newmodelcontext())
{
count=dbContext.Regions.AsNoTracking().count();
}
对于(var i=0;i t.RegionID)。跳过(i)。获取(批次大小),
“区域”);
}
}
使用(var dbContext=newmodelcontext())
{
count=dbContext.Towns.AsNoTracking().count();
}
对于(var i=0;i t.TownID).跳过(i).获取(批量大小),“Town”);
}
}
}
public void IndexMany(IQueryable对象,字符串类型)
{
var itemCount=objects.Count();
如果(itemCount>0)
{
SearchClient.Instance.IndexManySync(对象,SearchClient.Instance.Settings.DefaultIndex,类型);
}
}
正如您所看到的,我将非常大的表分为若干批,以避免将太多的数据加载到内存中。问题是这不起作用,而且我总是出现内存不足的异常。我认为为每个批使用一个新的上下文可以避免这个问题,因为当上下文被释放时,它会释放它加载的所有实体,但情况似乎并非如此。有什么想法吗

作为数据量的指示: 国家表有193项记录 区域表有80523条记录
Town表有2743469条记录

我不知道ElasticSearch和NEST,但根据,
IndexManySync
每次调用它时都会创建一个新任务

所以,如果任务的执行速度比实体框架具体化实体的速度慢得多,那么将有大量正在执行(或等待执行)的任务,每个任务都有
BATCH\u SIZE
实体加载到内存中,这些实体作为参数传递:因此基本上所有实体都将同时加载到内存中


我不知道如何解决这个问题,因为我不知道NEST或ElasticSearch在批处理索引方面的最佳实践,但下面是对您的问题的解释。

对象只有在没有实时引用的情况下才有资格进行垃圾收集。
显然,您已经处理了上下文,但是您可能仍然有对不太明显的实体的引用。在SearchClient.Instance.IndexManySync(对象,…)中的某个地方,您必须仍然持有对对象的引用

在本例中,释放dbContext时不会回收内存

List<Region> regions;
using (var dbContext = new ModelContext())
{
    regions = dbContext.Regions.ToList();  
}  //dbContext is disposed, but memory is not reclaimed.
regions = null; //memory is reclaimed
列出区域;
使用(var dbContext=newmodelcontext())
{
regions=dbContext.regions.ToList();
}//已释放dbContext,但未回收内存。
区域=空//内存被回收

对于
dbContext.Countries
innerContext.Regions
,您是否会缺少
AsNoTracking()
?当您使用ChangeTracker时,它将在内存中保留引用,直到查询的实体引用消失

在您的情况下,它可能会增加您的内存,因为多个上下文(主要是区域的innerContext)实际上由于ChangeTracker而没有被处理

只需尝试对所有查询使用AsNoTracking,然后再次检查内存占用

在您的情况下,通过不使用AsNoTracking,所有被跟踪的实体都会被传递到您的SearchClient方法,那么您就不知道这些引用实际何时会被释放


如果问题与EF本身无关,请尝试使用类似的工具来查找内存泄漏,它非常有用。

是否明智地创建和处理大dbcontext 80523次(仅用于区域)和2743469次(用于城镇)?您需要等待IndexManySync完成加法,然后在等待完成的同时将所有内容放入内存中。