• Lucene知识总结


    (1) Lucene查询上只能提供近实时而非实时查询,原因是Segment在被flush或commit之前,数据保存在内存中,是不可被搜索的。

    (2) IndexWriter提供的核心接口都是线程安全的,并且内部做了特殊的并发优化来优化多线程写入的性能。IndexWriter内部为每个线程都会单独开辟一个空间来写入,这块空间由DocumentsWriterPerThread(简称DWPT)来控制。整个多线程数据处理流程为:

      1. 多线程并发调用IndexWriter的写接口,在IndexWriter内部具体请求会由DocumentsWriter来执行。DocumentsWriter内部在处理请求之前,会先根据当前执行操作的Thread来分配DocumentsWriterPerThread。

      2. 每个线程在其独立的DocumentsWriterPerThread空间内部进行数据处理,包括分词、相关性计算、索引构建等。

      3. 数据处理完毕后,在DocumentsWriter层面执行一些后续动作,例如触发FlushPolicy的判定等。

    引入DWPT后,Lucene内部在处理数据时,整个处理步骤只需要对以上第一步和第三步进行加锁,第二步完全不用加锁,每个线程都在自己独立的空间内处理数据。而通常来说,第一步和第三步都是非常轻量级的,而第二步是对计算和内存资源消耗最大的。所以这样做之后,能够将加锁的时间大大缩短,提高并发的效率。每个DWPT内单独包含一个In-memory buffer,这个buffer最终会flush成不同的独立的segment文件。

    (3) flush:flush是将DWPT内In-memory buffer里的数据持久化到文件的过程,flush会在每次新增文档后由FlushPolicy判定自动触发,也可以通过IndexWriter的flush接口手动触发。每个DWPT会flush成一个segment文件,flush完成后这个segment文件是不可被搜索的,只有在commit之后,所有commit之前flush的文件才可被搜索。

    (4) commit:commit时会触发数据的一次强制flush,commit完成后再此之前flush的数据才可被搜索。commit动作会触发生成一个commit point,commit point是一个文件。Commit point会由IndexDeletionPolicy管理,lucene默认配置的策略只会保留last commit point,当然lucene提供其他多种不同的策略供选择。

    (5) merge:merge是对segment文件合并的动作,合并的好处是能够提高查询的效率以及回收一些被删除的文档。Merge会在segment文件flush时触发MergePolicy来判定自动触发,也可通过IndexWriter进行一次force merge。

    (6) close:close = commit + flush + merge

    (7) 单线程内,相同的IndexWriter对象,一并commit或先后commit都没有问题。

    (8) 单线程内,不同的IndexWriter对象,如果对象A还未close就操作对象B,结果抛出异常(LockObtainFailedException),如果对象A close后再操作对象B则没有问题。

    (9) 多线程环境下,相同的IndexWriter对象,先后commit没有问题(线程安全)。

    (10) 多线程环境下,不同的IndexWriter对象,道理同(7),close一个才能操作另外一个。

    (11) 单线程内,IndexWriter操作完成后commit才能使用IndexReader,多线程环境下则没有问题。

    (12) 在Web环境下,IndexReader(IndexSearcher)和IndexWriter都推荐使用单例模式(消耗较大,线程安全)。下面是一个标准例子。

     1 package XXX;
     2 
     3 import lombok.extern.slf4j.Slf4j;
     4 import org.apache.lucene.analysis.Analyzer;
     5 import org.apache.lucene.analysis.standard.StandardAnalyzer;
     6 import org.apache.lucene.index.DirectoryReader;
     7 import org.apache.lucene.index.IndexReader;
     8 import org.apache.lucene.index.IndexWriter;
     9 import org.apache.lucene.index.IndexWriterConfig;
    10 import org.apache.lucene.search.IndexSearcher;
    11 import org.apache.lucene.store.Directory;
    12 import org.apache.lucene.store.FSDirectory;
    13 import org.springframework.beans.factory.annotation.Value;
    14 import org.springframework.stereotype.Service;
    15 import org.springframework.transaction.annotation.Transactional;
    16 
    17 import java.io.IOException;
    18 import java.nio.file.Paths;
    19 
    20 @Service
    21 @Slf4j
    22 public class LuceneService {
    23 
    24     @Value("${app.property.index-dir}")
    25     private String indexDir;
    26 
    27     private Directory directory;
    28 
    29     private IndexReader indexReader;
    30 
    31     private IndexWriter indexWriter;
    32 
    33     /**
    34      * Get Directory.
    35      *
    36      * @return Directory
    37      */
    38     private synchronized Directory getDirectory() {
    39         if (directory == null) {
    40             try {
    41                 directory = FSDirectory.open(Paths.get(indexDir));
    42             } catch (IOException e) {
    43                 throw new RuntimeException("Create Directory failed!", e);
    44             }
    45         }
    46         return directory;
    47     }
    48 
    49     /**
    50      * Get IndexReader/IndexSearcher.
    51      *
    52      * @return IndexReader
    53      */
    54     public synchronized IndexReader getIndexReader() {
    55         try {
    56             if (indexReader == null) {
    57                 indexReader = DirectoryReader.open(getDirectory());
    58             } else {
    59                 IndexReader newReader = DirectoryReader.openIfChanged((DirectoryReader) indexReader);
    60                 if (newReader != null) {
    61                     // close the old indexReader
    62                     indexReader.close();
    63                     indexReader = newReader;
    64                 }
    65             }
    66             return indexReader;
    67         } catch (IOException e) {
    68             throw new RuntimeException("Create IndexReader failed!", e);
    69         }
    70     }
    71 
    72     /**
    73      * Get IndexSearcher.
    74      * Recommend instead of IndexReader.
    75      *
    76      * @return IndexReader
    77      */
    78     public IndexSearcher getIndexSearcher() {
    79         return new IndexSearcher(getIndexReader());
    80     }
    81 
    82     /**
    83      * Get IndexWriter.
    84      *
    85      * @return IndexWriter
    86      */
    87     public synchronized IndexWriter getIndexWriter() {
    88         if (indexWriter == null) {
    89             Analyzer analyzer = new StandardAnalyzer();
    90             IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
    91             try {
    92                 indexWriter = new IndexWriter(getDirectory(), indexWriterConfig);
    93             } catch (IOException e) {
    94                 throw new RuntimeException("Create IndexWriter failed!", e);
    95             }
    96         }
    97         return indexWriter;
    98     }
    99 }
  • 相关阅读:
    imx6 关闭调试串口
    imx6 Image Vector Table (IVT)
    imx6 DDR_Stress_Test
    java安装1.8和1.7,报错:Error: Registry key 'SoftwareJavaSoftJava Runtime Environment'CurrentVers
    maven安装与环境变量配置
    14.商品添加功能
    MyBatis 接口的使用
    MyBatis 的缓存机制
    MyBatis 别名标签 & sql的复用
    MyBatis 多表查询
  • 原文地址:https://www.cnblogs.com/storml/p/14915037.html
Copyright © 2020-2023  润新知