深入浅出jcr之十一 jackrabbit改进要点

作者,ahuaxuan

在看过前面的一系列文章之后,对于jackrabbit,我们脑海里应已经有了一幅比较清晰的图。接下来我们要思考的是如何提高搜索模块的性能。其中涉及到如何正确的使用lucene,如何让搜索模块专注的做它应该做的事情。

我们先谈谈第一个话题:专注。
为什么先要谈专注呢?因为它最重要了,一个功能要能够高效的完成任务,那么它应该只做自己擅长的事情。否则就会引来别人怀疑的目光。这一点在铁岭明星本山大叔的公鸡下蛋这部作品中有着较为深刻的阐述,原文如下:“当时这个鸡———心里特别矛盾,一个公鸡,居然它要下蛋,不是它的活它要干。大公鸡怎么看?鸭子怎么看?大鹅怎么看?跟它好过的小母鸡怎么看?”。

由此我们可以看出,会下蛋这项生理功能是绝不会让一只公鸡成为好公鸡的。在逆向思维一下,我们认为,一只公鸡把打鸣和繁殖后代的工作做好,而且要做得很好,这样它才能成为一只好公鸡。

那么在jackrabbit的querymodule中也是如此,querymodule要做好,就不应该做不属于它做的事情,而且要把search的功能做到非常的好,比如搜索非常的快,等等。

而有些功能的加入,反而会影响搜索的效率,这就是前面提到的高亮功能,高亮功能作为一个附属功能,在不影响搜索效率的情况下当然可以加入到query module中去,但是作为内容仓库,我们不得不考虑一个问题?那就是内容仓库中存放的到底是什么东西?文档,文档会有多少,显然很多很多,一个企业的文档是每天都在增加的,那么为了高亮,我们就必须做两个事情:

1, 把从文档中提取出来的text存放到索引中
2, 把该文档的分词之后的term offset存放到索引中

这样带来的后果是索引大小成倍的增加,索引越大,麻烦越多,需要考虑的问题就越多。比如说,我做分布式索引,那拷贝20G的索引和拷贝10G的索引,给人的感觉就是完全不一样的,那拷贝40G和20G就更不一样了。

据ahuaxuan的不完全测试,一般情况下,在使用jackrabbit时offset+text的大小几乎是真正索引数据的一倍多。这个和存放进去的文档有直接关系,其他场景ahuaxuan并不能保证也是这个比例。

所以如果我们去掉jackrabbit query module的高亮功能,会让我们的索引大小缩小一半,尤其在大索引文件的情况下,这样对我们做分布式索引也带来了非常大的好处。

在query module中去掉高亮并不是不要高亮,高亮功能不需要jackrabbit来做,直接交给jackrabbit的客户机,或者直接交给客户机的浏览器来做,这样把高亮带来的性能消耗分布出去,可以有效的提高平台服务的性能。尤其是放到浏览器上来做的做法,真正的把高亮这种非数值计算带来的CPU时间摊到最终的用户机上,真正,彻底的分布式啊,即使因为特殊原因不能放到最终的客户机上来做,我们也可以放到jackrabbit的client上来做,不管怎么说用jackrabbit来做这个功能其实就是干自己不擅长的事情,带来无穷的麻烦。
那么关于专注的问题,我们再回头看看公鸡下蛋那个新闻事件的结局,最后下蛋的公鸡完蛋了,被下锅了,这一事件警醒着我们,别让jackrabbit去“下蛋”,否则上面的人可能让它完蛋。

接着,让我们再来谈谈第二个话题:即时性
我们知道在数据库中,新插入的数据在会立刻生成其对应的索引,因为在普通的关系型数据库中,字段中保存的值都比较单一,而且比较小,如果是文本索引,那么即使索引的代价是非常大的,这意味着没新插入一条数据,都需要重新打开对应的indexreader,这个在普通的lucene应用中代价是非常大的,重新打开indexreader需要耗时,而且打开之后的第一次查询速度也非常的忙,所以一般不推荐即使索引,但是jackrabbit中提供的恰恰是即时索引,不过由于之前我们知道了jackrabbit中的indexmerge的逻辑,我们大概可以知道,最近常打开的indexreader一般情况下包含的document数量都在100-1000左右,那么这个代价还是稍微少一点,但是这样带来的后果是目录数比较多,查询的时候,要查很多个indexreader,然后合并结果集。

那么如果我们把即使性的特点去掉,那么会带来什么样的坏处呢?经过源代码的阅读,发现有这么几点:
1 删除数据之后,索引中的数据不能及时删除,那么返回的nodeid list中还包含已经删除的nodeid
2 新插入的数据不能及时的通过搜索模块搜索到。

优点呢:不用频繁的打开indexreader,更重要的是不需要wait。原因是在MultiIndex#update方法中和MultiIndex#getIndexReader有一个wait和notify的关系,在一些场景中,比如update执行一次之后关闭了reader,接着查询现场发现reader为空,又发现有线程正在做update,那么这个查询线程就不得不等待,知道update线程将其notify。这样的场景在MultiIndex中有7处之多,我们只要把这个逻辑去掉那么就可以将查询和索引两个线程的关系相对独立起来,相互不影响。

而且后台有一个deamon线程定期的重新打开indexreader,供查询请求使用。Ahuaxuan已经完成了这项改造。


虽然牺牲了及时性,但是换来性能上的提升,这一点还是值得做的。

总结,在jackrabbit中,将高亮模块拿掉,牺牲掉即时查询的特性会大幅度提高jackrabbit搜索功能的性能。

在下文中,ahuaxuan将会详细描述,如何在去除jackrabbit高亮特性的情况下保留二进制文件中提取出来的文本,并使其能够返回给客户端。

TO BE CONTINUE

你可能感兴趣的:(多线程,应用服务器,浏览器,企业应用,Lucene)