C#中的Lucene序列化程序需要性能建议

C#中的Lucene序列化程序需要性能建议,c#,serialization,reflection,lucene,C#,Serialization,Reflection,Lucene,我正在尝试构建一个Lucene序列化程序类,该类将序列化/反序列化对象(类),对象(类)的属性由DataMember修饰,特殊属性包含如何在Lucene索引中存储属性/字段的指令 当我需要通过某个键/值对检索单个对象时,该类工作正常。 但我注意到,如果有时我需要检索所有项目,比如说有100000个文档,那么MySQL的检索速度大约要快10倍。。。出于某种原因 请您(Lucene专家)回顾一下这段代码,并提出任何与性能相关的改进意见好吗 public IEnumerable<T> Lo

我正在尝试构建一个Lucene序列化程序类,该类将序列化/反序列化对象(类),对象(类)的属性由DataMember修饰,特殊属性包含如何在Lucene索引中存储属性/字段的指令

当我需要通过某个键/值对检索单个对象时,该类工作正常。 但我注意到,如果有时我需要检索所有项目,比如说有100000个文档,那么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;
}
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