Подтвердить что ты не робот

Concurrency в Lucene.NET.

Я хочу использовать Lucene.NET для полнотекстового поиска, разделяемого между двумя приложениями: один - приложение ASP.NET MVC, а другое - консольное приложение. Оба приложения должны искать и обновлять индекс. Как обращаться с concurrency?
Я нашел учебник по ifdefined.com, где обсуждается аналогичный вариант использования. Меня беспокоит то, что блокировка будет большим узким местом.

PS: Также я заметил, что IndexSearcher использует моментальный снимок индекса, и в упомянутом выше руководстве искатель создается только при обновлении индекса. Это хороший подход? Могу ли я просто создать обычный поисковый объект при каждом поиске, и если да, то какие накладные расходы?

Я нашел связанный с ним вопрос Ли Lucene.Net управляет несколькими потоками, обращаясь к одному и тому же индексу, одна индексирует, а другая ищет?, что утверждает, что interprocess concurrency безопасен. Означает ли это, что это не условия гонки для индекса?

Также один очень важный аспект. Каким будет влияние производительности, если пусть говорят, что 10-15 потоков пытаются обновить индекс Lucene, получив общую блокировку, представленную в это решение?

После использования нескольких месяцев я должен добавить, что индекс открытия для поиска часто может создавать исключение OutOfMemory при высоких загрузках центрального процессора и памяти, если запрос использует сортировку. Стоимость операции открытия индекса небольшая (по моему опыту), но стоимость GC может быть довольно высокой.

4b9b3361

Ответ 1

Прежде всего, мы должны определить операцию "write". Операция записи будет блокировать блокировку после запуска операции записи и будет продолжаться до тех пор, пока вы не закроете объект, выполняющий работу. Такие, как создание IndexWriter и индексация документа, заставят писать объект блокировки, и он будет удерживать эту блокировку до тех пор, пока вы не закроете IndexWriter.

Теперь мы можем немного поговорить о замке. Эта блокировка, которая является объектом, является блокировкой на основе файлов. Как упоминалось ранее мифом, существует файл, называемый "write.lock", который создается. Как только блокировка записи заблокирована, она является исключительной! Эта блокировка вызывает все операции модификации индекса (IndexWriter и некоторые методы из IndexReader) до тех пор, пока блокировка не будет удалена.

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

1) Возможное решение # 1 Прямые операции

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

2) Возможное решение # 2 Веб-сервис

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

3) создайте еще один индекс, затем слейте

Если приложение консоли действительно сильно работает с индексом, вы можете посмотреть, как консольное приложение может создать отдельный индекс в консольном приложении, а затем объединить индексы в определенное безопасное запланированное время с помощью IndexWriter.AddIndexes.

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

4) Индекс и поиск нескольких индексов

Лично я считаю, что людям нужно отделять свои индексы. Это помогает отделить обязанности от программ и минимизировать время простоя и поддерживать единую точку для всех индексов. Например, если ваше консольное приложение отвечает только за добавление в определенных полях или ваше расширение расширяет индекс, вы можете разглядеть отдельные индексы, но сохраните личность, используя поле идентификатора в каждом документе. Теперь вы можете воспользоваться встроенной поддержкой поиска нескольких индексов с использованием класса MultiSercher. Или, если вы хотите, есть также класс ParallelMultiSearch, который может одновременно искать оба индекса.

5) Посмотрите на SOLR

Что-то еще, что может помочь вам в сохранении одного места для вашего индекса, вы можете изменить свою программу для работы с сервером SOLR. http://lucene.apache.org/solr/ есть также хороший SOLRNET http://code.google.com/p/solrnet/ библиотека, которая может быть полезна в этой ситуации. Хотя у меня нет опыта с solr, но у меня создается впечатление, что это поможет вам управлять ситуацией, такой как это. Кроме того, он имеет другие преимущества, такие как выделение ярлыков и поиск связанных предметов путем поиска элементов "MoreLikeThis" или обеспечения проверки орфографии.

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

Ответ 2

У меня также есть индекс поиска lucene, который используется несколькими клиентами, я решу эту проблему, сделав "Lucene Search Service" отдельным веб-сервисом, работающим в своем собственном домене приложений. Поскольку оба клиента попадают в один и тот же веб-сервис для поиска или обновления индекса, я могу сделать его потокобезопасным с блокировками на Lucene Indexers.

Кроме того, если вы хотите сохранить его в процессе, я предлагаю использовать блокировки файлов, чтобы убедиться, что только один клиент может записать в индекс.

Чтобы получить его, чтобы использовать новый индекс, я создаю его на стороне, а затем сообщаю службе Search Index об обмене, чтобы использовать новый индекс, безопасно удаляя любые индексы в текущем индексе и переименовывая каталоги, например

  • Index.Current > Index.Old
  • Index.New > Index.Current

Ответ 3

Если у вас будет несколько авторов в разных процессах, и они потратят более 10 секунд, записывая свои изменения в индекс (что вызовет ожидания ожидающих авторов), вы можете синхронизировать доступ через процессы, используя named Мьютексы. Просто откройте/создайте Mutex одного и того же глобального имени в каждом приложении и используйте Mutex.WaitOne перед записью и Mutex.ReleaseMutex после записи.

var mut = Mutex.OpenExisting("myUniqueMutexName"); // wrap in try..catch to create if non-existent
mut.WaitOne();
try {
  // write logic
}
finally {
  // recover from write failure
  mut.ReleaseMutex();
}

Вероятно, лучше сделать Mutex одним синглом, так как они немного дороже построить.

Обновить (за комментарий):

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

var iw = new IndexWriter();
iw.WRITE_LOCK_TIMEOUT = 60000;

Вы также можете просто пробовать определенное количество раз.

var committed = false;
var attempts = 0;
while(!committed && attempts < 10) {
  try {
    // write logic
    committed = true;
  } catch (LockObtainFailedException) {
    attempts++;
  }
}