Lucene简介
Lucene是一个基于Java的、高性能的全文检索工具包,它目前是著名的 Apache Jakarta 家族中的一个开源项目,也是目前最为流行的基于 Java 开源全文检索工具包。但它不是一个完整的搜索应用程序,而是为应用程序提供索引和搜索功能。
Lucene 是为文本类型的数据建立索引的,所以只要能把需要索引的数据格式转化的文本的,Lucene 就能对文档进行索引和搜索。比如HTML、PDF,都可以转换文本再交给Lucene进行索引。
1. Lucene环境
1.1 Lucene版本
当前版本:取当前最新版本Lucene Core 3.4.0
下载地址:http://lucene.apache.org/java/docs/index.html
linux版本: lucene-3.4.0.tgz
windows版本:lucene-3.4.0.zip
1.2 IKAnalyzer中文分词器
Lucene的分词器以接口Analyzer的形式对外提供,外部根据业务需要实现该分词器。Lucene本身提供了标准分词器StandarAnalyzer,针对英文的分词。
中文分词器现在比较成熟的是开源项目的IKAnalyzer,是针对中文的分词, 目前最新版本是IKAnalyzer3.2.8.jar
下载地址: http://code.google.com/p/ik-analyzer/downloads/list
2. Lucene和应用程序的关系
3. Lucene API使用
3.1 建立索引
为了对文档进行索引,Lucene 提供了五个基础的类,他们分别是 Document, Field, IndexWriter, Analyzer, Directory。下面我们分别介绍一下这五个类的用途:
Document
Document 是用来描述文档的,这里的文档可以指一个 HTML 页面,一封电子邮件,或者是一个文本文件。一个 Document对象由多个 Field 对象组成的。可以把一个 Document 对象想象成数据库中的一个记录,而每个 Field 对象就是记录的一个字段。
Field
Field 对象是用来描述一个文档的某个属性的,比如一封电子邮件的标题和内容可以用两个 Field 对象分别描述。
Analyzer
在一个文档被索引之前,首先需要对文档内容进行分词处理,这部分工作就是由 Analyzer 来做的。Analyzer 类是一个抽象类,它有多个实现。针对不同的语言和应用需要选择适合的 Analyzer。Analyzer 把分词后的内容交给 IndexWriter 来建立索引。
IndexWriter
IndexWriter 是 Lucene 用来创建索引的一个核心的类,他的作用是把一个个的 Document 对象加到索引中来。
Directory
这个类代表了 Lucene 的索引的存储的位置,这是一个抽象类,它目前有两个实现,第一个是 FSDirectory,它表示一个存储在文件系统中的索引的位置。第二个是 RAMDirectory,它表示一个存储在内存当中的索引的位置。
使用例子
public void createIndexs() throws Exception { String indexDir = "d:\\Temp\\lucence\\indexDir"; String dataDir = "d:\\Temp\\lucence\\dataDir"; Analyzer analyzer = new IKAnalyzer(true); // 使用中文分词器 File dir = new File(dataDir); File[] files = dir.listFiles();
Directory fsDirectory = FSDirectory.open(new File(indexDir)); IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_34, analyzer); config.setOpenMode(OpenMode.CREATE_OR_APPEND); config.setMaxBufferedDocs(1000); IndexWriter indexWriter = new IndexWriter(fsDirectory, config);
for(int i = 0; i < files.length; i++) { String filePath = files[i].getAbsolutePath();
if(filePath.endsWith(".html") || filePath.endsWith(".htm")) { HTMLDocParser htmlParser = new HTMLDocParser(filePath); String path = htmlParser.getPath(); String title = htmlParser.getTitle(); Reader content = htmlParser.getContent();
Document document = new Document(); document.add(new Field("path", path, Field.Store.YES, Field.Index.NO, Field.TermVector.NO)); document.add(new Field("title", title, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS)); document.add(new Field("content", content, Field.TermVector.WITH_POSITIONS_OFFSETS));
indexWriter.addDocument(document); } } indexWriter.commit(); indexWriter.optimize(); indexWriter.close(); } |
3.2 搜索文档
在上面一部分中,我们已经为一个目录下的文本文档建立好了索引,现在在这个索引上进行搜索以找到包含某个关键词或短语的文档。Lucene 提供了几个基础的类来完成这个过程,它们分别是呢 IndexSearcher, Query, QueryParser,TopDocs. 下面我们分别介绍这几个类的功能。
Query
这是一个抽象类,Lucene针对不同的类型提供了不同的实现,比如 TermQuery, BooleanQuery, PrefixQuery,PhraseQuery
等
. 这个类的目的是把用户输入的查询字符串封装成 Lucene 能够识别的 Query。
QueryParser
如果不乐意去了解诸如BooleanQuery,PhraseQuery等看上去复杂的查询类型。希望的是输入一个字符串,它就能够理解用户的搜索意图,然后转换成lucene中合理的Query子类,提供给lucene进行搜索,那这个就是QueryParser。QueryParser能够根据用户的输入来进行解析,自动构建合适的Query对象。
IndexSearcher
IndexSearcher 是用来在建立好的索引上进行搜索的。它只能以只读的方式打开一个索引,所以可以有多个 IndexSearcher的实例在一个索引上进行操作。
TopDocs
TopDocs是用来保存搜索的结果。保存前N条得分高的记录。
使用例子
public List search(String strQuery) throws Exception { List searchResult = new ArrayList(); String indexDir = "d:\\Temp\\lucence\\indexDir"; String field = "content"; Analyzer analyzer = new IKAnalyzer(true); // 使用中文分词器
Directory fsDirectory = FSDirectory.open(new File(indexDir)); IndexSearcher indexSearcher = new IndexSearcher(fsDirectory, true);
QueryParser queryParser = new QueryParser(Version.LUCENE_34, field, analyzer); Query query = queryParser.parse(strQuery);
if (null != query && null != indexSearcher) { TopDocs hits = indexSearcher.search(query, 1000); int totalHits = hits.totalHits; int len = Math.min(1000, totalHits);
ScoreDoc[] docs = hits.scoreDocs; for (int i = 0; i < len; i++) { SearchResultBean resultBean = new SearchResultBean();
Document doc = indexSearcher.doc(docs[i].doc); resultBean.setHtmlPath(doc.get("path")); resultBean.setHtmlTitle(doc.get("title")); searchResult.add(resultBean); } } return searchResult; } |