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

时间:2011-08-09 22:14:58

标签: c# serialization reflection lucene

我正在尝试构建一个Lucene Serializer类,它将使用DataMember修饰的属性序列化/反序列化对象(类),以及一个特殊属性,其中包含有关如何在Lucene索引中存储属性/字段的说明。 / p>

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

提前谢谢!

1 个答案:

答案 0 :(得分:1)

以下是一些提示:

首先,不要使用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一个索引)或者继续从磁盘读取索引。

另外,我知道yield return中你不能try...catch,但你可以try...finally,我建议你将LoadAll()中的逻辑包装成一个try...finally IndexReader reader = null; try { //logic here... } finally { if (reader != null) reader.Close(); } ,例如

string fieldValue = myField.StringValue();

现在,当谈到你的实际Deserialize代码时,你可能以几乎最快的方式完成它,除了你在不需要的时候装箱。 Lucene仅将字段存储为byte []数组或字符串。因为你正在调用字符串值,所以你知道它总是一个字符串,并且只有在绝对必要时才必须将其打包。将其更改为:

{{1}}

这至少有时可以节省你的小拳击费用。 (真的,不多)

关于拳击的主题,我们正在研究lucene的一个分支,你可以从SVN中提取,它将Lucene的内部结构从使用装箱容器(ArrayLists,非泛型列表和HashTables)更改为使用泛型的版本以及更多.net友好的东西。这是2.9.4g branch。正如我们所愿说的那样.Net'。我们尚未正式对其进行基准测试,但开发人员测试显示,在某些情况下,它比旧版本快了约200%。

另外要记住的是,Lucene作为一个搜索引擎很棒,你可能会发现在某些情况下,它可能无法与MySQL相提并论。但实际上,唯一可以确定的方法就是测试并尝试找到性能瓶颈,就像我上面提到的一些瓶颈一样。

希望有所帮助!如果您有任何疑问,请不要忘记Lucene.Net邮件列表(lucene-net-dev@lucene.apache.org)。我和其他提交者通常很快回答问题。