簡體   English   中英

在Lucene中,如何判斷IndexSearcher或IndexWriter是否在另一個線程中使用?

[英]In Lucene, how can I find out if the IndexSearcher or IndexWriter is being used in another thread or not?

Lucene文檔指出,IndexSearcher和IndexWriter的單個實例應該用於整個應用程序中的每個索引,以及所有線程。 此外,在重新打開索引之前,對索引的寫入將不可見。

所以,我試圖在多線程設置中遵循這些指南。 (一些線程編寫,多個用戶線程搜索)。 我不想在每次更改時重新打開索引,而是希望保持搜索器實例不超過一定的時間(比如20秒)。

中央組件負責打開索引讀取器和編寫器,並保留單個實例並同步線程。 我跟蹤上次任何用戶線程訪問IndexSearcher的時間,以及它變臟的時間。 如果有人需要在更改過去20秒后訪問它,我想關閉搜索器並重新打開它。

問題是我不確定先前對搜索者(由其他線程制作)的請求是否已經完成,因此我可以關閉IndexSearcher。 這意味着如果我關閉並重新打開在所有線程之間共享的單個IndexSearcher實例,則可能會在其他某個線程中同時進行搜索。

更糟糕的是,這是理論上可能發生的事情:可以同時執行多次搜索。 (假設有數千名用戶在同一索引上運行搜索)。 單個IndexSearcher實例可能永遠不會被釋放,因此可以關閉它。 理想情況下,我想創建另一個IndexSearcher並將新請求指向它(雖然舊的仍然打開並運行之前已請求的搜索)。 當舊實例上運行的搜索完成后,我想關閉它。

同步IndexSearcher(或IndexWriter)的多個用戶以調用close()方法的最佳方法是什么? Lucene是否為此提供任何功能/設施,或者它應該完全由用戶代碼完成(比如使用搜索器計算線程,並在每次使用時增加/減少計數)?

有關於上述設計的任何建議/想法嗎?

值得慶幸的是,在最近的版本(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.

作家可以用同樣的方式處理。 我傾向於記得定期關閉作者,以便讀者注意到它的變化(提交它)。 我沒有很好地描述這一點,但它的搜索方式大致相同。 如果有活躍的作家,你就無法關閉作家。 如果你是出門的最后一位作家關閉作家。 你明白了。

有一個相對較新的SearcherManager類可以解決這個問題,並且可以完全隱藏代碼中的IndexReader 盡管API可能會發生變化,但我認為這大大簡化了事情。

來自Lucene項目指揮官Mike McCandless的基本教程: http ://blog.mikemccandless.com/2011/09/lucenes-searchermanager-simplifies.html

如果實際索引已更改,您只想創建一個新的閱讀器。 我做的是保留對IndexReader的引用,並在我重新編譯索引后刪除它。 那是因為我希望能夠在索引編制期間進行搜索,而且我相信你在編寫時無法打開IndexReader(如果我錯了,請糾正我)。

如果沒有可用的應用程序,我讓應用程序創建一個新的讀取器,因此它是一種在每次索引提交后被釋放的緩存。

如果您需要實時索引功能(在idnexing oepration期間在當前索引的實體中搜索),您可以使用getReader()方法從當前IndexWriter獲取IndexReader。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM