Lucene知识总结

摘要:
Lucene查询只能提供接近实时的查询,而不能提供实时查询,因为段的数据在刷新或提交之前存储在内存中,无法搜索。在处理请求之前,DocumentsWriter根据当前执行操作的线程分配DocumentsWriterPerThread。引入DWPT后,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 }

免责声明:文章转载自《Lucene知识总结》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇mysql关于char和varchar的查询效率问题vm安装centos7 Minimal 配置静态ip添加dns: 解决连不上网下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java实现文件夹下文件实时监控

一、commons-io方法 1、使用Commons-io的monitor下的相关类可以处理对文件进行监控,它采用的是观察者模式来实现的 (1)可以监控文件夹的创建、删除和修改 (2)可以监控文件的创建、删除和修改 (3)采用的是观察者模式来实现的 (4)采用线程去定时去刷新检测文件的变化情况 2、引入commons-io包,需要2.0以上。 ?...

apache2添加模块和添加站点

apache2添加模块和添加站点 linux下的apache2的目录和windows上的区别还是很大的,但是用起来却更方便了,详解请看另一篇文章http://www.cnblogs.com/wancy86/p/linux_apache2.html 这里补充两个命令: 添加模块: model_name是mods-available 下的模块名 sudo a2...

liteos 从入门到放弃

这两天收到一份sdk,hisi 3516cv200 liteos的sdk 正好手头有硬件,就随便编译玩玩. 解压sdk. Hi3518E_SDK_V5.0.5.0 ll@ubuntu:~/work2016/liteos/Hi3518E_SDK_V5.0.5.0$ ls -lh total 32K drwxrwxr-x 4 ll ll 4.0K Oct 25...

windows添加右键菜单

哔哔 有时候想要用websotrm打开一个项目, 有时候想要用VScode打开,最快的方法就是右键指定打开方式了这些软件安装的时候会自带,但如果有些软件没有自带右键项,就得去注册表里手动添加这些东西也不好搜,索性自己记一下,免得下次忘了 -------------2020-12-31更新-------------------今天发现了一个使用js脚本的快捷...

.Net Core System.IO.Compression.ZipFile实现Zip格式压缩和Zip格式解压缩

一、安装Nuget包 System.IO.Compression.ZipFile Install-package System.IO.Compression.ZipFile 二、ZipFile 类使用 简单操作方法: ZipFile.CreateFromDirectory()---压缩 ZipFile.ExtractToDirectory()---解压缩...

oracle expdp/impdp 用法详解

http://hi.baidu.com/hzfsai/item/4a4b3fc4b1cf7e51ad00efbd oracle expdp/impdp 用法详解 Data Pump 反映了整个导出/导入过程的完全革新。不使用常见的 SQL 命令,而是应用专用 API(direct path api etc) 来以更快得多的速度加载和卸载数据。1.Data...