Sphinx 被删除的索引怎么又出来啦?
2016-05-29
场景
按照之前的创建的索引, 我们已经基本进行搜索了, 但这个时候, 我们会发现, 有些已经被删除(标记)的索引, 为何在我们的搜索中还会出现呢, 甚至说已经被更新了状态的文档, 却搜到了老的状态文档
原因解析
我们使用增量的方式创建了索引, 假设是main
和delta
, 索引查询的时候指定的索引顺序是main delta
, 这样索引查询时会先在delta
中查询文档, 如果没有的话, 就会再到main
中查找。
一般情况下, 我们只是新增文档, 新增的这部分就在delta
中了, 老的则还在main
里, 如果我们只新增, 不更改状态(包括标记删除), 那么我们可以正常的搜索, 不会有问题, 可一旦有在main
中的数据状态更新了,且新的状态文档在delta
中,那我们搜索这条文档的时候就会出现问题, 老的状态就可能被搜出来(包括标记删除)
解决方式
索引创建时, 在sphinx相关索引的source
中配置 sql_query_killlist
sql_query_killlist
会创建一个文档id列表,与某个索引项绑定在一起,用于隐藏从另一个索引中出现的结果,比如上面, 在delta
中设置这个参数, 那么这部分冲突的数据就会只在delta
中查找, 而忽略main
中的
实践
首先我们把之前的索引配置修改一下, 把 is_del
这个状态值加到索引中
- 修改
article
和article_delta
的source
, 把is_del
添加到sql_query
中 - 在
article
的source
中设置sql_attr_uint = is_del
修改部分如下
source article:src_db{
sql_query = select id,title, content, cid, is_del, unix_timestamp(ctime) ctime,\
unix_timestamp(mtime) mtime from article
sql_query_post = replace into sysconfig (varname, info, value) select \
"article_delta","article delta time node", max(mtime) from article
sql_attr_uint = cid
sql_field_string = title
sql_field_string = content
sql_attr_timestamp = ctime
sql_attr_timestamp = mtime
sql_attr_uint = is_del
}
source article_delta:article
{
sql_query = select id,title, content, cid, is_del, unix_timestamp(ctime) ctime,\
unix_timestamp(mtime) mtime from article where mtime >= \
(select value from sysconfig where varname = "article_delta")
sql_query_post = SET NAMES UTF8
}
这里修复一下以前的一个算是bug
的地方, 在article_delta
中, 我们要重置sql_query_post
, 否则delta
中也会继承main
的 sql_query_post
, 这样就会导致第二次delta
创建数据为空了(因为每次增量创建时,增量的时间起始点应该是不变的)
然后重建所有的索引即可
然后我们来重现一下开始的场景
场景重现
首先, 我们的索引里有且仅有一个文档包含了关键字全是红包啊
, 我们将其搜索出来, 并要求是未删除的is_del=0
python test.py -p 3316 -i "article article_delta" -f "is_del" -v 0 "全是红包啊"
结果如下
1. doc_id=3, weight=6, title=全是红包啊, content=<p>都在发红啊<img width="530" height="340" src="http://api.map.baidu.com/staticimage?center=116.404,39.915&zoom=10&width=530&height=340&markers=116.404,39.915"/> </p>, cid=1, is_del=0, ctime=2015-12-23 08:15:44, mtime=2016-05-30 00:44:11
因为标题里有这个关键字了,为求简单,我们都把结果中的content字段去除
1. doc_id=3, weight=6, title=全是红包啊, cid=1, is_del=0, ctime=2016-05-30 00:44:11, mtime=2016-05-30 00:39:21
然后, 我们将原始数据(mysql)的这条文档的is_del
值做修改, 刷新mtime
, 并重建delta
索引,
然后再执行上面的搜索
python test.py -p 3316 -i "article article_delta" -f "is_del" -v 0 "全是红包啊"
我们依然能搜结果,即便是已经被删除了的, 但时间(mtime)却是旧的索引时间
1. doc_id=3, weight=6, title=全是红包啊, cid=1, is_del=0, ctime=2015-12-23 08:15:44, mtime=2016-05-30 00:42:48
这样,我们就把场景重现出来了
sql_query_killlist 设置
现在, 我们来设置这个参数, 试试能不能达到预期
在 article_delta
的 source
中设置
sql_query_killlist = select id from article where mtime > (select value from \
sysconfig where varname = "article_delta")
这样, 所有的增量文档的id 就能在 sql_query_killlist
了, 增量数据也就不会与老的数据冲突了
配置好后,把所引发服务重启, 并重建article
和article_delta
索引(索引配置修改了)。
为了后面验证这个设置,我们把在重建索引之前, 把数据恢复一下, id=3
的is_del
设置为 0
验证
依次执行场景重现
的步骤, 我们发现, 第二次的查询中, 我们就不会把已经删除的数据查出来了.
我们把is_del=0
这个过滤给去除, 查询结果发现,is_del
真的已经变成1
(已删除)了, 而且时间是新的(mtime)
python test.py -p 3316 -i "article article_delta" "全是红包啊"
1. doc_id=3, weight=6, title=全是红包啊, cid=1, is_del=1, ctime=2015-12-23 08:15:44, mtime=2016-05-30 00:48:49