2016-02-29 55 views
0

我需要在Lucene中添加文档后立即使用我的结果。我读的所有内容都说我应该缓存IndexSearcher实例,但是我没有看到如何在每次写入时重新打开IndexReader并因此IndexSearcher无法实现我想要的内容...Lucene NRT - 每次提交后都打开一个新的IndexReader?

我在做什么错了?

class LuceneStorage { 

    private final Directory luceneDirectory; 
    private final IndexWriter indexWriter; 

    private volatile DirectoryReader indexReader; 

    LuceneStorage() { 
     try { 
      this.luceneDirectory = NIOFSDirectory.open(Paths.get(System.getProperty("user.home")).resolve("lucene")); 

      IndexWriterConfig config = new IndexWriterConfig(new KeywordAnalyzer()); 
      config.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND); 

      this.indexWriter = new IndexWriter(luceneDirectory, config); 
      this.indexReader = DirectoryReader.open(indexWriter); 
     } catch (IOException e) { 
      throw new UncheckedIOException(e); 
     } 
    } 

    public Stream<String> read(String id) { 
     IndexSearcher indexSearcher = new IndexSearcher(indexReader); 
     QueryParser queryParser = new QueryParser("id", new KeywordAnalyzer()); 
     StreamableSimpleCollector collector = new StreamableSimpleCollector(); 

     try { 
      indexSearcher.search(queryParser.parse(id), collector); 
     } catch (Exception e) { 
      throw new IllegalStateException(e); 
     } 

     IntStream docIds = collector.stream(); 

     return docIds.mapToObj(i -> { 
       try { 
        return indexSearcher.doc(i).get("content"); 
       } catch (IOException e) { 
        throw new UncheckedIOException(e); 
       } 
      }); 
    } 

    public String write(String content, String... ids) { 
     String uuid = UUID.randomUUID().toString(); 

     Document document = new Document(); 
     document.add(new StringField("id", uuid, Field.Store.YES)); 

     Stream.of(ids) 
      .forEach(i -> document.add(new StringField("id", i, Field.Store.YES))); 

     document.add(new StoredField("content", content)); 

     try { 
      indexWriter.addDocument(document); 
      indexReader = DirectoryReader.openIfChanged(indexReader); 
     } catch (IOException e) { 
      throw new UncheckedIOException(e); 
     } 

     return uuid; 
    } 
} 
+0

这些告诫的意义在于,您不用为每个查询*打开一个新的'IndexReader'。编写完成后,您需要重新打开以进行更改。创建一个新的IndexSearcher并不是特别昂贵。它打开了价格昂贵的'IndexReader'。 – femtoRgon

+0

@femtoRgon我想,为了满足我的要求,我必须在添加每个文档后打开一个'IndexReader'。 – Cheetah

+0

你有一个选项,可能对性能有帮助,你可以使用['openIfChanged(DirectoryReader oldReader,IndexWriter writer,boolean applyAllDeletes)'](https://lucene.apache.org/core/5_4_0/core/org /apache/lucene/index/DirectoryReader.html#openIfChanged(org.apache.lucene.index.DirectoryReader,%20org.apache.lucene.index.IndexWriter,%20boolean)),它允许您搜索未提交的更改(即没有关闭或委托作者)。 – femtoRgon

回答

0

Lucene不是为提供实时搜索结果而设计的。所以如果这真的是一个要求,你应该看看别的东西。

但是Lucene可以提供附近的实时搜索结果,所以你的用户将不得不等待, 1秒钟之后,更改才可搜索。做到这一点的方法是使用SearcherManager(http://lucene.apache.org/core/5_5_0/core/org/apache/lucene/search/SearcherManager.html),并有一个后台线程定期刷新当前的索引阅读器。

相关问题