一般使用 Lucene 来做全文搜索时,都会碰到这样一个问题,什么时候创建、更新或者删除索引。
假设是发帖子吧,如果一发贴就即时写入索引,好处是索引及时,但这会引起索引库被锁的问题,因为同一个时间可能很多人都在发帖,更新和删除都是同样的问题存在。
还有另外一个方法是后台定时将新增的帖子写入索引库,这种可以避免索引库被锁的问题,不过刚发的帖子就没法被索引到(这个不是大问题,一般都可以接受),但是对一些帖子的修改和删除,处理起来就比较麻烦,你不知道哪些帖子被改了,或者被删了。
OSChina 现在的做法是引入一个 LuceneTask 类,代表要执行的一次索引任务,这个任务可以是添加、修改或者删除,每次新增帖子、修改帖子或者删除帖子时,只是对应的往数据库的一个表里写入一条 LuceneTask 数据即可。而后台通过 crontab 每隔一分钟从 LuceneTask 表中检索出待处理的索引任务记录,处理完毕后将该记录的状态改为已完成。
LuceneTask 类的代码如下:
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
|
package
net.oschina.search;
import
java.util.Date;
import
my.db.QueryHelper;
import
my.search.SearchEnabled;
import
net.oschina.beans.Article;
import
net.oschina.beans.Blog;
import
net.oschina.beans.News;
import
net.oschina.beans.Pojo;
import
net.oschina.beans.Project;
/**
* Lucene索引更新任务
* @author Winter Lau
* @date 2010-1-4 下午04:57:47
*/
public
class
LuceneTask
extends
Pojo {
public
final
static
transient
byte
OPT_ADD =
0x01
;
public
final
static
transient
byte
OPT_UPDATE =
0x02
;
public
final
static
transient
byte
OPT_DELETE =
0x04
;
/**
* 返回对应的对象资料
* @return
*/
public
SearchEnabled object(){
switch
(obj_type) {
case
TYPE_PROJECT:
return
(Project)Project.INSTANCE.Get(obj_id);
case
TYPE_NEWS:
return
(News)News.INSTANCE.Get(obj_id);
case
TYPE_THREAD:
return
net.oschina.beans.Thread.Read(obj_id);
case
TYPE_ARTICLE:
return
(Article)Article.INSTANCE.Get(obj_id);
case
TYPE_BLOG:
return
(Blog)Blog.INSTANCE.Get(obj_id);
}
return
null
;
}
public
void
afterBuild(){
String sql =
"UPDATE osc_lucene_tasks SET status=1,handle_time=NOW() WHERE id=?"
;
QueryHelper.update(sql, getId());
}
public
static
void
add(
long
obj_id,
byte
obj_type) {
new
LuceneTask(obj_id, obj_type, OPT_ADD).Save();
}
public
static
void
update(
long
obj_id,
byte
obj_type) {
new
LuceneTask(obj_id, obj_type, OPT_UPDATE).Save();
}
public
static
void
delete(
long
obj_id,
byte
obj_type) {
new
LuceneTask(obj_id, obj_type, OPT_DELETE).Save();
}
public
LuceneTask() {
}
public
LuceneTask(
long
obj_id,
byte
obj_type,
byte
opt) {
this
.obj_id = obj_id;
this
.obj_type = obj_type;
this
.opt = opt;
this
.status =
0
;
}
private
long
obj_id;
private
byte
obj_type;
private
byte
opt;
private
byte
status;
private
Date create_time;
private
Date handle_time;
public
long
getObj_id() {
return
obj_id;
}
public
void
setObj_id(
long
obj_id) {
this
.obj_id = obj_id;
}
public
byte
getObj_type() {
return
obj_type;
}
public
void
setObj_type(
byte
obj_type) {
this
.obj_type = obj_type;
}
public
byte
getOpt() {
return
opt;
}
public
void
setOpt(
byte
opt) {
this
.opt = opt;
}
public
byte
getStatus() {
return
status;
}
public
void
setStatus(
byte
status) {
this
.status = status;
}
public
Date getCreate_time() {
return
create_time;
}
public
void
setCreate_time(Date create_time) {
this
.create_time = create_time;
}
public
Date getHandle_time() {
return
handle_time;
}
public
void
setHandle_time(Date handle_time) {
this
.handle_time = handle_time;
}
}
|
其中 obj_id 代表帖子的编号,obj_type 代表帖子的类型,可以是帖子,可以是新闻,也可以是软件。
这个结构其实挺适合 Lucene 实现索引的各类项目,所以贴出来分享一下。
按默认排序 显示最新评论 共有14个评论 (最后回答: 1年前)
-
没有完整源码,小白表示看的云里雾里!
-
红薯您好,我现在一个项目需要用到lucene,我想在请教您一下, lucene更新索引的效率到底如何,比如:我目前数据库有30万,数据,估计从数据库查询取数据到创建索引完成会要多久呢?不考虑服务器性能方面的问题!
-
好像还有个机制就是增加或者更新的索引先写到内存里,每隔一定的时候与硬盘中索引合并
这样可以做到及时索引
但是如果出现down机了 内存中的索引就over了
-
真的顶一下。
-
关注...
-
这个想法,见过,哈哈