c#中的Lucene序列化器,需要性能建议



我正在尝试构建一个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...catchyield 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),如果你有任何问题。我和其他提交者通常很快回答问题。

相关内容

  • 没有找到相关文章

最新更新