問題: 提示されたコードでは、約 26000 のジオフェンス (ポリゴン) のインデックスを作成しようとしています。簡潔にするために、1) データの挿入と 2) データのインデックス作成の多くの組み合わせを試しましたが、一部はコードに示されていません。事前に作成されたインデックスを使用してすべてのデータをインポートしました。データをインポートしてからインデックスを作成し、インデックスを作成して、古くないインデックスを待ってデータを部分的にインポートします。いずれの場合も、すべてのメモリを消費して失敗します (失敗とは、インデックス作成プロセスが完了するまで 30 分間待機することを意味します)。事前に構築されたインデックスを使用した部分挿入で、興味深い観察が 1 つ発生しました。常に ~1790 エントリあたりですべてのメモリを消費し始めます。
環境: 私はこれを 2 台のマシンでテストしました: 1) 4 GB RAM、デュアルコア 2.56 CUP 2) 12 GB RAM、i7 CPU。私は Visual Studio 2012 (これは重要ではありません) を使用して、RavenDB ビルド 2230 で .NET 4.0 をターゲットにしました。ここで使用した唯一の外部ライブラリ (RavenDB クライアント ライブラリ以外) は NetTopologySuite (NuGet) でした。
補足と背景: 私は 2 つのメモリ内データ構造を使用して空間計算を行っています: KD ツリーと静的データを含む R ツリー (挿入/削除/更新なし)。プロジェクトに新しいステップが追加され、1 日に 2 回データを更新/挿入する必要があります。そのため、この部分のハウスキーピングの負担を取り除く代替品を探し、SQLite R-Tree モジュールを思いつきました。十分に高速です (いくつかの並列プログラミングを使用し、ほとんどが読み取り専用のデータベースです)。これまでのところ、RavenDB は選択の余地がありません (戦略的決定など) が、私は RavenDB で遊ぶのが好きで、がっかりしました。正確に言うと、私は RavenDB 960 が大好きで、RavenDB 2230 には本当に腹を立てています。
インメモリ ツリーを使用し、SQLite を ~3,000,000 ポリゴン (正確には「バウンディング ボックス」) でテストしましたが、RavenDB を ~26,000 ポリゴンで使用できませんでした。私は何かひどく間違ったことをしていることを本当に願っています。
コード:
namespace MyApp
{
static partial class Program
{
static void Main(string[] args)
{
Initialization();
InitializeIndexes();
// MODE 1:
// OneTimeImport(-1, 1024, true);
// MODE 2:
// OneTimeImport(-1, 1024, false);
// MODE 3:
// PartialImport(64); and PartialImport(32); and PartialImport(16);
}
static void PartialImport(int len)
{
bool finished = false;
int index = 0;
// read finished from file
if (finished)
{
return;
}
// read index from file, if not exists then set it to 0
index = OneTimeImport(index, len, true);
if (index == 0)
{
finished = true;
}
// write index and finished to file
return;
}
static int OneTimeImport(int start, int len, bool waitForIndexing)
{
var counter = start < 0 ? 0 : start;
using (var reader = new StreamReader(@"D:\PATH\DATA.TXT", Encoding.UTF8))
using (var session = Store.OpenSession())
{
session.Advanced.MaxNumberOfRequestsPerSession = int.MaxValue - 1;
if (len < 0) len = 16;
IEnumerable<string> lines = null;
if (start < 0) { lines = reader.Lines(); }
else { lines = reader.Lines().Skip(start).Take(len); }
foreach (var line in lines)
{
var parts = line.Split(new string[] { "|" }, StringSplitOptions.None);
var lm = new Area();
lm.Description = parts[5];
var poly = string.Empty;
if (!string.IsNullOrWhiteSpace(parts[8]))
{
try
{
var list = new List<Coordinate>();
var pairs = parts[8].Split(';');
foreach (var p in pairs)
{
var coor = p.Split(',');
var lon = coor[0].ToDouble();
var lat = coor[1].ToDouble();
list.Add(new Coordinate(lon, lat));
}
if (list.Count > 0)
{
list.Add(list[0]);
var ring = new LinearRing(list.ToArray());
poly = new Polygon(ring).ToString();
}
}
catch { } // some logging
}
lm.Polygon = poly;
session.Store(lm);
counter++;
if (counter % len == 0)
{
session.SaveChanges();
if (waitForIndexing) while (Store.DatabaseCommands.GetStatistics().StaleIndexes.Length > 0) Thread.Sleep(10);
}
Trace.WriteLine(counter);
}
session.SaveChanges();
if (waitForIndexing) while (Store.DatabaseCommands.GetStatistics().StaleIndexes.Length > 0) Thread.Sleep(500);
}
return counter;
}
static void Initialization()
{
Store = new DocumentStore { ConnectionStringName = "LoxConnectionString" };
Store.Initialize();
}
static void InitializeIndexes()
{
IndexCreation.CreateIndexes(typeof(Program).Assembly, Store);
}
public static IEnumerable<string> Lines(this StreamReader reader)
{
string line = null;
while ((line = reader.ReadLine()) != null) yield return line;
}
public static double ToDouble(this string s)
{
double d = 0;
double.TryParse(s, out d);
return d;
}
public static DocumentStore Store { get; private set; }
}
public class Area
{
public string Id { get; set; }
public string Description { get; set; }
public string Polygon { get; set; }
}
public class AreaIndex : AbstractIndexCreationTask<Area>
{
public AreaIndex()
{
Map = docs => from doc in docs
select new
{
doc.Description,
_ = SpatialGenerate("AreaPolygon", doc.Polygon)
};
}
}
}