一、应用场景
在聚合新闻类项目中,历史新闻是很多的,每次爬虫新增的却相当地少,如果频繁地重建索引,执行时间会很久,而新闻具有及时性,需要“近实时”地更新索引,让新入库的新闻显示出来。
在这种情况下可以用所谓的“主索引+增量索引”(main+delta)模式来实现“近实时”的索引更新。
二、使用方法
这个模式实现的基本原理是设置两个数据源和两个索引,为那些基本不更新的数据建立主索引,而对于那些新增的数据建立增量索引。主索引的更新频率可以设置的长一些(例如设置在每天的午夜进行),而增量索引的更新频率,我们可以将时间设置的很短(几分钟左右),这样在用户搜索的时候,我们可以同时查询这两个索引的数据。
2.1.建立索引
内容表sql
CREATE TABLE `news_content_item` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`source_id` int(11) DEFAULT NULL COMMENT '内容源id',
`tag` varchar(200) DEFAULT NULL COMMENT '标签',
`column` varchar(200) DEFAULT NULL COMMENT '专栏',
`title` varchar(200) NOT NULL DEFAULT '' COMMENT '标题',
`alias` varchar(200) NOT NULL DEFAULT '' COMMENT '别名、副标题',
`desc` text COMMENT '摘要',
`origin` varchar(50) DEFAULT NULL COMMENT '新闻内容的来源,如:人民日报',
`origin_url` varchar(200) DEFAULT NULL COMMENT '新闻来源对应的url',
`detail_url` varchar(2000) DEFAULT NULL COMMENT '详情url',
`media_data` text COMMENT '图片或者视频信息保存字段,json数组',
`usable` tinyint(5) DEFAULT '1' COMMENT '使用可用,默认可用',
`weight` int(11) DEFAULT '0' COMMENT '运营权重',
`orig_weight1` int(11) DEFAULT '0' COMMENT '内容权重1',
`orig_weight2` int(11) DEFAULT '0' COMMENT '内容权重2`',
`c_time` bigint(1) NOT NULL DEFAULT '0' COMMENT '数据入库时间',
`u_time` datetime DEFAULT NULL COMMENT '数据更新时间',
`content_u_time` datetime DEFAULT NULL COMMENT '内容的更新时间',
`dl_count` int(11) DEFAULT '0' COMMENT '新闻被下载或者访问的次数',
`content_type` varchar(50) DEFAULT NULL COMMENT '内容分类',
`content` longtext COMMENT '详细内容',
PRIMARY KEY (`id`),
KEY `spider-unique` (`source_id`,`detail_url`(255))
) ENGINE=InnoDB DEFAULT CHARSET=utf8
在数据库中增加一个计数表,记录每次重新构建主索引时,被索引表最新内容的更新时间,这样在增量索引时只需要索引这个时间以后的数据即可,每次重新构建主索引时都更新这个表。因为数据入库后除id外其他属性有可能被修改,所以采用修改时间u_time作为计数依据。一般会涉及多个索引,所以计数表结构如下
CREATE TABLE `sph_counter` (
`idx`char(40) NOT NULL COMMENT '索引名称',
`max_doc_id` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT'最新更新时间',
UNIQUE KEY `uni_idx` (`idx`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
主索引和增量索引配置:
# 新闻数据源配置
source webpage_news_content_item : base
{
sql_query_pre = replace into sph_counter SELECT 'news_content_item_idx', MAX(u_time) FROM news_content_item
sql_query_pre = SET NAMES utf8
sql_query = SELECT ci.`id` as `id`, ci.title, ci.`tag` as `tag`, ci.`c_time` as `create_date` FROM `news_content_item` ci, `content_source`
sql_query_post = replace into sph_counter SELECT 'news_content_item_idx', MAX(u_time) FROM news_content_item
#属性字段
sql_attr_uint = create_date
}
index news_content_item_idx
{
source = webpage_news_content_item
path = /tmp/webpage/data/news/index
docinfo = extern
min_word_len = 1
charset_type = zh_cn.utf-8
charset_dictpath = /tmp/webpage/dict
}
# 增量新闻数据源配置
source webpage_news_content_item_delta : base
{
sql_query_pre = SET NAMES utf8
sql_query_killlist = SELECT id FROM news_content_item WHERE `usable`=0
sql_query = SELECT ci.`id` as `id`, ci.title as title, ci.`tag` as `tag`, ci.`c_time` as `create_date` FROM `news_content_item` ci WHERE ci.`usable`=1 and u_time > (SELECT max_doc_id from sph_counter where idx='news_content_item_idx')
sql_query_post = replace into sph_counter SELECT 'news_content_item_idx', DATE_ADD((SELECT MAX(u_time) FROM news_content_item), INTERVAL -1MINUTE)
sql_attr_uint = create_date
}
index news_content_item_idx_delta : news_content_item_idx
{
source = webpage_news_content_item_delta
path = /tmp/webpage/data/news_delta/index
}
2.2 索引合并
合并两个已有索引有时比重新索引所有数据有效,虽然,索引合并时,待合并的两个索引都会被读入内存一次,合并后的内容需写入磁盘一次,即,合并100GB和1GB的两个所以,将 导致202GB的IO操作
命令原型:
indexer --merge DSTINDEX SRCINDEX [--rotate] 将SRCINDEX合并到 DSTINDEX ,所以只有DSTINDEX会改变。
命令:
indexer --config webpage_sphinx.conf --merge-killlists --rotate --merge news_content_item_idx news_content_item_idx_delta
三、验证效果
测试增量索引是否成功,往数据库表中插入数据,查找是否能够检索到,这个时候检索应该为空,然后,单独重建delta索引查看是否将新的记录进行了索引。如果成功,此时,再用search 工具来检索,能够看到,在main索引中检索到的结果为0,而在delta中检索到结果。合并索引后,在main索引上也可以搜索到结果。
文档:26195 docs, 3.6 MB
主索引执行时间:2.102s
新增文档:1417 docs, 0.2 MB
增量索引执行时间:0.212s
索引合并时间:0.885s