官网: http://lucene.apache.org/
lucene中国: lucene.com.cn
1. 简介
Lucene 是 apache 软件基金会 4 jakarta 项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,
提供了 完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。 Lucene 的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现
全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。
2. 下载
http://labs.renren.com/apache-mirror//lucene/java/3.0.3/
3. 测试
在 eclipse 中邪见项目 Lucence3.0Test, 将一下包导入到 build 路径中
lucene-core-3.0.2.jar
lucene-demos-3.0.2.jar
lucene-analyzers-3.0.2.jar
lucene-fast-vector-highlighter-3.0.2.jar
lucene-highlighter-3.0.2.jar
lucene-memory-3.0.2.jar
在任意目录下新建两个文件夹:
用来存放 lucence 进行分词的文件和生成的 index 。如下图: file1 用来存放进行分词的文件,里面存放有 N 个 txt 文件, txt 文件的内容任意,如:我们都是中国人, index 文件夹是新建的,里面不要有任何的文件,是用来存储生成的 index 的
4. 代码
新建创建索引的类,以及测试
import
java.io.BufferedReader;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.IOException;
import
java.io.InputStreamReader;
import
java.util.Date;
import
org.apache.lucene.analysis.Analyzer;
import
org.apache.lucene.document.DateTools;
import
org.apache.lucene.document.Document;
import
org.apache.lucene.document.Field;
import
org.apache.lucene.index.IndexWriter;
import
org.apache.lucene.store.FSDirectory;
import
org.wltea.analyzer.lucene.IKAnalyzer;
public
class
IndexerOK {
private
static
String INDEX_DIR = "D:\\nutchwork\\LucenceTestDir\\index";
//
索引存放目录
private
static
String DATA_DIR = "D:\\nutchwork\\LucenceTestDir\\file1";
//
小文件存放的目录
public
static
void
main(String[] args)
throws
Exception {
long
start =
new
Date().getTime();
int
numIndexed = index(
new
File(INDEX_DIR),
new
File(DATA_DIR));
//
调用
index
方法
long
end =
new
Date().getTime();
System.out.println("Indexing " + numIndexed + " files took "
+ (end - start) + " milliseconds");
}
/**
*
索引
dataDir
下的
.txt
文件,并储存在
indexDir
下,返回索引的文件数量
*
*
@param
indexDir
*
@param
dataDir
*
@return
int
*
@throws
IOException
*/
public
static
int
index(File indexDir, File dataDir)
throws
IOException {
if
(!dataDir.exists() || !dataDir.isDirectory()) {
throw
new
IOException(dataDir
+ " does not exist or is not a directory");
}
Analyzer analyzer =
new
IKAnalyzer();
//
采用的分词器
//
第三个参数 为
true
表示新建,
false
表示添加到原有索引中
IndexWriter writer =
new
IndexWriter(FSDirectory.open(indexDir),
analyzer,
true
, IndexWriter.MaxFieldLength.LIMITED);
indexDirectory(writer, dataDir);
//
调用
indexDirectory
方法
int
numIndexed = writer.numDocs();
writer.optimize();
writer.close();
return
numIndexed;
}
/**
*
循环遍历目录下的所有
.txt
文件并进行索引
*
*
@param
writer
*
@param
dir
*
@throws
IOException
*/
private
static
void
indexDirectory(IndexWriter writer, File dir)
throws
IOException {
File[] files = dir.listFiles();
for
(
int
i = 0; i < files.length; i++) {
File f = files[i];
if
(f.isDirectory()) {
indexDirectory(writer, f);
// recurse
}
else
if
(f.getName().endsWith(".txt")) {
indexFile(writer, f);
}
}
}
/**
*
对单个
txt
文件进行索引
*
*
@param
writer
*
@param
f
*
@throws
IOException
*/
private
static
void
indexFile(IndexWriter writer, File f)
throws
IOException {
if
(f.isHidden() || !f.exists() || !f.canRead()) {
return
;
}
System.out.println("Indexing " + f.getCanonicalPath());
Document doc =
new
Document();
// doc.add(new Field("contents", new FileReader(f)));
doc.add(
new
Field("filename", f.getCanonicalPath(), Field.Store.YES, Field.Index.ANALYZED));
String temp = FileReaderAll(f.getCanonicalPath(), "GBK");
System.out.println(temp);
doc.add(
new
Field("TTT", temp, Field.Store.YES, Field.Index.ANALYZED));
doc.add(
new
Field("path", f.getPath(), Field.Store.YES,
Field.Index.ANALYZED));
doc.add(
new
Field("modified", DateTools.timeToString(f.lastModified(),
DateTools.Resolution.MINUTE), Field.Store.YES,
Field.Index.ANALYZED));
FileInputStream fis =
new
FileInputStream(f);
//
按照
UTF-8
编码方式将字节流转化为字符流
InputStreamReader isr =
new
InputStreamReader(fis, "utf-8");
//
从字符流中获取文本并进行缓冲
BufferedReader br =
new
BufferedReader(isr);
doc.add(
new
Field("contents", br));
writer.setUseCompoundFile(
false
);
writer.addDocument(doc);
}
public
static
String FileReaderAll(String FileName, String charset)
throws
IOException {
BufferedReader reader =
new
BufferedReader(
new
InputStreamReader(
new
FileInputStream(FileName), charset));
String line =
new
String();
String temp =
new
String();
while
((line = reader.readLine()) !=
null
) {
temp += line;
}
reader.close();
return
temp;
}
}
运行结果:
Indexing D:\nutchwork\LucenceTestDir\file1\1.txt
我们是中国人
Indexing D:\nutchwork\LucenceTestDir\file1\2.txt
我们是中国人
Indexing D:\nutchwork\LucenceTestDir\file1\3.txt
我们是中国人
Indexing D:\nutchwork\LucenceTestDir\file1\4.txt
我们是中国人
Indexing 4 files took 2293 milliseconds
新建查询的类以及测试:
import
java.io.File;
import
java.io.StringReader;
import
java.util.Date;
import
java.util.List;
import
org.apache.lucene.analysis.Analyzer;
import
org.apache.lucene.analysis.TokenStream;
import
org.apache.lucene.document.Document;
import
org.apache.lucene.document.Fieldable;
import
org.apache.lucene.search.IndexSearcher;
import
org.apache.lucene.search.Query;
import
org.apache.lucene.search.ScoreDoc;
import
org.apache.lucene.search.Sort;
import
org.apache.lucene.search.SortField;
import
org.apache.lucene.search.TopDocs;
import
org.apache.lucene.search.highlight.Highlighter;
import
org.apache.lucene.search.highlight.QueryScorer;
import
org.apache.lucene.search.highlight.SimpleFragmenter;
import
org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import
org.apache.lucene.store.FSDirectory;
import
org.wltea.analyzer.lucene.IKAnalyzer;
import
org.wltea.analyzer.lucene.IKQueryParser;
import
org.wltea.analyzer.lucene.IKSimilarity;
public
class
SearchQueryOK {
private
static
String INDEX_DIR = "D:\\nutchwork\\LucenceTestDir\\index";
//
索引所在的路径
private
static
String KEYWORD = "
中国人
";
//
关键词
private
static
int
TOP_NUM = 100;
//
显示前
100
条结果
public
static
void
main(String[] args)
throws
Exception {
File indexDir =
new
File(INDEX_DIR);
if
(!indexDir.exists() || !indexDir.isDirectory()) {
throw
new
Exception(indexDir
+ " does not exist or is not a directory.");
}
search(indexDir, KEYWORD);
//
调用
search
方法进行查询
}
/**
*
查询
*
*
@param
indexDir
*
@param
q
*
@throws
Exception
*/
public
static
void
search(File indexDir, String q)
throws
Exception {
IndexSearcher is =
new
IndexSearcher(FSDirectory.open(indexDir),
true
);
// read-only
String[] field = {"TTT","modified","filename"};
long
start =
new
Date().getTime();
// start time
//
高亮设置
Analyzer analyzer =
new
IKAnalyzer();
//
设定分词器
Query query2 = IKQueryParser.parseMultiField(field, KEYWORD);
//
实例化搜索器
IndexSearcher isearcher1 =
new
IndexSearcher(FSDirectory.open(indexDir));
//
在索引器中使用
IKSimilarity
相似度评估器
isearcher1.setSimilarity(
new
IKSimilarity());
Sort sort =
new
Sort(
new
SortField("path", SortField.DOC,
false
));
//TermQuery q1 = new TermQuery(new Term("filename", "1"));
//
搜索相似度最高的记录
TopDocs topDocs1 = isearcher1.search(query2,
null
, TOP_NUM,sort);
ScoreDoc[] hits3 = topDocs1.scoreDocs;
SimpleHTMLFormatter simpleHtmlFormatter =
new
SimpleHTMLFormatter(
"<span style='color:#ff0000'>", "</span>");
//
设定高亮显示的格式,也就是对高亮显示的词组加上前缀后缀
Highlighter highlighter =
new
Highlighter(simpleHtmlFormatter,
new
QueryScorer(query2));
for
(
int
i = 0; i < hits3.length; i++) {
Document doc = is.doc(hits3[i].doc);
String docTTT = doc.get("TTT");
highlighter.setTextFragmenter(
new
SimpleFragmenter(docTTT.length()));
//
设置每次返回的字符数
.
想必大家在使用搜索引擎的时候也没有一并把全部数据展示出来吧,当然这里也是设定只展示部分数据
TokenStream tokenStream = analyzer.tokenStream("",
new
StringReader(docTTT));
String str = highlighter.getBestFragment(tokenStream, docTTT);
System.out.println("
高亮设置
: " + str );
String docModified = doc.get("filename");
highlighter.setTextFragmenter(
new
SimpleFragmenter(docModified.length()));
TokenStream tokenStream2 = analyzer.tokenStream("",
new
StringReader(docModified));
String str2 = highlighter.getBestFragment(tokenStream2, docModified);
System.out.println("
高亮设置
: " + str2 );
List<Fieldable> list = doc.getFields();
for
(
int
j = 0; j < list.size(); j++) {
Fieldable fieldable = list.get(j);
System.out.println(fieldable.name() + " : "
+ fieldable.stringValue() + "<br>");
}
}
long
end =
new
Date().getTime();
// end time
System.out.println("Found " + hits3.length
+ " document(s) (in " + (end - start)
+ " milliseconds) that matched query '" + q + "':");
}
}
对索引的操作类:
import
java.io.File;
import
java.io.IOException;
import
java.sql.Connection;
import
java.sql.SQLException;
import
org.apache.lucene.analysis.Analyzer;
import
org.apache.lucene.analysis.standard.StandardAnalyzer;
import
org.apache.lucene.document.Document;
import
org.apache.lucene.document.Field;
import
org.apache.lucene.index.IndexReader;
import
org.apache.lucene.index.IndexWriter;
import
org.apache.lucene.index.Term;
import
org.apache.lucene.store.Directory;
import
org.apache.lucene.store.FSDirectory;
import
org.apache.lucene.util.Version;
import
org.wltea.analyzer.lucene.IKAnalyzer;
public
class
ManageIndexFile {
private
static
String INDEX_DIR = "D:\\nutchwork\\LucenceTestDir\\index";
//
索引存放目录
//
删除索引
public
static
void
DeleteIndex(SearchDocBean bean)
throws
IOException {
Directory dir = FSDirectory.open(
new
File(INDEX_DIR));
IndexReader reader = IndexReader.open(dir,
false
);
Term term =
new
Term("modified", bean.getId());
int
count = reader.deleteDocuments(term);
reader.close();
System.out.println("Successful Delete " + count + " path==" + bean.getId());
}
public
static
void
DeleteIndex(
int
[] posIDS)
throws
IOException {
Directory dir = FSDirectory.open(
new
File(INDEX_DIR));
IndexReader reader = IndexReader.open(dir,
false
);
for
(
int
i = 0; i < posIDS.length; i++) {
Term term =
new
Term("posID", Integer.toString(posIDS[i]));
reader.deleteDocuments(term);
}
reader.close();
}
//
更新索引
public
static
void
UpdateIndex(SearchDocBean bean)
throws
IOException {
Directory dir = FSDirectory.open(
new
File(INDEX_DIR));
IndexReader reader = IndexReader.open(dir,
false
);
Term term =
new
Term("modified", bean.getId());
reader.deleteDocuments(term);
reader.close();
IndexWriter writer =
new
IndexWriter(FSDirectory.open(
new
File(
INDEX_DIR)),
new
StandardAnalyzer(Version.LUCENE_CURRENT),
true
, IndexWriter.MaxFieldLength.LIMITED);
Document doc =
new
Document();
doc.add(
new
Field("modified", bean.getId(), Field.Store.YES,
Field.Index.NOT_ANALYZED));
writer.addDocument(doc);
writer.optimize();
writer.close();
}
//
增加索引
public
static
void
AddIndex(SearchDocBean bean,
Connection conn)
throws
IOException, SQLException {
Analyzer analyzer =
new
IKAnalyzer();
//
采用的分词器
IndexWriter writer =
new
IndexWriter(FSDirectory.open(
new
File(
INDEX_DIR)), analyzer,
false
,
IndexWriter.MaxFieldLength.LIMITED);
Document doc =
new
Document();
doc.add(
new
Field("filename", bean.getFileName(), Field.Store.YES,
Field.Index.ANALYZED));
doc.add(
new
Field("path", bean.getPath(), Field.Store.YES,
Field.Index.ANALYZED));
doc.add(
new
Field("dateTime", bean.getId(), Field.Store.YES,
Field.Index.ANALYZED));
doc.add(
new
Field("TTT", bean.getContents(), Field.Store.YES, Field.Index.ANALYZED));
writer.setUseCompoundFile(
false
);
writer.addDocument(doc);
writer.optimize();
writer.close();
}
}
封装起来的查询结果:
public
class
SearchDocBean {
private
String id;
private
String path;
private
String contents;
private
String dateTime;
public
String getId() {
return
id;
}
public
void
setId(String id) {
this
.id = id;
}
public
String getPath() {
return
path;
}
public
void
setPath(String path) {
this
.path = path;
}
public
String getContents() {
return
contents;
}
public
void
setContents(String contents) {
this
.contents = contents;
}
public
String getDateTime() {
return
dateTime;
}
public
void
setDateTime(String dateTime) {
this
.dateTime = dateTime;
}
public
String getFileName() {
return
fileName;
}
public
void
setFileName(String fileName) {
this
.fileName = fileName;
}
private
String fileName;
}
下面是 serach 中国人的 结果:
高亮设置
: <span style='color:#ff0000'>
中国人
</span>
高亮设置
: null
filename : D:\nutchwork\LucenceTestDir\file1\1.txt<br>
TTT :
我们是中国人
<br>
path : D:\nutchwork\LucenceTestDir\file1\1.txt<br>
modified : 201107161115<br>
高亮设置
: <span style='color:#ff0000'>
中国人
</span>
高亮设置
: null
filename : D:\nutchwork\LucenceTestDir\file1\2.txt<br>
TTT :
我们是中国人
<br>
path : D:\nutchwork\LucenceTestDir\file1\2.txt<br>
modified : 201107161115<br>
高亮设置
: <span style='color:#ff0000'>
中国人
</span>
高亮设置
: null
filename : D:\nutchwork\LucenceTestDir\file1\3.txt<br>
TTT :
我们是中国人
<br>
path : D:\nutchwork\LucenceTestDir\file1\3.txt<br>
modified : 201107161115<br>
高亮设置
: <span style='color:#ff0000'>
中国人
</span>
高亮设置
: null
filename : D:\nutchwork\LucenceTestDir\file1\4.txt<br>
TTT :
我们是中国人
<br>
path : D:\nutchwork\LucenceTestDir\file1\4.txt<br>
modified : 201107161115<br>
Found 4 document(s) (in 717 milliseconds) that matched query '
中国人
':
整个工程:基本上是从网上找到的代码,运行了下,算是有一个大概的了解。
Lucene 简介
Lucene 是一个基于 Java 的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能。 Lucene 目前是 Apache Jakarta 家族中的一个开源项目。也是目前最为流行的基于 Java 开源全文检索工具包。
目前已经有很多应用程序的搜索功能是基于 Lucene 的,比如 Eclipse 的帮助系统的搜索功能。 Lucene 能够为文本类型的数据建立索引,所以你只要能把你要索引的数据格式转化的文本的, Lucene 就能对你的文档进行索引和搜索。比如你要对一些 HTML 文档, PDF 文档进行索引的话你就首先需要把 HTML 文档和 PDF 文档转化成文本格式的,然后将转化后的内容交给 Lucene 进行索引,然后把创建好的索引文件保存到磁盘或者内存中,最后根据用户输入的查询条件在索引文件上进行查询。不指定要索引的文档的格式也使 Lucene 能够几乎适用于所有的搜索应用程序。
图 1 表示了搜索应用程序和 Lucene 之间的关系,也反映了利用 Lucene 构建搜索应用程序的流程:
索引是现代搜索引擎的核心,建立索引的过程就是把源数据处理成非常方便查询的索引文件的过程。为什么索引这么重要呢,试想你现在要在大量的文 档中搜索含有某个关键词的文档,那么如果不建立索引的话你就需要把这些文档顺序的读入内存,然后检查这个文章中是不是含有要查找的关键词,这样的话就会耗 费非常多的时间,想想搜索引擎可是在毫秒级的时间内查找出要搜索的结果的。这就是由于建立了索引的原因,你可以把索引想象成这样一种数据结构,他能够使你 快速的随机访问存储在索引中的关键词,进而找到该关键词所关联的文档。 Lucene 采用的是一种称为反向索引( inverted index )的机制。反向索引就是说我们维护了一个词 / 短语表,对于这个表中的每个词 / 短语,都有一个链表描述了有哪些文档包含了这个词 / 短语。这样在用户输入查询条件的时候,就能非常快的得到搜索结果。我们将在本系列文章的第二部分详细介绍 Lucene 的索引机制,由于 Lucene 提供了简单易用的 API ,所以即使读者刚开始对全文本进行索引的机制并不太了解,也可以非常容易的使用 Lucene 对你的文档实现索引。
对文档建立好索引后,就可以在这些索引上面进行搜索了。搜索引擎首先会对搜索的关键词进行解析,然后再在建立好的索引上面进行查找,最终返回和用户输入的关键词相关联的文档。
Lucene 软件包分析
Lucene 软件包的发布形式是一个 JAR 文件,下面我们分析一下这个 JAR 文件里面的主要的 JAVA 包,使读者对之有个初步的了解。
Package: org.apache.lucene.document
这个包提供了一些为封装要索引的文档所需要的类,比如 Document, Field 。这样,每一个文档最终被封装成了一个 Document 对象。
Package: org.apache.lucene.analysis
这个包主要功能是对文档进行分词,因为文档在建立索引之前必须要进行分词,所以这个包的作用可以看成是为建立索引做准备工作。
Package: org.apache.lucene.index
这个包提供了一些类来协助创建索引以及对创建好的索引进行更新。这里面有两个基础的类: IndexWriter 和 IndexReader ,其中 IndexWriter 是用来创建索引并添加文档到索引中的, IndexReader 是用来删除索引中的文档的。
Package: org.apache.lucene.search
这个包提供了对在建立好的索引上进行搜索所需要的类。比如 IndexSearcher 和 Hits, IndexSearcher 定义了在指定的索引上进行搜索的方法, Hits 用来保存搜索得到的结果。
假设我们的电脑的目录中含有很多文本文档,我们需要查找哪些文档含有某个关键词。为了实现这种功能,我们首先利用 Lucene 对这个目录中的文档建立索引,然后在建立好的索引中搜索我们所要查找的文档。通过这个例子读者会对如何利用 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 给出了对某个目录下的文本文件建立索引的源代码。
package TestLucene; import java.io.File; import java.io.FileReader; import java.io.Reader; import java.util.Date; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexWriter; /** * This class demonstrate the process of creating index with Lucene * for text files */ public class TxtFileIndexer { public static void main(String[] args) throws Exception{ //indexDir is the directory that hosts Lucene's index files File indexDir = new File("D:\\luceneIndex"); //dataDir is the directory that hosts the text files that to be indexed File dataDir = new File("D:\\luceneData"); Analyzer luceneAnalyzer = new StandardAnalyzer(); File[] dataFiles = dataDir.listFiles(); IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true); 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(Field.Text("path",dataFiles[i].getCanonicalPath())); document.add(Field.Text("contents",txtReader)); indexWriter.addDocument(document); } } indexWriter.optimize(); 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()); } } |
在清单 1 中,我们注意到类 IndexWriter 的构造函数需要三个参数,第一个参数指定了所创建的索引要存放的位置,他可以是一个 File 对象,也可以是一个 FSDirectory 对象或者 RAMDirectory 对象。第二个参数指定了 Analyzer 类的一个实现,也就是指定这个索引是用哪个分词器对文挡内容进行分词。第三个参数是一个布尔型的变量,如果为 true 的话就代表创建一个新的索引,为 false 的话就代表在原来索引的基础上进行操作。接着程序遍历了目录下面的所有文本文档,并为每一个文本文档创建了一个 Document 对象。然后把文本文档的两个属性:路径和内容加入到了两个 Field 对象中,接着在把这两个 Field 对象加入到 Document 对象中,最后把这个文档用 IndexWriter 类的 add 方法加入到索引中去。这样我们便完成了索引的创建。接下来我们进入在建立好的索引上进行搜索的部分。
利用 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 TestLucene; import java.io.File; import org.apache.lucene.document.Document; import org.apache.lucene.index.Term; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.FSDirectory; /** * This class is used to demonstrate the * process of searching on an existing * Lucene index * */ public class TxtFileSearcher { public static void main(String[] args) throws Exception{ String queryStr = "lucene"; //This is the directory that hosts the Lucene index File indexDir = new File("D:\\luceneIndex"); FSDirectory directory = FSDirectory.getDirectory(indexDir,false); IndexSearcher searcher = new IndexSearcher(directory); 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); Hits hits = searcher.search(luceneQuery); for(int i = 0; i < hits.length(); i++){ Document document = hits.doc(i); System.out.println("File: " + document.get("path")); } } } |
在清单 2 中,类 IndexSearcher 的构造函数接受一个类型为 Directory 的对象, Directory 是一个抽象类,它目前有两个子类: FSDirctory 和 RAMDirectory. 我们的程序中传入了一个 FSDirctory 对象作为其参数,代表了一个存储在磁盘上的索引的位置。构造函数执行完成后,代表了这个 IndexSearcher 以只读的方式打开了一个索引。然后我们程序构造了一个 Term 对象,通过这个 Term 对象,我们指定了要在文档的内容中搜索包含关键词 ”lucene” 的文档。接着利用这个 Term 对象构造出 TermQuery 对象并把这个 TermQuery 对象传入到 IndexSearcher 的 search 方法中进行查询,返回的结果保存在 Hits 对象中。最后我们用了一个循环语句把搜索到的文档的路径都打印了出来。 好了,我们的搜索应用程序已经开发完毕,怎么样,利用 Lucene 开发搜索应用程序是不是很简单。
本文首先介绍了 Lucene 的一些基本概念,然后开发了一个应用程序演示了利用 Lucene 建立索引并在该索引上进行搜索的过程。希望本文能够为学习 Lucene 的读者提供帮助。