Сериализатор Lucene в C #, нужен совет по производительности - PullRequest
0 голосов
/ 10 августа 2011

Я пытаюсь создать класс 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;
}

Заранее спасибо!

1 Ответ

1 голос
/ 10 августа 2011

Вот несколько советов:

Во-первых, не используйте IndexReader.Open(string path). Мало того, что это будет удалено в следующем основном выпуске Lucene.net, это вообще не ваш лучший вариант. Там на самом деле тонна ненужного кода вызывается, когда вы позволяете Lucene генерировать каталог для вас. Я предлагаю:

var dir = new SimpleFSDirectory(new DirectoryInfo(path));
var reader = IndexReader.Open(dir, true);

Вы также должны сделать то же, что я делал выше, и открыть IndexReader как доступный только для чтения, если вам совершенно не нужно писать в него, так как это будет быстрее в многопоточных средах, особенно.

Если вы знаете, что размер вашего индекса не превышает объем, который вы можете хранить в памяти (т. Е. Менее 500-600 МБ и не сжат), вы можете использовать RAMDirectory вместо этого. Это загрузит весь индекс в память, что позволит вам обойти большинство дорогостоящих операций ввода-вывода, если вы оставляли индекс на диске. Это должно значительно улучшить вашу скорость, особенно если вы сделаете это с другими советами ниже.

Если индекс слишком велик, чтобы поместиться в памяти, вам нужно либо разбить его на куски (т. Е. Индекс каждые n МБ), либо просто продолжить читать его с диска.

Кроме того, я знаю, что вы не можете yield return в try...catch, но вы можете в try...finally, и я бы рекомендовал заключить вашу логику в LoadAll() в try...finally, как

IndexReader reader = null;
try
{
     //logic here...
}
finally
{
    if (reader != null) reader.Close();
}

Теперь, когда дело доходит до вашего фактического кода десериализации, вы, вероятно, делаете это почти самым быстрым из возможных способов, за исключением того, что вы упаковываете строку, когда вам это не нужно. Lucene сохраняет поле только в виде массива byte [] или строки. Так как вы вызываете строковое значение, вы знаете, что оно всегда будет строкой, и его нужно будет заполнить только в случае крайней необходимости. Измените это на это:

string fieldValue = myField.StringValue();

Это, по крайней мере, иногда спасает вас от незначительных затрат на бокс. (правда, не очень)

По теме бокса мы работаем над веткой lucene, которую вы можете извлечь из SVN, которая меняет внутреннюю часть Lucene с использования контейнеров-контейнеров (ArrayLists, неуниверсальных списков и HashTables) на версию, в которой используются универсальные шаблоны. и более .net-дружественные вещи. Это ветка 2.9.4g . .Net'ified, как мы хотели бы сказать. Мы официально не тестировали его, но тесты разработчиков показали, что в некоторых случаях он примерно на 200% быстрее, чем в старых версиях.

Еще одна вещь, которую стоит иметь в виду, Lucene великолепен как поисковая система, вы можете обнаружить, что в некоторых случаях он может не соответствовать MySQL. Правда, единственный способ узнать наверняка - это просто протестировать и попытаться найти узкие места в производительности, как некоторые из упомянутых выше.

Надеюсь, это поможет! Не забывайте о списке рассылки Lucene.Net (lucene-net-dev@lucene.apache.org), если у вас есть какие-либо вопросы. Я и другие коммиттеры, как правило, быстро отвечают на вопросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...