В Lucene, как я могу узнать, используется ли IndexSearcher или IndexWriter в другом потоке или нет? - PullRequest
2 голосов
/ 19 ноября 2011

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

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

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

Проблема в том, что я не уверен в предыдущих запросах поисковика (сделано другими потоками) еще не закончена, так что я могу закрыть IndexSearcher.Это означает, что если я закрою и снова открою один экземпляр IndexSearcher, который используется всеми потоками, то в каком-то другом потоке может одновременно выполняться поиск.

Что еще хуже, вот что может произойтитеоретически: может быть несколько поисков, выполняемых в одно и то же время все время.(предположим, у вас есть тысячи пользователей, выполняющих поиск по одному индексу).Один экземпляр IndexSearcher может никогда не стать свободным, чтобы его можно было закрыть.В идеале я хочу создать еще один IndexSearcher и направить ему новые запросы (пока старый еще открыт и выполняет запросы, уже запрошенные ранее).Когда поиск по старому экземпляру завершен, я хочу закрыть его.

Каков наилучший способ синхронизации нескольких пользователей IndexSearcher (или IndexWriter) для вызова метода close ()?Предоставляет ли Lucene какие-либо функции / возможности для этого, или это должно быть полностью выполнено с помощью пользовательского кода (например, подсчет потоков с помощью поискового устройства и увеличение / уменьшение количества при каждом его использовании)?

Есть ликакие-либо рекомендации / идеи по поводу вышеупомянутого дизайна?

Ответы [ 3 ]

9 голосов
/ 19 ноября 2011

К счастью, в последних версиях (3.x или поздней версии 2.x) они добавили метод, чтобы сообщить вам, было ли какое-либо письмо после открытия поисковика. IndexReader.isCurrent () сообщит вам, произошли ли какие-либо изменения с момента открытия этой программы или нет. Таким образом, вы, вероятно, создадите простой класс-обертку, который инкапсулирует как чтение, так и запись, и с некоторой простой синхронизацией вы можете предоставить 1 класс, который управляет всем этим между всеми потоками.

Вот примерно то, что я делаю:

  public class ArchiveIndex {
      private IndexSearcher search;
      private AtomicInteger activeSearches = new AtomicInteger(0);
      private IndexWriter writer;
      private AtomicInteger activeWrites = new AtomicInteger(0);

      public List<Document> search( ... ) {
          synchronized( this ) {
              if( search != null && !search.getIndexReader().isCurrent() && activeSearches.get() == 0 ) {
                 searcher.close();
                 searcher = null;
              }

              if( search == null ) {
                  searcher = new IndexSearcher(...);
              }
          }

          activeSearches.increment();
          try {
              // do you searching
          } finally {
              activeSearches.decrement();
          }
          // do you searching
      }


      public void addDocuments( List<Document> docs ) {
          synchronized( this ) {
             if( writer == null ) {
                 writer = new IndexWriter(...);
             }
          }
          try {
              activeWrites.incrementAndGet();
              // do you writes here.
          } finally {
              synchronized( this ) {
                  int writers = activeWrites.decrementAndGet();
                  if( writers == 0 ) {
                      writer.close();
                      writer = null;
                  }
              }
          }
      }
  }

Итак, у меня есть один класс, который я использую как для читателей, так и для писателей. Обратите внимание, что этот класс позволяет писать и читать одновременно, и несколько читателей могут выполнять поиск одновременно. Единственная синхронизация - это быстрые проверки, чтобы увидеть, нужно ли вам снова открыть поисковик / писатель. Я не синхронизировал на уровне методов, который позволял бы только одному читателю / писателю за раз, что было бы плохой производительностью. Если есть активные поисковики, вы не можете отказаться от поисковика. Так что, если к вам придет много читателей, просто выполните поиск без изменений. Как только он иссякнет, следующий одинокий искатель снова откроет грязный искатель. Это может быть полезно для сайтов с небольшим объемом, где будет пауза в трафике. Это все еще может вызвать голод (то есть вы всегда читаете все более и более старые результаты). Вы можете добавить логику, чтобы просто остановить и повторно инициализировать, если время, которое было замечено как грязное, старше X, в противном случае мы ленивы, как сейчас. Таким образом, вам гарантированно, что поиск никогда не будет старше X.

С писателями можно обращаться практически одинаково. Я часто вспоминаю закрытие писателя, чтобы читатель мог заметить его изменение (зафиксировать). Я не очень хорошо описал это, но это почти тот же способ поиска. Если есть активные писатели, вы не можете закрыть писателя. Если вы последний писатель, закройте писателя. Вы поняли идею.

2 голосов
/ 26 июля 2012

Существует относительно новый класс SearcherManager, который решает эту проблему и может полностью скрыть IndexReader из вашего кода. Хотя API, возможно, может быть изменен, я считаю, что это сильно упрощает вещи.

Базовое руководство от Майк МакКэндлесс , комментатор проекта Lucene: http://blog.mikemccandless.com/2011/09/lucenes-searchermanager-simplifies.html

0 голосов
/ 19 ноября 2011

Вы захотите создать новый считыватель, только если фактический индекс изменился.Что я сделал, так это сохранил ссылку на IndexReader и отбросил ее после переиндексации.Это потому, что я хочу иметь возможность поиска во время индексации, и я считаю, что вы не можете открыть IndexReader во время записи (поправьте меня, если я ошибаюсь).

Я разрешаю приложению создавать новое средство чтения, если его нет, так что это своего рода кэширование, которое располагается после каждой фиксации индекса.

Если вам нужны возможности индексирования в реальном времени (поиск средив настоящее время индексируемые сущности во время операции idnexing), вы можете получить IndexReader из текущего IndexWriter, используя метод getReader ().

...