4

他のオブジェクトを場所にマッピングできるように、世界中のすべての町、地域、国にデータベースを持つ Web アプリを作成しています。アプリケーションの一部として、ユーザーが場所を検索できるようにしたいと考えています。そのために、Elastic Search を使用してすべてのインデックスを作成しています。Elastic Search と対話するために、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);
    }
}

ご覧のとおり、非常に大きなテーブルをバッチに分割して、大量のメモリへのロードを回避しようとしています。問題は、これが機能していないことです。メモリ不足の例外が発生し続けています。コンテキストが破棄されると、読み込まれたすべてのエンティティが破棄されるため、バッチごとに新しいコンテキストを使用すると、この問題が回避されると思いましたが、そうではないようです。何か案は?

データ量の目安: 国テーブルには 193 件のレコードが含まれています 地域テーブルには 80,523 件のレコードがあります 町テーブルには 2,743,469 件のレコードがあります

4

3 に答える 3

0

ElasticSearch や NEST についてはわかりませんが、ソース コードによると、IndexManyAsync呼び出されるたびに新しいタスクが作成されます。

したがって、Entity Framework がエンティティを具体化するよりもタスクの実行がはるかに遅い場合、実行中の (または実行を待機している) 膨大な数のタスクが発生し、各タスクにはBATCH_SIZEエンティティがパラメーターとして渡されるため、エンティティがメモリに読み込まれます。すべてのエンティティが同時にメモリに読み込まれます。

バッチ インデックスに関する NEST または ElasticSearch のベスト プラクティスがわからないため、これを解決する方法がわかりませんが、問題の説明は次のとおりです。

于 2013-11-04T13:35:36.363 に答える
0

オブジェクトへのライブ参照がない場合にのみ、オブジェクトはガベージ コレクションの対象となります。
明らかに、コンテキストを破棄しましたが、あまり明白ではないエンティティへの参照がまだ残っている可能性があります。SearchClient.Instance.IndexManyAsync(objects, ...) 内のどこかで、まだオブジェクトへの参照を保持している必要があります。

この例では、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
于 2013-11-06T22:25:54.077 に答える