论坛首页 Java版 Struts

初次使用lucene2.0的心得和疑问

浏览 2239 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
时间:2007-07-11
这几天一直在看有关lucene的资料,在网上查了下,发现好多文章都是重复的,也有将的不错的文章,但大多例子都是基于lucene1.4.3的。本人刚接触lucene,在此一点小小的心得和疑问。请看下面:
lucene的基本特性可以参考:
初识lucene
Lucene基本使用介绍
网上大家对中文分词插件IK_CAnalyzer的评价不错,目前IK_CAnalyzer的最新版本是1.4,是在lucene2.0API的基础上开发的。本人下面的例子就是结合lucene2.0和IK_CAnalyzer使用的。

介绍:
例子是对lucene的简单使用,对“文章”的三个基本属性Id,title,content的索引和搜索。
通过ArticleBiz.getForumArt("10");取得一个文章列表。
从此list里取得各文章属性建立索引。
public class IndexAndSearch{
   public static void main(String[] args) throws IOException, ParseException{

  //RAMDirectory directory = new RAMDirectory(); // 将索引保存到内存中

   String directory = "C:/index";             // 将索引保存到硬盘中
   if(!new File(directory).exists())             
      new File(directory).mkdirs();

   // IK_CAnalyzer的分词器
   MIK_CAnalyzer mkAnalyzer = new MIK_CAnalyzer();
   try{
           // 取得文章列表,这部分省略了其与数据库的具体操作。
           List alist = ArticleBiz.getForumArt("10");

           // 生成一个IndexWriter,其作用是把每个Document 对象加到索引中来。
           IndexWriter writer = new IndexWriter(directory,mkAnalyzer,true);
           long s = System.currentTimeMillis();// 计算开始时间

           // 定义Document用来储存索引记录
            Document doc = null;

         // 循环从文章列表里对每一篇文章进行索引并将其结果加到以上的writer 里
           for(int i=0;i<alist.size();i++){
            doc = new Document();
            Article curArt = (Article) alist.get(i);
            System.out.println("index of :"+i+" the id is:"+curArt.getId()+" the title :"+curArt.getTitle());

           // 对文章Id,title,content索引,id:存储不分词。title:存储且分词。content:不存储但分词。

           doc.add(new Field("id",String.valueOf(curArt.getId()),Field.Store.YES,Field.Index.UN_TOKENIZED));
           doc.add(new Field("title", curArt.getTitle(),Field.Store.YES,Field.Index.TOKENIZED));
           doc.add(new Field("content",curArt.getContent(),Field.Store.NO,Field.Index.TOKENIZED));
           writer.addDocument(doc);      // 加入到writer
           }
           writer.optimize();   // 优化,关闭
            writer.close();
           System.out.println("the process in:"+(System.currentTimeMillis()-s)+" ms");
      } catch (IOException e) {
         System.out.println(e);
      } 

   //查询tilte里含有"视频" 或content里含有"投票"的文章信息
   Query query1 = new TermQuery(new Term("title", "视频"));
   Query query2 = new TermQuery(new Term("content", "投票"));
   BooleanQuery query = new BooleanQuery();
   query.add(query1,null);
   query.add(query2,null);

   // 如果只查询一个字段:不需要BooleanQuery来整合两个Query。
   // 如:只查询tilte里含有"视频"
   // Query query = new TermQuery(new Term("title", "视频"));

   // 生成一个IndexSearcher搜索
   IndexSearcher indexsearch = new IndexSearcher(directory);

   // 通过indexsearch获得query结果。
   Hits hits2 = indexsearch.search(query);
   System.out.println("begin search:length:"+hits2.length());
   Document doc2 = null;
   int id = 0;
   String title = "";

   // 循环输去搜索结果。
   for(int i=0;i<hits2.length();i++){
     doc2 = hits2.doc(i);
     id = Integer.valueOf(doc2.get("id"));
     title = doc2.get("title");
     System.out.println("Result is:"+id+" and the title is:"+title);
   }
   System.out.println("end search");
}
}



