链接地址
个人的博客小站也搭建成功,网址:www.llwjy.com/blog.php ,欢迎大家来吐槽~
在前一篇博客中,对实时索引的实现原理做了一些简单的介绍,这里就介绍下,如何利用Lucene来实现索引的管理(Lucene中已经实现了大部分的功能,我们只需要对其再次封装即可)。
逐个击破
在Lucene4.3.1中,实现实时索引时,需要将IndexWrite的相关操作委托给TrackingIndexWriter来处理,具体代码实现如下:
ps:关于如何创建索引这里就不再介绍了,可以参照之前的博客或者该博客后面的完整代码。
1 2
| 1this.trackingIndexWriter = new TrackingIndexWriter(this.indexWriter);
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 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 |
在之前的博客中,我也多次提到,加载索引是一个相当消耗资源的事情,所以我们不可能每一次索引操作都加载一次索引,所以我们就必须使用单例模式来实现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 |