Lucene学习笔记

来源:互联网 发布:2015网络流行语大全 编辑:程序博客网 时间:2024/06/15 01:51

    最近研究学习Lucene中,基本上是用到了项目中,下面是一些笔记,比较零碎,主要是参考JavaEye上面的一些文章。

 

 

 

我下载的是 Lucene 2.4.1 版本,在开始之前,我们先来看下,不同版本之间的区别:

 

1.x,2.0和2.4是有一些区别的
比如说:
1

Java代码

  1. //1.x  
  2. IndexWriter writer new IndexWriter(indexPath, getAnalyzer(), true);    
  3. //2.0,2.4  
  4. IndexWriter writer new IndexWriter(indexPath, getAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);  

//1.x

IndexWriter writer = new IndexWriter(indexPath, getAnalyzer(), true); 

//2.0,2.4

IndexWriter writer = new IndexWriter(indexPath, getAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);


2.

Java代码

  1. Field.Index.TOKENIZED 替换为 Field.Index.ANALYZED   
  2. 没啥特殊的,改了一个名字而已  

Field.Index.TOKENIZED 替换为 Field.Index.ANALYZED

没啥特殊的,改了一个名字而已


3.

Java代码

  1. IndexWriter.flush();   
  2. 替换为   
  3. IndexWriter.commit();   

IndexWriter.flush();

替换为

IndexWriter.commit();



4.org.apache.lucene.search.Hits;
这个类将在3.0中被删除
新的使用方法在上面的例子中

---- 上面的例子----

·  //表示查出前四个  

·          TopDocCollector collector new TopDocCollector(4);  

·          //查找  

·          indexSearch.search(query,collector);  

·          //ScoreDoc这个对象还不清楚,但是有多少结果,就有多少个这个对象  

·          ScoreDoc[] hits collector.topDocs().scoreDocs;  

·          for(int i=0;i<hits.length;++i)  

·              //找到这个Document原来的索引值  

·              int docId hits[i].doc;  

·              System.out.println(docId);  

·              //根据这个值找到对象的Document  

·              Document indexSearch.doc(docId);  

·              System.out.println((i 1) ". d.get("title"));              

·           

--- 上面的例子 end -----

5.Field的创建

Java代码

  1. 在2.0+中  
  2. Field没了Keyword、UnIndexed、UnStored、Text这几个静态成员,只能用  
  3. Field(String, String, Store, Index)。  
  4. Keyword对应Field.Store.YES, Field.Index.UN_TOKENIZED,  
  5. UnIndexed 对应Field.Store.YES, Field.Index.NO,  
  6. UnStored对应Field.Store.NO, Field.Index.TOKENIZED,  
  7. Text对应Field.Store.YES, Field.Index.TOKENIZED  
  8. //2.0版本以上  
  9. Field(String name, byte[] value, Field.Store store)   
  10.           // Create stored field with binary value.   
  11. Field(String name, Reader reader)   
  12.           // Create tokenized and indexed field that is not stored.   
  13. Field(String name, Reader reader, Field.TermVector termVector)   
  14.           // Create tokenized and indexed field that is not stored, optionally with storing term vectors.   
  15. Field(String name, String value, Field.Store store, Field.Index index)   
  16.           // Create field by specifying its name, value and how it will be saved in the index.   
  17. Field(String name, String value, Field.Store store, Field.Index index, Field.TermVector termVector)   
  18.           // Create field by specifying its name, value and how it will be saved in the index.   

在2.0+中

Field没了Keyword、UnIndexed、UnStored、Text这几个静态成员,只能用

Field(String, String, Store, Index)。

Keyword对应Field.Store.YES, Field.Index.UN_TOKENIZED,

UnIndexed 对应Field.Store.YES, Field.Index.NO,

UnStored对应Field.Store.NO, Field.Index.TOKENIZED,

Text对应Field.Store.YES, Field.Index.TOKENIZED

//2.0版本以上

Field(String name, byte[] value, Field.Store store)

          // Create a stored field with binary value.

Field(String name, Reader reader)

          // Create a tokenized and indexed field that is not stored.

Field(String name, Reader reader, Field.TermVector termVector)

          // Create a tokenized and indexed field that is not stored, optionally with storing term vectors.

Field(String name, String value, Field.Store store, Field.Index index)

          // Create a field by specifying its name, value and how it will be saved in the index.

Field(String name, String value, Field.Store store, Field.Index index, Field.TermVector termVector)

          // Create a field by specifying its name, value and how it will be saved in the index.

 



Field.Store 表示“是否存储”,即该Field内的信息是否要被原封不动的保存在索引中。

Field.Index 表示“是否索引”,即在这个Field中的数据是否在将来检索时需要被用户检索到,一个“不索引”的Field通常仅是提供辅助信息储存的功能。

Field.TermVector 表示“是否切词”,即在这个Field中的数据是否需要被切词。


通常,参数用Reader,表示在文本流数据源中获取数据,数据量一般会比较大。像链接地址URL、文件系统路径信息、时间日期、人名、居民身份证、电话号码等等通常将被索引并且完整的存储在索引中,但一般不需要切分词,通常用上面的第四个构造函数,第三四个参数分别为 Field.Store.YES, Field.Index.YES。而长文本通常可用第3个构造函数。

 

------ 看了一两天我最疑惑不解的地方L 终于有点眉目了)

