问题:在提供的代码中,我试图索引~26000 个地理围栏(多边形)。我尝试了许多组合 1)插入数据和 2)为简洁起见,为代码中未显示的数据编制索引。我已经使用预建索引导入了所有数据;导入数据然后制作索引并制作索引并部分导入数据并等待非陈旧索引。在所有情况下,它都会耗尽所有内存并失败(失败是指我等待 30 分钟以完成索引过程)。一个有趣的观察发生在带有预建索引的部分插入中:它总是开始消耗大约 1790 个条目的所有内存。
环境:我在 2 台机器上测试过:1) 4 GB Ram,双核 2.56 CUP 2) 12 GB Ram,i7 CPU。我使用 Visual Studio 2012(这应该不重要)针对 .NET 4.0 和 RavenDB build 2230。这里使用的唯一外部库(RavenDB 客户端库除外)是 NetTopologySuite (NuGet)。
旁注和背景:我正在使用 2 个内存数据结构进行空间计算:一个 KD-Tree 和一个带有静态数据的 R-Tree(无插入/删除/更新)。现在我的项目中添加了一个新步骤,需要每天两次更新/插入一些数据;因此,我寻找替代品以消除这部分的内务负担,并提出了 SQLite R-Tree 模块。它足够快(使用一些并行编程+它是一个主要是只读数据库)。到目前为止,RavenDB 的选择并不多(战略决策等),但我喜欢玩它,结果令人失望。准确地说,我喜欢 RavenDB 960,我真的对 RavenDB 2230 很生气。
我使用了内存树并使用约 3,000,000 个多边形(再次准确地说是“边界框”)测试了 SQLite,但未能将 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)
};
}
}
}