随笔 - 3458, 文章 - 0, 评论 - 739, 阅读 - 1188万
  管理

OSChina 是如何处理索引的更新问题?

Posted on   lzhdim  阅读(649)  评论(0编辑  收藏  举报

一般使用 Lucene 来做全文搜索时,都会碰到这样一个问题,什么时候创建、更新或者删除索引。

假设是发帖子吧,如果一发贴就即时写入索引,好处是索引及时,但这会引起索引库被锁的问题,因为同一个时间可能很多人都在发帖,更新和删除都是同样的问题存在。

还有另外一个方法是后台定时将新增的帖子写入索引库,这种可以避免索引库被锁的问题,不过刚发的帖子就没法被索引到(这个不是大问题,一般都可以接受),但是对一些帖子的修改和删除,处理起来就比较麻烦,你不知道哪些帖子被改了,或者被删了。

OSChina 现在的做法是引入一个 LuceneTask 类,代表要执行的一次索引任务,这个任务可以是添加、修改或者删除,每次新增帖子、修改帖子或者删除帖子时,只是对应的往数据库的一个表里写入一条 LuceneTask 数据即可。而后台通过 crontab 每隔一分钟从 LuceneTask 表中检索出待处理的索引任务记录,处理完毕后将该记录的状态改为已完成。

LuceneTask 类的代码如下:

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 实现索引的各类项目,所以贴出来分享一下。

编辑推荐:
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2025年3月3日 星期一 【蛇】己卯月辛未日 乙巳年 二月初四 全国爱耳日
您的IP:3.15.193.22,操作系统:未知操作系统,浏览器:未知浏览器
Copyright (C) 2000-2025 Lzhdim Software All Rights Reserved
点击右上角即可分享
微信分享提示