现在的Hits 变成了这种取法:

TopDocCollector collector new TopDocCollector(4);  

·          //查找  

·          indexSearch.search(query,collector);  

·          //ScoreDoc这个对象还不清楚,但是有多少结果,就有多少个这个对象  

 

 ScoreDoc[] hits collector.topDocs().scoreDocs;

 

而 lucene 2.0 版本中的取法如下:

IndexSearcher indexSearch = new IndexSearcher("c:\\index");

      

       // new StandardAnalyzer() 是一个分词器

       QueryParser queryParser = new QueryParser("file",new StandardAnalyzer());

      

       String queryString = "中华";

      

       Query query = queryParser.parse(queryString);

      

Hits hits = indexSearch.search(query);

 

这让我在考虑分页的时候,就有些搞不懂了,因为新的取法中,hits 是根据 TopDocCollector 来的,而 TopDocCollector 声明的时候,又必须带一个参数,就是所取的记录的条数,这让我想不通,就是那我如何获取lucene供查询处了多少条记录了。。。。, 比如在以前的版本中, Hits hits = indexSearch.search(query); 获得的 hits.length 就表示了共获取的查询记录数。。。这让我一直搜索想知道该如何来解决,知道看到了这篇文章:

http://xuganggogo.javaeye.com/blog/323886 Lucene实例

下面我仅列出有用的代码:

·    

·      int CACHE_PAGE 3; // 缓存的页面数  

 

·    

·          BooleanClause.Occur[] clauses BooleanClause.Occur.SHOULD,  

·                  BooleanClause.Occur.SHOULD };  

·          Query query MultiFieldQueryParser.parse(key, new String[]  

·                  "filename", "contents" }, clauses, analyzer);  

·          // QueryParser parser new QueryParser("contents", analyzer);  

·          // Query query parser.parse(key);  

·    

·          TopDocCollector collector new TopDocCollector(perPage CACHE_PAGE); // perPage  

·            

·          searcher.search(query, collector);  

·          ScoreDoc[] hits collector.topDocs().scoreDocs;  

·    

·          int numTotalHits collector.getTotalHits();  

·          System.out.println("符合查询词的文件数:" numTotalHits);  

·    

·          // 获得总页数  

·          if (numTotalHits perPage != 0)  

·              total_Page numTotalHits perPage 1;  

·          else  

·              total_Page numTotalHits perPage;  

·           

·    

·          if (begin total_Page)  

·              System.err.println("超出范围");  

·          else  

·              // 如果起始页大于缓存页,这就代表我们需要重新搜索更多的资源  

·              if (begin CACHE_PAGE)  

·                  // 这时,我把搜索的资源都搜索出来,缓存页数=总页数  

·                  CACHE_PAGE total_Page;  

