C#中的Lucene序列化程序需要性能建议
我正在尝试构建一个Lucene序列化程序类,该类将序列化/反序列化对象(类),对象(类)的属性由DataMember修饰,特殊属性包含如何在Lucene索引中存储属性/字段的指令 当我需要通过某个键/值对检索单个对象时,该类工作正常。 但我注意到,如果有时我需要检索所有项目,比如说有100000个文档,那么MySQL的检索速度大约要快10倍。。。出于某种原因 请您(Lucene专家)回顾一下这段代码,并提出任何与性能相关的改进意见好吗C#中的Lucene序列化程序需要性能建议,c#,serialization,reflection,lucene,C#,Serialization,Reflection,Lucene,我正在尝试构建一个Lucene序列化程序类,该类将序列化/反序列化对象(类),对象(类)的属性由DataMember修饰,特殊属性包含如何在Lucene索引中存储属性/字段的指令 当我需要通过某个键/值对检索单个对象时,该类工作正常。 但我注意到,如果有时我需要检索所有项目,比如说有100000个文档,那么MySQL的检索速度大约要快10倍。。。出于某种原因 请您(Lucene专家)回顾一下这段代码,并提出任何与性能相关的改进意见好吗 public IEnumerable<T> Lo
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;
}
public IEnumerable LoadAll()
{
IndexReader=IndexReader.Open(this.PathToLuceneIndex);
int itemscont=reader.NumDocs();
对于(int i=0;i
提前谢谢你 以下是一些提示:
首先,不要使用IndexReader.Open(字符串路径)
。它不仅会在Lucene.net的下一个主要版本中被删除,而且通常不是您的最佳选择。当您让Lucene为您生成目录时,实际上会调用大量不必要的代码。我建议:
var dir = new SimpleFSDirectory(new DirectoryInfo(path));
var reader = IndexReader.Open(dir, true);
您还应该像我上面所做的那样,以只读方式打开IndexReader
,如果您不一定需要对其进行写入,因为它在多线程环境中会更快
如果您知道索引的大小不超过内存容量(即小于500-600 MB且未压缩),则可以使用RAMDirectory
。这将把整个索引加载到内存中,如果您将索引留在磁盘上,就可以绕过大部分代价高昂的IO操作。它应该大大提高你的速度,特别是如果你按照下面的其他建议来做的话
如果索引太大,无法放入内存,则需要将索引拆分为块(即每n MBs一个索引),或者继续从磁盘读取它
另外,我知道您不能在try…catch
中产生返回,但您可以在try…finally
中,我建议您将LoadAll()
中的逻辑包装成try…finally
,如
IndexReader reader = null;
try
{
//logic here...
}
finally
{
if (reader != null) reader.Close();
}
现在,当涉及到实际的反序列化代码时,您可能正在以几乎最快的方式进行反序列化,除了在不需要时装箱字符串。Lucene仅将字段存储为字节[]数组或字符串。因为您正在调用字符串值,所以您知道它将始终是一个字符串,并且只有在绝对必要时才需要将其装箱。将其更改为:
string fieldValue = myField.StringValue();
这至少有时会为你节省一点拳击费用。(真的,不多)
关于装箱主题,我们正在研究lucene的一个分支,您可以从SVN中获取它,它将lucene的内部结构从使用装箱容器(ArrayList、非泛型列表和哈希表)更改为使用泛型和更为.net友好的内容的版本。这是。正如我们常说的,网络化了。我们还没有正式对它进行基准测试,但开发人员测试表明,在某些情况下,它比旧版本快200%左右
另一件需要记住的事情是,Lucene是一个伟大的搜索引擎,你可能会发现在某些情况下,它可能无法与MySQL相媲美。但实际上,唯一确定的方法是测试并尝试找到性能瓶颈,就像我上面提到的一些瓶颈一样
希望有帮助!不要忘记Lucene.Net邮件列表(Lucene Net-dev@lucene.apache.org),如果你有任何问题。我和其他提交人通常能快速回答问题。谢谢您的评论。我已经按照建议实现了RAMDirectory,而阅读器是只读的。。。装箱成本并不显著,我将尝试通过调整Activator.CreateInstance()来挤出更多的性能;以及找到通过反射设置属性值的最快方法。有没有比document doc=reader.document(i);?更快的方法获取/读取文档因为,例如,对于我的文档集,检索100000个项目需要大约700毫秒。。。这是在创建对象实例(新)、转换日期时间和布尔值(从字符串转换为..)、设置反射值等之前进行的。这是获取文档的首选方法。获取文档的部分问题在于,加载文档时,字段会加载到内存中。在我看来,Lucene应该总是惰性地加载文档字段,但是当前版本的Lucene没有这样做。您可以使用MapFieldSelector,只选择您知道需要的字段,或者向其传递一个包含字符串、FieldSelector或Result
的字典,您可以告诉它加载某些字段。您最终将不得不加载所需的数据,因此这只是推迟了成本。好的,太好了,谢谢。。还有FieldSelectorResult