一个简单的搜索应用程序
假设我们的电脑的目录中含有很多文本文档,我们需要查找哪些文档含有某个关键词。为了实现这种功能,我们首先利用Lucene对这个目录中的文档建立索引,然后在建立好的索引中搜索我们所要查找的文档。
建立索引
为了对文档进行索引,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,它表示一个存储在内存当中的索引的位置。
熟悉了建立索引所需要的这些类后,我们就开始对某个目录下面的文本文件建立索引,清单1给出了对某个目录下的文本文件建立索引的源代码。
清单1、对文本文件建立索引
public class TxtFileIndexer {
public static void main(String[] args) throws IOException {
//indexDir is the directory that hosts Lucene's index files
Directory indexDir = FSDirectory.open(new File("C:\\luceneIndex"));
//dataDir is the directory that hosts the text files that to be indexed
File dataDir = new File("C:\\luceneData");
Analyzer luceneAnalyzer = new StandardAnalyzer(Version.LUCENE_40);
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_40, luceneAnalyzer);
File[] dataFiles = dataDir.listFiles();
IndexWriter indexWriter = new IndexWriter(indexDir, iwc);
long startTime = new Date().getTime();
for(int i=0; i<dataFiles.length; i++){
if(dataFiles[i].isFile() && dataFiles[i].getName().endsWith(".txt")){
System.out.println("Indexing file " + dataFiles[i].getCanonicalPath());
Document document = new Document();
Reader txtReader = new FileReader(dataFiles[i]);
document.add(new StringField("path", dataFiles[i].getPath(), Field.Store.YES));
document.add(new TextField("contents", txtReader));
indexWriter.addDocument(document);
}
}
indexWriter.close();
long endTime = new Date().getTime();
System.out.println("It takes " + (endTime - startTime)
+ " milliseconds to create index for the files in directory "
+ dataDir.getPath());
}
}
搜索文档
利用Lucene进行搜索就像建立索引一样也是非常方便的。在上面的一部分中,我们已经为目录下的文本文档建立好了索引,现在我们就要在这个索引上进行搜索以找到包含某个关键词或短语的文档。Lucene提供了几个基础的类完成这个过程,它们分别是IndexSearcher、Term、Query、TermQuery、Hits。
Query
这是一个抽象类,它有多个实现,比如TermQuery、BooleanQuery、PrefixQuery。这个类的目的是把用户输入 的查询字符串封装Lucene能够识别的Query。
Term
Term是搜索的基本单位,一个Term对象有两个String类型的域组成。生成一个Term对象可以有如下一条语句来完成:Term term = new Term("fieldName", "queryWord");其中第一个参数代表了要在文档的哪一个Field上进行查找,第二个参数代表了要查询的关键词。
TermQuery
TermQuery是抽象类Query的一个子类,它同时也是Lucene支持的最为基本的一个查询类。生成一个TermQuery对象由如下语句完成:TermQuery termQuery = new TermQuery(new Term("fieldName", "queryWord"));它的构造函数只接受一个参数,那就是一个Term对象。
IndexSearcher
IndexSearcher是用来在建立好的索引上进行搜索的。它只能以只读的方式打开一个索引,所以可以有多个IndexSearcher的实例在一个索引上进行操作。
Hits
Hits是用来保存搜索的结果的
清单2、给出了完成搜索功能所需要的代码
package cn.lichunan.test;
import java.io.File;
import java.io.IOException;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
public class TxtFileSearcher {
public static void main(String[] args) throws IOException {
String queryStr = "DEBUG";
// This is the directory that hosts the Lucene index
File indexDir = new File("C:\\luceneIndex");
FSDirectory directory = FSDirectory.open(indexDir);
IndexReader reader = DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
if (!indexDir.exists()) {
System.out.println("The Lucene index is not exist");
return;
}
Term term = new Term("contents", queryStr.toLowerCase());
TermQuery luceneQuery = new TermQuery(term);
int hitsPerPage = 3;
TopDocs results = searcher.search(luceneQuery, 5 * hitsPerPage);
ScoreDoc[] hits = results.scoreDocs;
for(int i=0; i<hits.length; i++){
Document document = searcher.doc(hits[i].doc);
System.out.println("File: " + document.get("path"));
}
}
}