·                  // 返回调用  

·                  search(key, perPage, begin);  

·                  // collector new TopDocCollector( numTotalHits ); //缓存不够,重新搜索  

·                  // searcher.search(query, collector);  

·                  // hits collector.topDocs().scoreDocs;  

·              else  

·                  int temp (begin 1) perPage perPage;  

·                  if ((begin 1) perPage perPage numTotalHits)  

·                      temp numTotalHits;  

·                   

 

 

看了这个我才想到了个大概,其实 int CACHE_PAGE 3; // 缓存的页面数  

应该就是值我们默认查询时需要显示的页数,比如10页,这样的话,我们查询时就之需要显示出 CACHE_PAGE * perPage (每页显示多少条记录) 的记录了。

 

我们来看看Google,和Baidu的搜索就知道了:

我们以Google为例,当我们搜索时:

 

Lucene学习笔记

 

这个能不能就相当于 google CACHE_PAGE 是 10, 每页显示了10条记录及 perPage ,当你点击了 Next 按钮之后,分页标签如下:

Lucene学习笔记

想想像Google这样搜索引擎中不知道针对一个关键词有多少记录,有必要一次把这些相符合的记录都取出来吗?一般的Google搜索处理的第一页我们就找到了想要的结果,又有多少机会,去点击 Next 按钮了。

 

另在实际项目使用过程中,发现,共用的记录数还是可以获取的,如下所示:

 

Lucene学习笔记


建立索引:

Java代码  收藏代码
  1. package paoding;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileNotFoundException;  
  7. import java.io.IOException;  
  8. import java.io.InputStreamReader;  
  9. import net.paoding.analysis.analyzer.PaodingAnalyzer;  
  10. import org.apache.lucene.analysis.Analyzer;  
  11. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  12. import org.apache.lucene.document.Document;  
  13. import org.apache.lucene.document.Field;  
  14. import org.apache.lucene.index.IndexWriter;  
  15.   
  16. public class IndexFiles {  
  17.   
  18.     public static void main(String[] args) {  
  19.         long start = System.currentTimeMillis();  
  20.         try {  
  21.             // 获取Paoding中文分词器  
  22.             Analyzer analyzer = new PaodingAnalyzer();  
  23.             // Analyzer analyzer = new StandardAnalyzer();  
  24.             // indexWriter建立索引  
  25.             IndexWriter writer = new IndexWriter("f:\\indexpaoding", analyzer, true,   
  26.                     IndexWriter.MaxFieldLength.UNLIMITED);  
  27.             indexDocs(writer, new File("F:\\徐剛:28tel(繁firfox)"));  
  28.             writer.optimize();  
  29.             writer.close();  
  30.             System.out.println("用时:" + (System.currentTimeMillis() - start)  
  31.                     + " 毫秒");  
  32.         } catch (IOException e) {  
  33.             e.printStackTrace();  
  34.         }  
  35.     }  
  36.     // 遍历文件夹文件,对需要的文件建立索引  
  37.     static void indexDocs(IndexWriter writer, File file) throws IOException {  
  38.         if (file.canRead()) {  
  39.             if (file.isDirectory()) {  
  40.                 String[] files = file.list();  
  41.                 if (files != null) {  
  42.                     for (int i = 0; i < files.length; i++) {  
  43.                         indexDocs(writer, new File(file, files[i]));  
  44.                     }  
  45.                 }  
  46.             } else {  
  47.                 if (file.getName().endsWith(".htm")  
  48.                         || file.getName().endsWith(".html")  
  49.                         || file.getName().endsWith(".jsp")  
  50.                         || file.getName().endsWith(".php")  
  51.                         || file.getName().endsWith(".txt")) {  
  52.                     System.out.println("添加 " + file);  
  53.                     try {  
  54.                         // 针对参数文件建立索引文档 ,一个Document就相当于一跳记录  
  55.                         Document doc = new Document();  
  56.                         // Field.Index.ANALYZED 文件名称 建立索引,分词  
  57.                         doc.add(new Field("filename", file.getCanonicalPath(),  
  58.                                 Field.Store.YES, Field.Index.ANALYZED,  
  59.                                 Field.TermVector.WITH_POSITIONS_OFFSETS));  
  60.                         doc.add(new Field("contents", ReadFile(file),  
  61.                                 Field.Store.YES, Field.Index.ANALYZED,  
  62.                                 Field.TermVector.WITH_POSITIONS_OFFSETS));  
  63.                         // new InputStreamReader(new  
  64.                         // FileInputStream(file.getCanonicalPath()), "utf-8")));  
  65.                         writer.addDocument(doc);  
  66.                     } catch (FileNotFoundException fnfe) {  
  67.                         ;  
  68.                     }  
  69.                 }  
  70.             }  
  71.         }  
  72.     }  
  73.   
  74.     // 用字符串形式,读取一个File的内容  
  75.     public static String ReadFile(File f) {  
  76.         String line = null;  
  77.         StringBuffer temp = new StringBuffer();  
  78.         try {  
  79.             BufferedReader br = new BufferedReader(new InputStreamReader(  
  80.                     new FileInputStream(f), "utf-8"));  
  81.             while ((line = br.readLine()) != null) {  
  82.                 temp.append(line);  
  83.             }  
  84.         } catch (FileNotFoundException e) {  
  85.             e.printStackTrace();  
  86.         } catch (IOException e) {  
  87.             e.printStackTrace();  
  88.         }  
  89.         return temp.toString();  
  90.     }  
  91.   
  92. }  
   

 

 

