2012年10月14日星期日

【Lucene学习笔记】基本的索引与检索

【Lucene学习笔记】基本的索引与检索

  Lucene作为全文检索工具,其作用还是蛮大的。举个例子,像我专门腾个盘来放各种各样的文档,都有50多个G了,现在有些啥文档、都存在哪的,我自己都记不清楚许多了- -Windows自带了搜索的,可是我只知道它能用来检索某个文件名,前提是我得记得住文件名啊!而且平时我们那会关心文件名,我们更关心内容是否符合我们要找的东西,只不过一般标题和正文都是匹配的而已。在这种情况下还不如自己用用Lucene来建个索引,当然索引文件也是要占空间的- -

  接下来就先看看一个最基本的索引与检索,以后的内容就是在这个框架上不断补充和深化。最近Lucene4.0正式版发布了,但是文档半天看不懂- -还是先用着3.6吧,等着研究清楚了再说。说实话,这东西我还真不知道该怎么说明,所以就贴出代码,然后注释吧。

  1 import java.io.*;  2 import java.util.Scanner;  3   4 import org.apache.lucene.index.*;  5 import org.apache.lucene.queryParser.ParseException;  6 import org.apache.lucene.queryParser.QueryParser;  7 import org.apache.lucene.search.*;  8 import org.apache.lucene.store.*;  9 import org.apache.lucene.util.Version; 10 import org.apache.lucene.analysis.standard.StandardAnalyzer; 11 import org.apache.lucene.document.*; 12  13 public class TestLucene { 14     public static void main(String[] args){ 15         Directory dir=null; 16         /** 17          * 建立索引 18          */ 19         IndexWriter iw=null; 20         try { 21             //1.创建Directory对象 22             //.指定你要将索引创建在哪个路径。我是Eclipse创建的项目,所以用的相对路径 23             //.值得注意的是,貌似new一个和调用open方法都可以,但我建议open,这样毕竟会有些处理和判断的,可以看一下源码它们的区别 24             dir=FSDirectory.open(new File("index")); 25             //2.创建IndexWriter对象 26             //.用来生成索引。在3.6中专门分出个IndexWriterConfig来配置IndexWriter 27             //.不知道哪个版本之前是直接传参数给IndexWriter构造函数,这样就很繁琐,参数一大串,重载构造函数一大堆,于是重构了一下 28             IndexWriterConfig conf=new IndexWriterConfig(Version.LUCENE_36, new StandardAnalyzer(Version.LUCENE_36)); 29             iw = new IndexWriter(dir, conf); 30              31             //指定你要索引的文件目录,文件不止一个,需要为每个文件都添加索引,自然得循环 32             //你也可以用高级点的语法:for(File f:file),相当于foreach。我也不知道是java几有的,反正我是java7 33             File file=new File("file"); 34             for(int i=0;i<file.listFiles().length;i++){ 35                 System.out.println("建立文件"+i+"的索引"); 36                 File f=file.listFiles()[i]; 37                 //3.创建Document对象 38                 Document doc=new Document(); 39                 //4.为Document配置Field 40                 //.Document就相当于数据库中的一个元祖,而Field就是列,整个索引自然是一张表 41                 //.这里分成三列,文件名、路径和内容。路径和文件名也要存储在索引中,而且它们是一个整体,不用分词 42                 //.如果要用4.0,Field也是重构了的,比如内容可用TextField,后面两个则StringField。而这几个重载构造函数自然被弃用了 43                 //.而且4.0的域存储选项和域索引选项貌似不见了,我也还不清楚到哪去了 44                  45 //                BufferedReader input = new BufferedReader(new FileReader(file));   46 //                StringBuffer buffer = new StringBuffer();   47 //                String text;   48 //                while((text=input.readLine())!=null){ 49 //                    buffer.append(text +"/n"); 50 //                } 51 //                doc.add(new Field("name",buffer.toString(),Field.Store.YES,Field.Index.ANALYZED)); 52                  53                 doc.add(new Field("contents",new FileReader(f))); 54                 doc.add(new Field("name",f.getName(),Field.Store.YES,Field.Index.ANALYZED)); 55                 doc.add(new Field("path",f.getAbsolutePath(),Field.Store.YES,Field.Index.NOT_ANALYZED)); 56                 //5.通过IndexWriter将文档添加到索引 57                 iw.addDocument(doc); 58             } 59         } catch (FileNotFoundException e) { 60             e.printStackTrace(); 61         } catch (IOException e) { 62             e.printStackTrace(); 63         }finally{ 64             System.out.println("建立索引完毕"); 65             //8.关闭IndexWriter流 66             //.本来我还关闭Directory的,但是运行异常,原因我不清楚 67             try { 68                 if(iw!=null){ 69                     iw.close(); 70                 } 71             } catch (IOException e) { 72                 e.printStackTrace(); 73             } 74         } 75          76         /** 77          * 查询索引 78          */ 79         System.out.print("请输入检索词:"); 80         Scanner input=new Scanner(System.in); 81         String qstr=input.nextLine(); 82          83         IndexReader ir=null; 84         IndexSearcher srch=null; 85         try { 86             //1.创建Directory 87             //.还是你索引所在的目录,毕竟是在索引中检索 88             dir=FSDirectory.open(new File("index")); 89             //2.创建IndexReader 90             //.Writer是写到索引文件中去,Reader自然是从索引文件中把内容读出来 91             ir=IndexReader.open(dir); 92             //3.根据IndexReader创建IndexSearch 93             //.就是要在这些索引中查找 94             srch=new IndexSearcher(ir); 95             //4.创建搜索的Query 96             //.首先得创建一个Parser对象,你输入的检索关键词也得解析解析吧,搜索域设定在contents中,也就是内容中有才算数,免得文不对题 97             QueryParser parser=new QueryParser(Version.LUCENE_36, "contents", new StandardAnalyzer(Version.LUCENE_36)); 98             Query query=parser.parse(qstr); 99             //5.根据Search搜索并返回TopDocs的文档100             //.这就开始执行搜索,搜索整个索引库后排序,然后取前3条,当然这里总共也只有3条索引101             TopDocs tds=srch.search(query, 3);102             //6.根据TopDocs获取ScoreDoc103             //.ScoreDoc的下标就相当于每个文档的id号,因为返回值是根据得分从高到低排序了的,直接根据它来遍历显示就OK了104             ScoreDoc[] sds=tds.scoreDocs;105             for(int i=0;i<sds.length;i++){106                 //7.根据Searcher和ScoreDoc获取具体Document107                 Document doc=srch.doc(sds[i].doc);108                 //8.根据Document获取需要的值109                 System.out.println(doc.get("name")+" | "+doc.get("path"));110             }111         } catch (IOException e) {112             e.printStackTrace();113         }catch(ParseException e){114             e.printStackTrace();115         }finally{116             try {117                 if(ir!=null){118                     ir.close();119                 }120                 if(srch!=null){121                     srch.close();122                 }123             } catch (IOException e) {124                 e.printStackTrace();125             }126         }127     }128 }

  最后的执行结果是:


TAG: