<%@ page contentType="text/html; charset=gb2312"%> 用Lucene做一个简单的Java搜索工具
网站公告:   ◆北天JAVA技术网热情为java爱好者服务,本网内容包括JAVA(JSP、servlet、EJB、webservice、j2ee、javabean、应用服务器、JavaScript),数据库(MYSQL、SQL Server、Sybase、Oracle、DB2、数据库综合知识),设计研究(设计模式、Struts、Spring、Hibernate、设计框架、设计综合知识),WEB2.0新技术(主要介绍AJAX),以及各种技术的入门、实例、例子等等,欢迎各位多来坐坐!◆  诚邀各位JAVA爱好者加盟!◆  本网站内容丰富,更新快,保证每周20篇以上!  
加入收藏
设为首页
联系站长
承接项目
  相关资源:网站首页 | 免费培训学院 | 技术论坛 | JAVA聊天室 | 作家专栏 | 开发工具 | 认证考试 | 会员俱乐部
  JAVA技术初学者园地 | jsp与servlet | javascript | Java源代码 | EJB | web service | 应用服务器 | JAVA综合知识
  设计研究设计模式 | 设计框架 | Struts | Spring | Hibernate | 开源项目 | 面向对象设计 | 设计综合知识
  数 据 库MYSQL | SQL Server | Sybase | Oracle | DB2 | Informix | Access | 数据库综合知识
  其他资源:AJAX新技术 | 网站开发 | ERP软件 | OA办公软件 | 商业智能BI | 开发综合知识 | 承接项目 | 项目试用

 
 
用Lucene做一个简单的Java搜索工具
     发布者: 发布时间:2007-02-25
   初学Lucene,刚接触搜索引擎。知道了一点点,想做个小工具,实现根据“单词”搜索某个java源文件。比如输入“String”去查询某些java源文件里用到了这个类。

    这个想法的来源是,在以前刚学java时,有一本java基础教程的书的附带光盘里有作者写的一个程序,可以方便初学者查找某些类在哪个实例里出现。当时没有太在意,觉得作者的代码很长。所以现在想自己也写一个这样的小程序。

    开发工具与运行环境:使用Lucene2.0的包,jdk1.5,在WindowsXP下运行。

    思路分析与设计:

    整个程序里,除了Lucene的必要操作外,就是IO的基本操作了。因为要对某目录下及其子目录下的所有Java源文件进行索引,就要用到递归,同时要过滤掉非Java源文件。根据这种情况,设计了以下5个类。


 
主类:索引类(IndexJavaFiles),搜索类(SearchJavaFiles
异常类:索引异常类(IndexException),搜索异常类(SearchException)
还有一个文件过滤工厂类(FileFilterFactory)。

    异常类不是必要的,特意设计来包装IO异常、文件异常和Lucene的异常。文件过滤工厂类的出现并不是故弄玄虚,只是不想太多代码集中一起,就把文件过虑器的设计放到一个类里。下面是程序的完整代码及注释。

 
IndexJavaFiles.java
/**
 *indexthejavasourcefiles
 */
package powerwind;
 
import java.io.*;
import java.util.Date;
 
import org.apache.lucene.document.*;
import org.apache.lucene.index.IndexWriter;
 
/**
 *@authorPowerwind
 *@version1.0
 */
publicclass IndexJavaFiles {
 
    /**
     *默认构造方法
     */
    public IndexJavaFiles() {
    }
 
    /**
     * 这个私有递归方法由index方法调用,保证index传入的file是目录不是文件
     *
     *@paramwriter
     *@paramfile
     *@paramff
     *@throwsIndexException
     */
    privatevoid indexDirectory(IndexWriter writer, File file, FileFilter filter)throws IndexException {
       if (file.isDirectory()) {
           // 有选择地(过滤)获取目录下的文件和目录
           File[] files = file.listFiles(filter);
           // 非空目录
           if (files != null) {
              for (int i = 0; i < files.length; i++) {
                  indexDirectory(writer, files[i], filter);
              }
           }
       } else {
           try {
             // 这里的file经过先前的过滤
              writer.addDocument(parseFile(file));
              System.out.println("增加文件: " + file);
           } catch (IOException ioe) {
              thrownew IndexException(ioe.getMessage());
           }
       }
    }
 
    /**
     *传参数是文件就直接索引,若是目录则交给indexDirectory递归
     *
     *@paramwriter
     *@paramfile
     *@paramff
     *@throwsIndexException
     */
    publicvoid index(IndexWriter writer, File file, FileFilter filter) throws IndexException {
       // 确定可读
       if (file.exists() && file.canRead()) {
           if (file.isDirectory()) {
              indexDirectory(writer, file, filter);
           } elseif (filter.accept(file)) {
              try {
                  writer.addDocument(parseFile(file));
                  System.out.println("增加文件: " + file);
              } catch (IOException ioe) {
                  thrownew IndexException(ioe.getMessage());
              }
           } else {
              System.out.println("指定文件或目录错误,没有完成索引");
           }
       }
    }
 
    /**
     *@paramfile
     *
     *File变成Document
     */
    private Document parseFile(File file) throws IndexException {
       Document doc = new Document();
       doc.add(new Field("path", file.getAbsolutePath(), Field.Store.YES,
                     Field.Index.UN_TOKENIZED));
       try {
           doc.add(new Field("contents", new FileReader(file)));
       } catch (FileNotFoundException fnfe) {
           thrownew IndexException(fnfe.getMessage());
       }
       return doc;
    }
}
index(IndexWriter writer, File file, FileFilter filter)调用私有方法indexDirectory(IndexWriter writer, File file, FileFilter filter)完成文件的索引。
下面是IndexException异常类。
IndexException.java
package powerwind;
 
publicclass IndexException extends Exception {
 
    public IndexException(String message) {
       super("Throw IndexException while indexing files: " + message);
    }
 
}
下面是FileFilterFactory类,返回一个特定的文件过滤器(FileFilter)。
FileFilterFactory.java
package powerwind;
 
import java.io.*;
 
publicclass FileFilterFactory {
    /**
     *静态匿名内部类
     */
    privatestatic FileFilter filter = new FileFilter() {
       publicboolean accept(File file) {
           long len;
           return file.isDirectory()||
                   (file.getName().endsWith(".java") &&
                   ((len = file.length()) > 0) && len < 1024 * 1024);
       }
    };
    publicstatic FileFilter getFilter() {
       returnfilter;
    }
}
 
main方法
    /**
     *      main方法
     */
    publicstaticvoid main(String[] args) throws Exception {
       IndexJavaFiles ijf = new IndexJavaFiles();
       Date start = new Date();
       try {
           IndexWriter writer = IndexWriterFactory.newInstance().createWriter("./index", true);
           System.out.println("Indexing ...");
           ijf.index(writer, new File("."), FileFilterFactory.getFilter());
           System.out.println("Optimizing...");
           writer.optimize();
           writer.close();
 
           Date end = new Date();
           System.out.println(end.getTime() - start.getTime() + " total milliseconds");
 
       } catch (IOException e) {
           System.out.println(" caught a " + e.getClass() + "\n with message: " + e.getMessage());
       }
    }
 
 
SearchJavaFiles.java
package powerwind;
 
import java.io.*;
 
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.*;
import org.apache.lucene.search.*;
 
publicclass SearchJavaFiles {
    private IndexSearcher searcher;
 
    private QueryParser parser;
 
    /**
     *
     *@paramsearcher
     */
    public SearchJavaFiles(IndexSearcher searcher) {
       this.searcher = searcher;
    }
 
    /**
     *
     *@paramfield
     *@paramanalyzer
     */
    publicvoid setParser(String field, Analyzer analyzer) {
       setParser(new QueryParser(field, analyzer));
    }
 
    /**
     *@paramparser
     */
    publicvoid setParser(QueryParser parser) {
       this.parser = parser;
    }
 
    /**
     *
     *@paramquery
     *@returnHits
     *@throwsSearchException
     */
    public Hits serach(Query query) throws SearchException {
       try {
           returnsearcher.search(query);
       } catch (IOException ioe) {
           thrownew SearchException(ioe.getMessage());
       }
    }
 
    /**
     *
     *@paramqueryString
     *@returnHits
     *@throwsSearchException
     */
    public Hits serach(String queryString) throws SearchException {
       if (parser == null)
           thrownew SearchException("parser is null!");
       try {
           returnsearcher.search(parser.parse(queryString));
       } catch (IOException ioe) {
           thrownew SearchException(ioe.getMessage());
       } catch (ParseException pe) {
           thrownew SearchException(pe.getMessage());
       }
    }
 
    /**
     *
     *输出hits的结果,从start开始到end,不包括end
     *
     *@paramhits
     *@paramstart
     *@paramend
     *@throwsSearchException
     */
    publicstatic Hits display(Hits hits, int start, int end) throws SearchException {
       try {
           while (start < end) {
              Document doc = hits.doc(start);
              String path = doc.get("path");
              if (path != null) {
                  System.out.println((start + 1) + "- " + path);
              } else {
                  System.out.println((start + 1) + "- " + "No such path");
              }
              start++;
           }
       } catch (IOException ioe) {
           thrownew SearchException(ioe.getMessage());
       }
       return hits;
    }
main方法
    /**
     *@paramargs
     */
    publicstaticvoid main(String[] args) throws Exception {
 
       String field = "contents";
       String index = "./index";
       finalint rows_per_page = 2;
       finalchar NO = 'n';
 
       SearchJavaFiles sjf = new SearchJavaFiles(new IndexSearcher(IndexReader.open(index)));
       sjf.setParser(field, new StandardAnalyzer());
       BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
 
       while (true) {
           System.out.println("Query: ");
           String line = in.readLine();
           if (line == null || line.length() < 2) {
              System.out.println("eixt query");
              break;
           }
           Hits hits = sjf.serach(line);
           System.out.println("searching for " + line + " Result is ");
 
           int len = hits.length();
           int i = 0;
           if (len > 0)
              while (true) {
                  if (i + rows_per_page >= len) {
                     SearchJavaFiles.display(hits, i, len);
                     break;
                  } else {
                     SearchJavaFiles.display(hits, i, i += rows_per_page);
                     System.out.println("more y/n?");
                     line = in.readLine();
                     if (line.length() < 1 || line.charAt(0) == NO)
                         break;
                  }
              }
           else
              System.out.println("not found");
       }
    }
}
 
SearchException.java
package powerwind;
 
publicclass SearchException extends Exception {
 
    public SearchException(String message) {
       super("Throw SearchException while searching files: " + message);
    }
 
}


 

 
完善设想:
1、文件格式:
能够处理Zip文件Jar文件,索引里面的java源文件。
通过反射机制索引class类文件。
2、输入输出:
除控制台输入输出外,还可以选择从文件读取查询关键字,输出查询结果到文件。
3、用户界面:
图形界面操作,双击查询结果的某条记录可以打开相应文件。
4、性能方面
索引文件时,用缓存和多线程处理
(转载文章请保留出处:北天JAVA技术网(www.java114.com))
 
更多精彩文章:
如何同时启动多个Tomcat服务器
运用Jakarta Struts的七大实战心法
equals() 方法对哪些类有效啊?
关于java中接口的认识
业务流程不是需求
学习Spring的小小心得
 
最近评论:
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(3106)
        
冰封的往事!
wow power leveling,wow gold,wow power leveling,wow gold max(6074)
        
冰封的往事!
wow power leveling,wow gold,WoW Gold,wow gold max(1841)
        
冰封的往事!
wow power leveling,wow gold,WoW Gold,wow gold max(955)
        
飞舞的传奇!
传世私服,传世私服.传奇世界私服传奇世界私服,传世私服传世私服, 传奇世界私服传奇世界私服.传奇私服传奇私服. max(4257)
        
回复:用Lucene做一个简单的Java搜索工具
谢谢!
        
标 题:   
内 容:   
 
                                  
 
免责声明:该文章由网友发表,如果对您造成侵权,请联系站长

首页 - 承接项目 - 网站地图 - 联系我们 -
版权所有北天JAVA技术工作室 ICP证号:粤ICP备06079815号