用来搜索:并带简单分页效果

Java代码  收藏代码
  1. package paoding;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStreamReader;  
  6. import net.paoding.analysis.analyzer.PaodingAnalyzer;  
  7. import org.apache.lucene.analysis.Analyzer;  
  8. import org.apache.lucene.analysis.TokenStream;  
  9. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  10. import org.apache.lucene.document.Document;  
  11. import org.apache.lucene.index.CorruptIndexException;  
  12. import org.apache.lucene.index.IndexReader;  
  13. import org.apache.lucene.index.TermPositionVector;  
  14. import org.apache.lucene.queryParser.MultiFieldQueryParser;  
  15. import org.apache.lucene.queryParser.ParseException;  
  16. import org.apache.lucene.queryParser.QueryParser;  
  17. import org.apache.lucene.search.BooleanClause;  
  18. import org.apache.lucene.search.IndexSearcher;  
  19. import org.apache.lucene.search.Query;  
  20. import org.apache.lucene.search.ScoreDoc;  
  21. import org.apache.lucene.search.Searcher;  
  22. import org.apache.lucene.search.TopDocCollector;  
  23. import org.apache.lucene.search.highlight.Formatter;  
  24. import org.apache.lucene.search.highlight.Highlighter;  
  25. import org.apache.lucene.search.highlight.QueryScorer;  
  26. import org.apache.lucene.search.highlight.TokenGroup;  
  27. import org.apache.lucene.search.highlight.TokenSources;  
  28.   
  29. public class SearchFiles {  
  30.     /** 
  31.      *  
  32.      * @param key 
  33.      *            搜索的关键字 
  34.      * @param perPage 
  35.      *            每页显示多少条记录 
  36.      * @param begin 
  37.      *            从第几页开始显示 
  38.      * @throws CorruptIndexException 
  39.      * @throws IOException 
  40.      * @throws ParseException 
  41.      */  
  42.     int CACHE_PAGE = 3// 缓存的页面数  
  43.   
  44.     public void search(String key, int perPage, int begin)  
  45.             throws CorruptIndexException, IOException, ParseException {  
  46.         String IDNEX_PATH = "f:\\indexpaoding";     //索引所在目录  
  47.   
  48.         int total_Page = 0// 总页数  
  49.   
  50.         // 获取Paoding中文分词器  
  51.         Analyzer analyzer = new PaodingAnalyzer();  
  52.         // Analyzer analyzer = new StandardAnalyzer();  
  53.         // 检索  
  54.         IndexReader reader = IndexReader.open(IDNEX_PATH);  
  55.         Searcher searcher = new IndexSearcher(reader);  
  56.   
  57.         /* 下面这个表示要同时搜索这两个域,而且只要一个域里面有满足我们搜索的内容就行 */  
  58.         BooleanClause.Occur[] clauses = { BooleanClause.Occur.SHOULD,  
  59.                 BooleanClause.Occur.SHOULD };  
  60.         Query query = MultiFieldQueryParser.parse(key, new String[] {  
  61.                 "filename""contents" }, clauses, analyzer);  
  62.         // QueryParser parser = new QueryParser("contents", analyzer);  
  63.         // Query query = parser.parse(key);  
  64.   
  65.         TopDocCollector collector = new TopDocCollector(perPage * CACHE_PAGE); // perPage  
  66.           
  67.         searcher.search(query, collector);  
  68.         ScoreDoc[] hits = collector.topDocs().scoreDocs;  
  69.   
  70.         int numTotalHits = collector.getTotalHits();  
  71.         System.out.println("符合查询词的文件数:" + numTotalHits);  
  72.   
  73.         // 获得总页数  
  74.         if (numTotalHits % perPage != 0) {  
  75.             total_Page = numTotalHits / perPage + 1;  
  76.         } else {  
  77.             total_Page = numTotalHits / perPage;  
  78.         }  
  79.   
  80.         if (begin > total_Page) {  
  81.             System.err.println("超出范围");  
  82.         } else {  
  83.             // 如果起始页大于缓存页,这就代表我们需要重新搜索更多的资源  
  84.             if (begin > CACHE_PAGE) {  
  85.                 // 这时,我把搜索的资源都搜索出来,缓存页数=总页数  
  86.                 CACHE_PAGE = total_Page;  
  87.                 // 返回调用  
  88.                 search(key, perPage, begin);  
  89.                 // collector = new TopDocCollector( numTotalHits ); //缓存不够,重新搜索  
  90.                 // searcher.search(query, collector);  
  91.                 // hits = collector.topDocs().scoreDocs;  
  92.             } else {  
  93.                 int temp = (begin - 1) * perPage + perPage;  
  94.                 if ((begin - 1) * perPage + perPage > numTotalHits) {  
  95.                     temp = numTotalHits;  
  96.                 }  
  97.                 // 根据参数,从指定的位置开始获取数据(用于分页)  
  98.                 for (int i = (begin - 1) * perPage; i < temp; i++) {  
  99.                     System.out.println(i);  
  100.                     int docId = hits[i].doc;  
  101.                     Document doc3 = searcher.doc(docId);  
  102.                     String filename = doc3.get("filename");  
  103.                     System.out.println("filename=" + filename);  
  104.                     // 高亮处理  
  105.                     String text = doc3.get("contents");  
  106.                     TermPositionVector tpv = (TermPositionVector) reader  
  107.                             .getTermFreqVector(hits[i].doc, "contents");  
  108.                     TokenStream ts = TokenSources.getTokenStream(tpv);  
  109.                     Formatter formatter = new Formatter() {  
  110.                         public String highlightTerm(String srcText, TokenGroup g) {  
  111.                             if (g.getTotalScore() <= 0) {  
  112.                                 return srcText;  
  113.                             }  
  114.                             return "<b>" + srcText + "</b>";  
  115.                         }  
  116.                     };  
  117.                     Highlighter highlighter = new Highlighter(formatter,  
  118.                             new QueryScorer(query));  
  119.                     String result = highlighter.getBestFragments(ts, text, 5,  
  120.                             "…");  
  121.                     System.out.println("result:\n\t" + result);  
  122.                 }  
  123.                 System.out.println("循环结束");  
  124.             }  
  125.         }  
  126.         reader.close();  
  127.         System.out.println("关闭reader");  
  128.   
  129.     }  
  130.   
  131.     public static void main(String[] args) throws Exception {  
  132.         SearchFiles sf = new SearchFiles();  
  133.         sf.search("vvczvxcxz"51);  
  134.     }  
  135. }  
 
原创粉丝点击