1. public void index() throws CorruptIndexException,     
  2.             LockObtainFailedException, IOException {     
  3.         // 索引目录     
  4.         File indexDir = new File("D:/workspace/code/java/TestLucene3/index/txt/test/");     
  5.         // 注意:这里建立索引用的分词方法,在搜索时分词也应该采用同样的分词方法。不然搜索数据可能会不正确     
  6.         // 使用Lucene自带分词器     
  7.         Analyzer luceneAnalyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);     
  8.         // 第一个参数是存放索引文件位置, 第二个参数是使用的分词方法, 第三个:true,建立全新的索引,false,建立增量索引。     
  9.         // IndexWriter indexWriter = new IndexWriter(indexDir, luceneAnalyzer, true);     
  10.     
  11.         // 第一个参数是存放索引目录有FSDirectory(存储到磁盘上)和RAMDirectory(存储到内存中), 第二个参数是使用的分词器, 第三个:true,建立全新的索引,false,建立增量索引,第四个是建立的索引的最大长度。     
  12.         IndexWriter indexWriter = new IndexWriter(FSDirectory.open(indexDir),     
  13.                 luceneAnalyzer, true, IndexWriter.MaxFieldLength.LIMITED);     
  14.         // 索引合并因子     
  15.         // SetMergeFactor(合并因子)        
  16.         // SetMergeFactor是控制segment合并频率的,其决定了一个索引块中包括多少个文档,当硬盘上的索引块达到多少时,        
  17.         // 将它们合并成一个较大的索引块。当MergeFactor值较大时,生成索引的速度较快。MergeFactor的默认值是10,建议在建立索引前将其设置的大一些。     
  18.         indexWriter.setMergeFactor(100);     
  19.         // SetMaxBufferedDocs(最大缓存文档数)        
  20.         // SetMaxBufferedDocs是控制写入一个新的segment前内存中保存的document的数目,        
  21.         // 设置较大的数目可以加快建索引速度,默认为10。        
  22.         indexWriter.setMaxBufferedDocs(100);     
  23.     
  24.         // SetMaxMergeDocs(最大合并文档数)        
  25.         // SetMaxMergeDocs是控制一个segment中可以保存的最大document数目,值较小有利于追加索引的速度,默认Integer.MAX_VALUE,无需修改。        
  26.         // 在创建大量数据的索引时,我们会发现索引过程的瓶颈在于大量的磁盘操作,如果内存足够大的话,        
  27.         // 我们应当尽量使用内存,而非硬盘。可以通过SetMaxBufferedDocs来调整,增大Lucene使用内存的次数。        
  28.         indexWriter.setMaxMergeDocs(1000);     
  29.     
  30.         // SetUseCompoundFile这个方法可以使Lucene在创建索引库时,会合并多个 Segments 文件到一个.cfs中。        
  31.         // 此方式有助于减少索引文件数量,对于将来搜索的效率有较大影响。        
  32.         // 压缩存储(True则为复合索引格式)        
  33.         indexWriter.setUseCompoundFile(true);     
  34.              
  35.         long startTime = new Date().getTime();     
  36.              
  37.         String temp = "";     
  38.         // 增加索引字段     
  39.         //              
  40.         // 在Field中有三个内部类:Field.Index,Field.Store,Field.termVector,而构造函数也用到了它们。        
  41.         // 参数说明:        
  42.         // Field.Store:     
  43.         // Field.Store.NO:表示该Field不需要存储。        
  44.         // Field.Store.Yes:表示该Field需要存储。        
  45.         // Field.Store.COMPRESS:表示使用压缩方式来存储。        
  46.         // Field.Index:     
  47.         // Field.Index.NO:表示该Field不需要索引。        
  48.         // Field.Index.TOKENIZED:表示该Field先被分词再索引。        
  49.         // Field.Index.UN_TOKENIZED:表示不对该Field进行分词,但要对其索引。        
  50.         // Field.Index.NO_NORMS:表示该Field进行索引,但是要对它用Analyzer,同时禁止它参加评分,主要是为了减少内在的消耗。     
  51.         // TermVector这个参数也不常用,它有五个选项。     
  52.         //                Field.TermVector.NO表示不索引Token的位置属性;     
  53.         //                Field.TermVector.WITH_OFFSETS表示额外索引Token的结束点;     
  54.         //                Field.TermVector.WITH_POSITIONS表示额外索引Token的当前位置;     
  55.         //                Field.TermVector.WITH_POSITIONS_OFFSETS表示额外索引Token的当前和结束位置;     
  56.         //                Field.TermVector.YES则表示存储向量。     
  57.     
  58.         // 增加文档 Field相当于增加数据库字段一样检索,获取都需要的内容,直接放index中,不过这样会增大index,保存文件的txt内容     
  59.         /**    
  60.          * Field.Store 表示“是否存储”,即该Field内的信息是否要被原封不动的保存在索引中。    
  61.          * Field.Index 表示“是否索引”,即在这个Field中的数据是否在将来检索时需要被用户检索到,一个“不索引”的Field通常仅是提供辅助信息储存的功能。    
  62.          * Field.TermVector 表示“是否切词”,即在这个Field中的数据是否需要被切词。    
  63.          */    
  64.         Field fieldPath = new Field("path""", Field.Store.YES, Field.Index.NO);     
  65.         Field fieldBody = new Field("content", temp, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS);     
  66.         Field fieldId = new Field("id""", Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS);     
  67.              
  68.         Document document = new Document();     
  69.         // 做测试,循环100000遍建索引。也可以读取文件内容建索引     
  70.         for (int i=0; i<100000; i++) {     
  71.             document  = new Document();     
  72.             temp = "王熙凤历幻返金陵 甄应嘉蒙恩还玉阙";     
  73.                  
  74.             fieldPath.setValue("D:/workspace/code/java/TestLucene3/txt/" +i+".txt");     
  75.             fieldBody.setValue(temp);     
  76.             fieldId.setValue(String.valueOf(i));     
  77.                  
  78.             document.add(fieldPath);     
  79.             document.add(fieldBody);     
  80.             document.add(fieldId);     
  81.             indexWriter.addDocument(document);     
  82.             i++;     
  83.         }     
  84.         //optimize()方法是对索引进行优化     
  85.         indexWriter.optimize();     
  86.         indexWriter.close();     
  87.              
  88.         // 若需要从索引中删除某一个或者某一类文档,IndexReader提供了两种方法:     
  89.         // reader.DeleteDocument(int docNum)     
  90.         // reader.DeleteDocuments(Term term)     
  91.         // 前者是根据文档的编号来删除该文档,docNum是该文档进入索引时Lucene的编号,是按照顺序编的;后者是删除满足某一个条件的多个文档。     
  92.         // 在执行了DeleteDocument或者DeleteDocuments方法后,系统会生成一个*.del的文件,该文件中记录了删除的文档,但并未从物理上删除这些文档。此时,这些文档是受保护的,当使用Document        
  93.         // doc = reader.Document(i)来访问这些受保护的文档时,Lucene会报“Attempt to access a        
  94.         // deleted document”异常。如果一次需要删除多个文档时,可以用两种方法来解决:        
  95.         // 1. 删除一个文档后,用IndexWriter的Optimize方法来优化索引,这样我们就可以继续删除另一个文档。        
  96.         // 2. 先扫描整个索引文件,记录下需要删除的文档在索引中的编号。然后,一次性调用DeleteDocument删除这些文档,再调用IndexWriter的Optimize方法来优化索引。     
  97.              
  98.         long endTime = new Date().getTime();     
  99.         System.out.println("\n这花费了" + (endTime - startTime) + " 毫秒增加到索引!");     
  100.     }  
 
  
  1. /**       
  2.      * 查询       
  3.      *        
  4.      * @param String word 关键词       
  5.      * @param String filedName 域字段       
  6.      * @param String indexDir 索引位置       
  7.      * @throws CorruptIndexException       
  8.      * @throws IOException       
  9.      * @throws ParseException       
  10.      * @auther <a href="mailto:gaoxuguo@feinno.com">Gao XuGuo</a> Nov 30, 2009      
  11.      *         2:56:42 PM       
  12.      */        
  13.     public List<Map<String, String>> search(String indexDir)        
  14.             throws CorruptIndexException, IOException, ParseException {        
  15.         File file = new File(indexDir);        
  16.         IndexSearcher is = new IndexSearcher(FSDirectory.open(file), true);        
  17.         String field = "content";        
  18.        
  19.         BooleanQuery bq = new BooleanQuery();        
  20.                 
  21.         QueryParser parser = new QueryParser(Version.LUCENE_CURRENT, field,        
  22.                 new StandardAnalyzer(Version.LUCENE_CURRENT));        
  23.         Query query = parser.parse("content:王熙凤");        
  24.                 
  25.         Query q = new TermQuery(new Term("id","100"));        
  26.         bq.add(q,Occur.SHOULD);        
  27.         bq.add(query,Occur.SHOULD);        
  28.         // 100表示取前100条数据        
  29.         TopScoreDocCollector collector = TopScoreDocCollector.create(100true);        
  30.        
  31.         long start = new Date().getTime();// start time        
  32.                 
  33.         /**      
  34.          * Lucene内置了三个Filter子类:      
  35.          * 1)DateFilter使搜索只限于指定的日期域的值在某一时间范围内的文档空间里      
  36.          * 2)QueryFilter把查询结果做为另一个新查询可搜索的文档空间      
  37.          * 3)CachingWrappperFilter是其他过滤器的装饰器,将结果缓存起来以便再次使用,从而提高性能。      
  38.          *       
  39.          */       
  40.         String[] dirs = {indexDir};        
  41.         MultiSearcher ms = this.getMultiSearcher(dirs);        
  42.         ms.search(bq, collector);        
  43.                 
  44. //        is.search(bq, collector);        
  45.         ScoreDoc[] docs = collector.topDocs().scoreDocs;        
  46.        
  47.         Document doc;        
  48.         for (ScoreDoc sd : docs) {        
  49.             doc = is.doc(sd.doc);        
  50.             // 取得doc里面的Field并从doc里面读取值        
  51.             for (Fieldable fa : doc.getFields()) {        
  52.                 System.out.print(fa.name() + "=" + doc.get(fa.name()) + " ");        
  53.             }        
  54.             System.out.println();        
  55.         }        
  56.         long end = new Date().getTime();        
  57.         if(is != null) is.close();        
  58.        
  59.         System.out.println("找到 " + collector.getTotalHits()        
  60.                 + " 条数据,花费时间 " + (end - start)        
  61.                 + " 秒");        
  62.         return null;        
  63.     }        
  64.       
  65.  
  66.  
  67. /**    
  68.      * 得到MultiSearcher多目录查询实例    
  69.      *    
  70.      * @param String[] dirs 要查询的索引目录。    
  71.      *     
  72.      * @return MultiSearcher    
  73.      * @throws IOException    
  74.      * @auther <a href="mailto:gaoxuguo@feinno.com">Gao XuGuo</a>    
  75.      * Jan 22, 2010 3:44:16 PM    
  76.      */    
  77.     private MultiSearcher getMultiSearcher(String[] dirs) throws IOException {     
  78.              
  79.         // 多目录     
  80.         IndexSearcher [] searchers = new IndexSearcher[dirs.length];     
  81.         int i = 0;     
  82.         for (String dir : dirs) {     
  83.             searchers[i] = new IndexSearcher(FSDirectory.open(new File(dir)), true);     
  84.             i++;     
  85.         }     
  86.         // 多目录查询     
  87.         return new MultiSearcher(searchers);     
  88.     }