我正在尝试构建一个Lucene Serializer类,它将序列化/反序列化对象(类)的属性装饰为DataMember和一个特殊的属性,指示如何在Lucene索引中存储属性/字段。
当我需要通过某个键/值对检索单个对象时,该类工作得很好。但是我注意到,如果有时我需要检索所有条目,假设有100,000个文档,那么MySQL会快10倍左右……
请检查这段代码(Lucene专家),并建议任何可能的性能相关的改进想法?
public IEnumerable<T> LoadAll()
{
IndexReader reader = IndexReader.Open(this.PathToLuceneIndex);
int itemsCount = reader.NumDocs();
for (int i = 0; i < itemsCount; i++)
{
if (!reader.IsDeleted(i))
{
Document doc = reader.Document(i);
if (doc != null)
{
T item = Deserialize(doc);
yield return item;
}
}
}
if (reader != null) reader.Close();
}
private T Deserialize(Document doc)
{
T itemInstance = Activator.CreateInstance<T>();
foreach (string fieldName in fieldTypes.Keys)
{
Field myField = doc.GetField(fieldName);
//Not every document may have the full collection of indexable fields
if (myField != null)
{
object fieldValue = myField.StringValue();
Type fieldType = fieldTypes[fieldName];
if (fieldType == typeof(bool))
fieldValue = fieldValue == "1" ? true : false;
if (fieldType == typeof(DateTime))
fieldValue = DateTools.StringToDate((string)fieldValue);
pF.SetValue(itemInstance, fieldName, fieldValue);
}
}
return itemInstance;
}
提前感谢!
以下是一些建议:
首先,不要使用IndexReader.Open(string path)
。它不仅会在Lucene.net的下一个主要版本中被删除,而且通常也不是您的最佳选择。当你让Lucene为你生成目录时,实际上会调用大量不必要的代码。我建议:
var dir = new SimpleFSDirectory(new DirectoryInfo(path));
var reader = IndexReader.Open(dir, true);
你也应该像我上面所做的那样,把IndexReader
打开为只读,如果你不是绝对需要写的话,因为它在多线程环境中会更快。
如果您知道索引的大小不超过您可以保存到内存中(即小于500-600 MB且未压缩),您可以使用RAMDirectory
代替。这将把整个索引加载到内存中,如果您将索引留在磁盘上,则可以绕过大多数昂贵的IO操作。应该会大大提高你的速度,特别是如果你按照下面的建议去做的话。
如果索引太大,内存无法容纳,您要么需要将索引分成块(即每n mb一个索引),要么继续从磁盘读取它。
也,我知道你不能在try...catch
中yield return
,但你可以在try...finally
中,我建议将LoadAll()
中的逻辑包装成try...finally
,如
IndexReader reader = null;
try
{
//logic here...
}
finally
{
if (reader != null) reader.Close();
}
现在,当涉及到实际的反序列化代码时,您可能会以几乎最快的方式完成它,除了在不需要的时候对字符串进行装箱。Lucene只将字段存储为byte[]数组或字符串。因为你在调用string value,你知道它将永远是一个字符串,只有在绝对必要的时候才应该把它框起来。改成这样:
string fieldValue = myField.StringValue();
这至少有时会为您节省少量的拳击成本。(真的,不多)
关于装箱的话题,我们正在开发lucene的一个分支,你可以从SVN中拉出来,它改变了lucene的内部结构,从使用装箱容器(数组列表,非泛型列表和哈希表)到使用泛型和更多。net友好的东西。正如我们喜欢说的那样,这是. net具体化的2.9.4分支。我们还没有正式对其进行基准测试,但开发人员测试表明,在某些情况下,它比旧版本快了大约200%。
另一件要记住的事情是,Lucene作为一个搜索引擎是很棒的,你可能会发现在某些情况下,它可能比不上MySQL。实际上,唯一确定的方法是测试并尝试找到我上面提到的一些性能瓶颈。
希望有帮助!别忘了Lucene。Net邮件列表(lucene-net-dev@lucene.apache.org),如果你有任何问题。我和其他提交者通常很快回答问题。