索引的创建、修改和删除 首先,我们来看一个例子:开源中国社区每天都有人发布新的博客,同时也有很多人在进行修改和删除博客的操作。如果我们只更新博客数据而不更新对应的索引数据,这会带来那些问题呢? 新增的博客信息不能够及时被用户搜索到; 修改的博客信息查询时依然显示之前的内容; 删除的博客信息查询时存在但实际已被删除。 因此,为了提高系统搜索的准确性和实时性,我们在进行数据更新的同时,也会更新与之对应的索引数据,这样业务数据就可以保持与索引数据的一致,上面的几个问题也就随之解决了。 首先,我们来看新增索引的操作,这个比较简单,之前的例子里面已经有讲到: //当新增博客时,索引也增量更新 public void addLuceneIndex(Blog blog){ try { IndexWriter writer = new IndexWriter(directory, config); Document doc = new Document(); //文章id,需要存储,查询结果的链接需要,但不需要检索 doc.add(new Field("id",blog.getString("id"),Field.Store.YES,Field.Index.NO)); //文章标题,需要存储也需要切词索引 doc.add(new Field("title",blog.getString("title"),Field.Store.YES,Field.Index.ANALYZED)); //文章内容一般会比较长,所以不需要存储,但需要切词索引 doc.add(new Field("content",blog.getString("content"),Field.Store.NO,Field.Index.ANALYZED)); //文章作者,需要存储,整体索引但不切词 doc.add(new Field("author",blog.getString("author"),Field.Store.YES,Field.Index.NOT_ANALYZED)); writer.addDocument(doc); writer.forceMerge(1); writer.commit(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 当博客被修改时,对应索引也执行更新操作,实际后台代码执行的是先删除再新增操作。 //索引更新操作 public void updateLuceneIndex(Blog blog){ try { IndexWriter writer = new IndexWriter(directory, config); Document doc = new Document(); writer.updateDocument(new Term("id", blog.getString("id")), doc); writer.forceMerge(1); writer.commit(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 当文章删除时,对应索引也执行删除操作 //索引删除操作 public void delLuceneIndex(Blog blog){ try { indexWriter.deleteDocuments(new Term("id", blog.getString("id"))); // Document删除 } catch (IOException e) { e.printStackTrace(); } } 最后说明一下,索引文件的增、删、改在实际应用过程中也是有很多策略的。比如对于搜索实时性要求比较高的系统,可以采取实时更新的策略,在更新记录时同时更新索引;如果系统对搜索的实时性要求不高,且服务器资源有限,可以设置一个定时任务,把白天更新的记录都标记出来,在凌晨服务器空闲的时候批量更新。总之,可以根据自己的需要去灵活的应用。 分词(切词) 分词也叫作切词,是指把文档的内容按照一定的规则切分成一个个独立的词语,通俗的说就是把句子切分成词语。分词是影响Lucene查询效率和查询准确率的关键因素。所有的分词器都继承自Lucene的Analyzer,今天介绍最流行和通用的中文分词器IKAnalyzer的使用。 Lucene默认实现的有英文分词。英文分词相对简单,主要是对每个单词的单复数,时态等做转换即可。而中文分词相对更复杂一些。因为中文的词库本身就非常庞杂,同一个句子可能有好几种分词法,不同的分词法可能就会导致不同的查询结果。IKAnalyzer为我们解决以上问题提供了很好的方案,它允许我们可以个性化定义扩展词库,而且分词效率极高。 下面我们来看下IKAnalyzer的配置文件IKAnalyzer.cfg.xml,把它放置到源文件根目录下面,系统会自动加载进来。 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>IKAnalyzer扩展配置</comment> <!--用户可以在这里配置自己的扩展字典--> <entry key="ext_dict"> /com/jfinal/lucene/ext.dic; /com/jfinal/lucene/ft_main2012.dic; /com/jfinal/lucene/ft_quantifier.dic; </entry> <!--用户可以在这里配置自己的扩展停止词字典--> <entry key="ext_stopwords"> /com/jfinal/lucene/stop.dic </entry> </properties> ext.dic用来定义自己的扩展词库。比如特定的地名,人名,就相当于告诉分词器如果遇到这些词汇就把它们做单独分词; stop.dic用来定义自己的扩展停止词字典,停止词就是指那些最普通的,没有特定含义的词。比如英语里面的a ,the,汉语里面的了,又等等。 把IKAnalyzer的jar包拷贝到lib下,使用时新建对象即可。 Analyzer analyzer = new IKAnalyzer()
--------------------------------------分割线 --------------------------------------