5、IndexWriter
索引这部分最后讲的是IndexWriter。如果说前面提到的都是数据的结构,那么IndexWriter就是业务的封装。无论述Document,Field还是看不见的Segment,Term都是对数据存储逻辑的抽象,IndexWriter包装了操作的过程。
当然,这里不会讨论IndexWriter的每个细节,这里主要介绍IndexWriter的常用法和实际使用中遇到的部署问题。
5.1 IndexWriter的常用方法
IndexWriter的用法很简单,前文有例子。在《接触Lucene.Net 》一文中代码2.1.1就是最简单的用法。可以看到IndexWriter的构造函数很重要,AddDocument方法也很重要,有这两个方法,就可以建立索引了。其它的方法都是对建立索引的过程或者结果进行了优化,或者是提供了一些索引中或者索引后的数据。比如,常用的Optimize方法,就是对索引进行优化,使得搜索能够效率更高。还有一些常用的方法(按字母排序):
(1)、AddIndexes方法是合并不同部分索引的,这个方法很有用,比如,用5个线程在5个目录下建立索引,然后用这个方法把5个索引合并为一个,这样就能提高索引的效率;
(2)、Close方法是最后使用的方法,除了能够去除对文件的锁定外,还能起到Flush方法的作用。这个方法非常重要,在IndexWriter实例建立后,无论出现什么样的问题,哪怕程序崩溃,都一定要显式调用该方法。要不然索引会处于锁定状态,无法解除;
(3)、DeleteDocuments是用来删除索引的,这里只能指定Term删除,使用价值不是太高;
(4)、Flush方法是把缓冲数据写入的一个方法,在不想关闭索引但是要清空缓冲区的时候使用;
(5)、Optimize方法是优化索引的方法,如果索引数据很大,则调用这个方法会耗费很长时间。另外就是,如果索引文件这个时候被读取,并不能达到删除废弃文件的目的。
(6)、SetMaxBufferedDocs方法是规定缓冲区能够缓冲Document的个数,因为写硬盘要比写内存慢很多,这个值设置得越大,暂时存储到内存的Document就会越多;
(7)、SetMaxFieldLength方法设置Field的最大长度;
(8)、UpdateDocument用来更新索引,但是实际上并不是真正的更新,而是先删除,再添加,如果不进行优化,那么至少会增加两个文件,一个记录了增加的一个记录了删除的。
5.2 索引的部署
索引的部署根据索引的大小而趋向复杂,我认为至少是平方增长。复杂度增长的原因在于,索引大小的增长,将会引入更多需要考虑的因素。比如,索引的重建,索引优化时间,多索引部署等,而分布式部署基本上是目前最复杂的部署方案。
一般来说,应该一个索引存储,只应该由一个IndexWriter来控制。一个存储不应该超过2G,即使是2G,每次索引更新都需要10分钟左右来优化索引。至于如何分配索引,要根据实际情况来决定,而且要考虑诸如程序崩溃等情况。
在Java版的搜索引擎解决方案中有很多可以借鉴的地方,比如,对于数据索引,Compass的索引方式可以参考;对于抓取式的搜索引擎,Nutch可以参考;分布式解决方案可以参考Hadoop。如何实现像Compass一样,添加、删除、更新都能及时反映到索引当中,站内搜索引擎一般都会面临这样的问题。Lucene.Net已经为我们提供了实现的方法,至于实现的逻辑需要你去思考。
6、索引小节
本篇文章是索引部分的完结篇。从第一篇到这里第七篇,主要介绍了两个东西,一个是Lucene.Net的逻辑存储,另外一个就是如何操作逻辑存储。在逻辑存储上讲得比较详细,特别是关于权重部分,而操作则只简单提一下。因为,逻辑存储有助于理解Lucene.Net索引的流程,而操作则只是相当于CPU的指令,业务逻辑需要自己去实现。相信看了以上七篇文章,有助于对Lucene.Net索引的理解,当然,这里只讲了表面上的东西,更加深入地理解Lucene需要从更加底层的Directory入手。索引部分就暂时写到这里了,后面将进入搜索问题的探讨。