FieldCache с часто обновляемым индексом - PullRequest
2 голосов
/ 28 марта 2011

ПриветУ меня есть индекс lucene, который часто обновляется новыми записями, у меня есть 5 000 000 записей в моем индексе, и я кэширую одно из своих числовых полей, используя FieldCache.но после обновления индекса потребуется время, чтобы перезагрузить FieldCache снова (я перезагружаю кэш, поскольку документация говорит, что DocID ненадежен), так как я могу минимизировать эти издержки, добавляя только новые добавленные DocID в FieldCache, потому что эта возможность превращается в узкое место в моемapplication.


IndexReader reader = IndexReader.Open(diskDir);
int[] dateArr = FieldCache_Fields.DEFAULT.GetInts(reader, "newsdate"); // This line takes 4 seconds to load the array
dateArr = FieldCache_Fields.DEFAULT.GetInts(reader, "newsdate"); // this line takes 0 second as we expected
// HERE we add some document to index and we need to reload the index to reflect changes

reader = reader.Reopen();
dateArr = FieldCache_Fields.DEFAULT.GetInts(reader, "newsdate"); // This takes 4 second again to load the array

Я хочу механизм, который минимизирует это время, добавляя только новые документы в индекс в нашем массиве, и существует метод, подобный этому http://invertedindex.blogspot.com/2009/04/lucene-dociduid-mapping-and-payload.html, который повышает производительность, но все жезагрузите все документы, которые у нас уже есть, и я думаю, что нет необходимости перезагружать их все, если мы найдем способ только добавления вновь добавленных документов в массив

Ответы [ 2 ]

4 голосов
/ 30 марта 2011

FieldCache использует слабые ссылки на считыватели индекса в качестве ключей для своего кэша.(При вызове IndexReader.GetCacheKey, который не устарел.) Стандартный вызов IndexReader.Open с FSDirectory будет использовать пул считывателей, по одному на каждый сегмент.

Вы должны всегда передавать самые внутренниечитатель к FieldCache.Проверьте ReaderUtil на некоторые вспомогательные материалы для извлечения отдельного читателя, в котором содержится документ.Идентификаторы документа не будут меняться в пределах сегмента, что они имеют в виду, когда описывают его как непредсказуемый / изменчивый, что он будет меняться между двумя фиксациями индекса.Удаленные документы могли быть распознаны, сегменты были объединены, и такие действия.

При фиксации необходимо удалить сегмент с диска (объединено / оптимизировано), что означает, что у новых читателей не будет считывателя из объединенных сегментови сборщик мусора удалит его, как только все старые читатели закроются.

Никогда, никогда не звоните FieldCache.PurgeAllCaches().Он предназначен для тестирования, а не для производственного использования.

Добавлено 2011-04-03;пример кода с использованием подчитывающих.

var directory = FSDirectory.Open(new DirectoryInfo("index"));
var reader = IndexReader.Open(directory, readOnly: true);
var documentId = 1337;

// Grab all subreaders.
var subReaders = new List<IndexReader>();
ReaderUtil.GatherSubReaders(subReaders, reader);

// Loop through all subreaders. While subReaderId is higher than the
// maximum document id in the subreader, go to next.
var subReaderId = documentId;
var subReader = subReaders.First(sub => {
    if (sub.MaxDoc() < subReaderId) {
        subReaderId -= sub.MaxDoc();
        return false;
    }

    return true;
});

var values = FieldCache_Fields.DEFAULT.GetInts(subReader, "newsdate");
var value = values[subReaderId];
1 голос
/ 28 марта 2011

Вот один из способов, которым я решил эту проблему. Вам нужно будет создать фоновый поток для создания IndexSearcher экземпляров, по одному за определенный промежуток времени. Продолжайте использовать текущий экземпляр IndexSearcher, пока не будет готов новый экземпляр из фонового потока. Затем замените новый на текущий. Каждый экземпляр действует как моментальный снимок индекса с момента его первого открытия. Обратите внимание, что накладные расходы памяти для FieldCache удваиваются, потому что вам нужно два экземпляра в памяти одновременно. Вы можете спокойно написать IndexWriter, пока это происходит.

Если вам нужно, вы можете сделать этот шаг дальше, сделав изменения индекса, немедленно доступные для поиска, хотя это может быть сложно. Вам нужно будет связать RAMDirectory с каждым экземпляром снимка выше, чтобы сохранить изменения в памяти. Затем создайте второй IndexWriter, который указывает на это RAMDirectory. Для каждой записи индекса вам нужно записать оба экземпляра IndexWriter. Для поиска вы будете использовать MultiSearcher через RAMDirectory и ваш обычный индекс на диске. RAMDirectory можно выбросить, если IndexSearcher, с которым он был связан, больше не используется. Я здесь приукрашиваю некоторые детали, но это общая идея.

Надеюсь, это поможет.

...