基于lucene的案例开发:实时索引管理类IndexManager

释放双眼,带上耳机,听听看~!

链接地址

个人的博客小站也搭建成功,网址:www.llwjy.com/blog.php ,欢迎大家来吐槽~

      在前一篇博客中,对实时索引的实现原理做了一些简单的介绍,这里就介绍下,如何利用Lucene来实现索引的管理(Lucene中已经实现了大部分的功能,我们只需要对其再次封装即可)。

逐个击破

      在Lucene4.3.1中,实现实时索引时,需要将IndexWrite的相关操作委托给TrackingIndexWriter来处理,具体代码实现如下:

ps:关于如何创建索引这里就不再介绍了,可以参照之前的博客或者该博客后面的完整代码。


1
2
1this.trackingIndexWriter = new TrackingIndexWriter(this.indexWriter);
2

1
2
1        同时初始化索引管理对象,代码如下:  
2

1
2
1this.nrtManager = new NRTManager(this.trackingIndexWriter, new SearcherFactory());
2

1
2
1        到这里还需要开启两个守护线程:内存索引重读线程和内存数据commit线程。内存索引重读线程执行的频率也就是实时索引的时差,由于内存中的数据不会太多,所以这个延时一般也就是在十几毫秒左右;内存数据commit线程是将内存中的数据写到磁盘上,不至于数据丢失,如果研究过Lucene源码的童鞋也许会发现,即使你不执行commit操作,到内存中的数据达到一定的程度,也会将一部分数据写到磁盘上,只不过重启服务这部分数据就丢失了同时还会造成一系列的问题, [链接地址](http://bbs.csdn.net/topics/390677902) 这个地址下就是commit线程死掉之后造成的一系列问题,感兴趣的童鞋可以了解下。
2

      内存重读线程我们只需要配置下参数启动即可,代码如下:


1
2
3
4
5
6
1this.nrtManagerReopenThread = new NRTManagerReopenThread(this.nrtManager, indexReopenMaxStaleSec, indexReopenMinStaleSec);
2this.nrtManagerReopenThread.setName("NRTManager Reopen Thread");
3this.nrtManagerReopenThread.setPriority(Math.min(Thread.currentThread().getPriority()+2, Thread.MAX_PRIORITY));
4this.nrtManagerReopenThread.setDaemon(true);
5this.nrtManagerReopenThread.start();
6

1
2
1        内存数据commit线程需要自己写代码实现,然后启动该线程即可,代码如下:
2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1private class IndexCommitThread extends Thread{
2   private boolean flag;
3   public IndexCommitThread(String name){
4       super(name);
5   }
6  
7   @SuppressWarnings("deprecation")
8   public void run(){
9       flag = true;
10      while(flag) {
11          try {
12              indexWriter.commit();
13              if (bprint) {
14                  System.out.println(new Date().toLocaleString() + "\t" + IndexManagerName + "\tcommit");
15              }
16              TimeUnit.SECONDS.sleep(indexCommitSeconds);
17          } catch (IOException e) {
18              e.printStackTrace();
19          } catch (InterruptedException e1) {
20              e1.printStackTrace();
21          }
22      }
23  }
24}
25

1
2
3
4
1this.indexCommitThread = new IndexCommitThread(IndexManagerName + "Index Commit Thread");
2this.indexCommitThread.setDaemon(true);
3this.indexCommitThread.start();
4

1
2
1        那又如何像普通的索引那样使用IndexSearcher呢?当然NrtManager类也提供了相关的方法,可以获取最新可用的IndexSearcher,代码如下:
2

1
2
3
4
5
6
7
8
9
1public IndexSearcher getIndexSearcher(){
2   try {
3       return this.nrtManager.acquire();
4   } catch (IOException e) {
5       e.printStackTrace();
6       return null;
7   }
8}
9

1
2
1        当然在使用之后别忘记释放,代码如下:
2

1
2
3
4
5
6
7
8
9
1public void release(IndexSearcher searcher){
2   try {
3       nrtManager.release(searcher);
4   } catch (IOException e) {
5       // TODO Auto-generated catch block  
6       e.printStackTrace();
7   }
8}
9

1
2
1  **另类单例模式**  
2

      在之前的博客中,我也多次提到,加载索引是一个相当消耗资源的事情,所以我们不可能每一次索引操作都加载一次索引,所以我们就必须使用单例模式来实现IndexManager类。这里的单例模式又和我们常见的单例模式有所区别,普通的单例模式该类只有一个对象,这里的单例模式是该类有多个对象,下面就简单的介绍下此处另类的单例模式。

      通过前一篇博客最后,你也许会注意到,系统中关于索引的配置信息是存在HashSet对象中,这也就是说这里IndexManager类会实例化多少次取决于HashSet对象,也就是你配置文件让他实例化多少次就会实例化多少次。既然这样,怎么还能叫单例模式呢?这里的单例是索引的单例,也就是说一个索引只有一个IndexManager对象,不会存在两个IndexManager对象去操作同一个索引的情况。具体代码实现如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1/**
2 * Initialization on Demand Holder式初始化IndexManager
3 */
4private static class LazyLoadIndexManager {
5   private static final HashMap<String, IndexManager> indexManager = new HashMap<String, IndexManager>();
6  
7   static {
8       for (ConfigBean configBean : IndexConfig.getConfigBean()) {
9           indexManager.put(configBean.getIndexName(), new IndexManager(configBean));
10      }
11  }
12}
13
14/**  
15 *@Description: IndexManager私有构造方法
16 *@Author: lulei  
17 *@Version: 1.1.0  
18 */
19private IndexManager(ConfigBean configBean){
20  //...
21}
22public static IndexManager getIndexManager(String indexName){
23  return LazyLoadIndexManager.indexManager.get(indexName);
24}
25

1
2
1        这样我们就可以通过索引名获取到该索引的IndexManager对象。  
2

庐山真面目

      说了这么多,下面就把IndexManager的源码附在最后,感兴趣的童鞋可以试试(里面还有一些其他的方法,相信不用介绍也都可以看的懂)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
1/**  
2 *@Description: 索引管理类  
3 */
4package com.lulei.lucene.index.manager;  
5
6import java.io.File;
7import java.io.IOException;
8import java.util.Date;
9import java.util.HashMap;
10import java.util.concurrent.TimeUnit;
11
12import org.apache.lucene.analysis.Analyzer;
13import org.apache.lucene.index.IndexWriter;
14import org.apache.lucene.index.IndexWriterConfig;
15import org.apache.lucene.index.IndexWriterConfig.OpenMode;
16import org.apache.lucene.search.IndexSearcher;
17import org.apache.lucene.search.NRTManager;
18import org.apache.lucene.search.NRTManager.TrackingIndexWriter;
19import org.apache.lucene.search.NRTManagerReopenThread;
20import org.apache.lucene.search.SearcherFactory;
21import org.apache.lucene.store.Directory;
22import org.apache.lucene.store.NIOFSDirectory;
23import org.apache.lucene.util.Version;
24
25import com.lulei.lucene.index.model.ConfigBean;
26import com.lulei.lucene.index.model.IndexConfig;
27
28public class IndexManager {
29
30  private IndexWriter indexWriter;
31  //更新索引文件的IndexWriter
32  private TrackingIndexWriter trackingIndexWriter;
33  //索引文件采用的分词器
34  private Analyzer analyzer;
35  //索引管理对象
36  private NRTManager nrtManager;
37  //索引重读线程
38  private NRTManagerReopenThread nrtManagerReopenThread;
39  //索引写入磁盘线程
40  private IndexCommitThread indexCommitThread;
41 
42  //索引地址
43  private String indexPath;
44  //索引重读最大、最小时间间隔
45  private double indexReopenMaxStaleSec;
46  private double indexReopenMinStaleSec;
47  //索引commit时间
48  private int indexCommitSeconds;
49  //索引名
50  private String IndexManagerName;
51  //commit时是否输出相关信息
52  private boolean bprint = true;
53 
54  /**
55   * Initialization on Demand Holder式初始化IndexManager
56   */
57  private static class LazyLoadIndexManager {
58      private static final HashMap<String, IndexManager> indexManager = new HashMap<String, IndexManager>();
59     
60      static {
61          for (ConfigBean configBean : IndexConfig.getConfigBean()) {
62              indexManager.put(configBean.getIndexName(), new IndexManager(configBean));
63          }
64      }
65  }
66 
67  /**  
68   *@Description: IndexManager私有构造方法
69   *@Author: lulei  
70   *@Version: 1.1.0  
71   */
72  private IndexManager(ConfigBean configBean){
73      //设置相关属性
74      analyzer = configBean.getAnalyzer();
75      indexPath = configBean.getIndexPath();
76      IndexManagerName = configBean.getIndexName();
77      indexReopenMaxStaleSec = configBean.getIndexReopenMaxStaleSec();
78      indexReopenMinStaleSec = configBean.getIndexReopenMinStaleSec();
79      indexCommitSeconds = configBean.getIndexCommitSeconds();
80      bprint = configBean.isBprint();
81      String indexFile = indexPath + IndexManagerName + "/";
82      //创建或打开索引
83      IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_43, analyzer);
84      indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
85      Directory directory = null;
86      try {
87          directory = NIOFSDirectory.open(new File(indexFile));
88          if (IndexWriter.isLocked(directory)){
89              IndexWriter.unlock(directory);
90          }
91          this.indexWriter = new IndexWriter(directory, indexWriterConfig);
92          this.trackingIndexWriter = new TrackingIndexWriter(this.indexWriter);
93          this.nrtManager = new NRTManager(this.trackingIndexWriter, new SearcherFactory());
94      } catch(IOException e){
95          e.printStackTrace();
96      }
97      //开启守护进程
98      this.setThread();
99  }
100 /**
101  * @Author: lulei  
102  * @Description: 创建索引管理线程
103  */
104 private void setThread(){
105     this.nrtManagerReopenThread = new NRTManagerReopenThread(this.nrtManager, indexReopenMaxStaleSec, indexReopenMinStaleSec);
106     this.nrtManagerReopenThread.setName("NRTManager Reopen Thread");
107     this.nrtManagerReopenThread.setPriority(Math.min(Thread.currentThread().getPriority()+2, Thread.MAX_PRIORITY));
108     this.nrtManagerReopenThread.setDaemon(true);
109     this.nrtManagerReopenThread.start();
110    
111     this.indexCommitThread = new IndexCommitThread(IndexManagerName + "Index Commit Thread");
112     this.indexCommitThread.setDaemon(true);
113     this.indexCommitThread.start();
114 }
115
116 /**
117  * @return
118  * @Author:lulei  
119  * @Description: 重启索引commit线程
120  */
121 public String setCommitThread() {
122     try {
123         if (this.indexCommitThread.isAlive()){
124             return "is alive";
125         }
126         this.indexCommitThread = new IndexCommitThread(IndexManagerName + "Index Commit Thread");
127         this.indexCommitThread.setDaemon(true);
128         this.indexCommitThread.start();
129     } catch (Exception e) {
130         e.printStackTrace();
131         return "failed";
132     }
133     return "reload";
134 }
135
136 /**
137  *@Description: 索引commit线程
138  *@Author: lulei  
139  *@Version: 1.1.0
140  */
141 private class IndexCommitThread extends Thread{
142     private boolean flag;
143     public IndexCommitThread(String name){
144         super(name);
145     }
146    
147     @SuppressWarnings("deprecation")
148     public void run(){
149         flag = true;
150         while(flag) {
151             try {
152                 indexWriter.commit();
153                 if (bprint) {
154                     System.out.println(new Date().toLocaleString() + "\t" + IndexManagerName + "\tcommit");
155                 }
156                 TimeUnit.SECONDS.sleep(indexCommitSeconds);
157             } catch (IOException e) {
158                 e.printStackTrace();
159             } catch (InterruptedException e1) {
160                 e1.printStackTrace();
161             }
162         }
163     }
164 }
165
166
167 /**
168  * @return IndexManager
169  * @Author: lulei  
170  * @Description: 获取索引管理类
171  */
172 public static IndexManager getIndexManager(String indexName){
173     return LazyLoadIndexManager.indexManager.get(indexName);
174 }
175
176 /**
177  * @@Description:释放IndexSearcher资源
178  * @param searcher
179  */
180 public void release(IndexSearcher searcher){
181     try {
182         nrtManager.release(searcher);
183     } catch (IOException e) {
184         // TODO Auto-generated catch block  
185         e.printStackTrace();
186     }
187 }
188
189 /**
190  * @return IndexSearcher
191  * @Author: lulei  
192  * @Description: 返回IndexSearcher对象,使用完之后,调用release方法进行释放
193  */
194 public IndexSearcher getIndexSearcher(){
195     try {
196         return this.nrtManager.acquire();
197     } catch (IOException e) {
198         e.printStackTrace();
199         return null;
200     }
201 }
202
203 public NRTManager getNRTManager(){
204     return this.nrtManager;
205 }
206
207 public IndexWriter getIndexWriter(){
208     return this.indexWriter;
209 }
210
211 public TrackingIndexWriter getTrackingIndexWriter(){
212     return this.trackingIndexWriter;
213 }
214
215 public Analyzer getAnalyzer(){
216     return analyzer;
217 }
218
219 /**
220  * @return
221  * @Author: lulei  
222  * @Description: 获取索引中的记录条数
223  */
224 public int getIndexNum(){
225     return indexWriter.numDocs();
226 }
227}
228

1
2
1  ps:最近发现其他网站可能会对博客转载,上面并没有源链接,如想查看更多关于 [http://www.aiuxian.com/catalog/p-322798.html]() 请 [http://www.aiuxian.com/catalog/p-322798.html]()。或访问网址http://blog.csdn.net/xiaojimanman/article/category/2841877 或 [链接地址](http://www.llwjy.com/blog.php)
2

给TA打赏
共{{data.count}}人
人已打赏
安全运维

OpenSSH-8.7p1离线升级修复安全漏洞

2021-10-23 10:13:25

安全运维

设计模式的设计原则

2021-12-12 17:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索