网上很多例子用的是lucene1.4.3,新版本的lucene在doc.add(new Field("content",curArt.getContent(),Field.Store.NO,Field.Index.TOKENIZED));这些地方与旧版本有很大的区别。
Field有两个属性可选:存储和索引。通过存储属性你可以控制是否对这个Field进行存储;通过索引属性你可以控制是否对该Field进行索引。这看起来似乎有些废话,事实上对这两个属性的正确组合很重要。
Field.Index Field.Store 说明
TOKENIZED(分词) YES 被分词索引且存储
TOKENIZED NO 被分词索引但不存储
NO YES 这是不能被搜索的,它只是被搜索内容的附属物。如URL等
UN_TOKENIZED YES/NO 不被分词,它作为一个整体被搜索,搜一部分是搜不出来的
NO NO 没有这种用法

如果要对某Field进行查找,那么一定要把Field.Index设置为TOKENIZED或UN_TOKENIZED。TOKENIZED会对Field的内容进行分词;而UN_TOKENIZED不会,只有全词匹配,该Field才会被选中。
如果Field.Store是No,那么就无法在搜索结果中从索引数据直接提取该域的值,会使null。

以上仅为个人拙见,有谬误的地方,希望大家指正。
同时本人有以下疑问请教,希望得到大家的指点。
1、对于大量数据的来说建立索引的过程肯定是很好费时间的,在论坛搜索中肯定不能够按照上面的例子来做,否则每一个用户搜索都要执行该过程系统就有些吃不消了。
如果将IndexWriter writer = new IndexWriter(directory,mkAnalyzer,true);第三个参数设为false那么新的文章内容又如何加到原来的索引里呢?
2、索引出来的结果太多的话需要分页,如果一下子全部检索出来的话肯定不科学,但是他又没有类似数据库里的limit限制,如何将大量的查询结果分页呢?
3、删除索引,随着数据的增多,系统索引也增大,在必要的时候可以调用自定义方法删除索引,是否在生成IndexWriter的时候将第三个参数设为false。下次执行的时候就会调用删除索引的方法删除以前的所有索引?

希望,谢谢!

来源:http://www.yyhweb.com/Article.htm?cId=2&fId=3&aId=50
   
时间:2007-07-11
IndexWriter的第三个参数的含义是在第一个参数所指定的路径下,删除原目录内的所有内容重新构建索引,或是在其中已经存在的索引上追加新的Document.通常在第一次构建索引时可以将它设为true,但在后面的不段更新中,则需要将该值设置为false,这样lucene不会将建立好的索引删除.
   
0 请登录后投票
时间:2007-07-11
如果数据量不是很大的情况下 ,可以把结果一次检索出来放到session中,然后从session中取出分页结果, 还可以采用缓存也就是部分结果放到session中+多次查询来处理.
   
0 请登录后投票
时间:2007-07-13
1. 没有太明白你的问题,但是感觉你好象理解不对。建立索引和搜索是两个分离的过程,只有在文章增删改的时候才会涉及到索引的操作。搜索操作基于索引操作生成的索引文件。
2. 这个不用担心,如果搜索结果很多,Lucene不是一次性把所有结果都加载到内存中的,而是只把前100条读入内存,当你请求后续数据的时候再继续加载。
3. IndexWriter的第三个参数仅仅表明是否创建索引文件,如果传入的目录中已经有索引文件存在,必须传入false否则会抛异常。 这个和索引条目的删除没有任何关系。索引条目删除必须手动调用IndexReader.deleteDocument()方法。
   
0 请登录后投票
时间:2007-07-14
1,“建立索引和搜索是两个分离的过程”
这个当然
当增加文章后,我如果想把该文章也增加到索引中该如何做呢?
应该不是从新建立所有索引吧?

2,“Lucene不是一次性把所有结果都加载到内存中的,而是只把前100条读入内存”
如果是这样的话,我想得到搜索结果的总数,而总数大于100的话岂不是总是得不到正确的数值?
   
0 请登录后投票
时间:2007-07-18
1)可以在增加文章时,同时在原索引的基础上新建一条索引。
2)Lucene有类试Hibernate的延迟加载机制,在你读的时候才会去取。
   
0 请登录后投票
时间:2007-07-26
这么多人支持 lucene
   
0 请登录后投票
时间:2007-07-26
在用COMPASS的时候,压力测试下会有索引文件被锁定的问题,而且CRUD执行效率明显低了。
及时得更新索引文件频繁地操作索引文件会造成这些问题,然后相关的CRUD时因为索引文件不能读写就全不能执行了,这也是个问题吧。
   
0 请登录后投票
论坛首页 Java版 Struts

跳转论坛:
JavaEye推荐