您的位置:首页 > 编程语言 > Java开发

[Java Web]Java的全文搜索类库 Lucene

2015-01-30 17:03 459 查看
Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。

Lucene的实现机制是倒排表。例如现在有2个文档需要建立索引,内容分别为"Lucene Learning"和"Lucene Hadoop",建立后的索引实际是这样的:


索引的优势在于:虽然建立索引会比较耗时,但是在一次建立后便可以永远支持高效的查询。

Lucene的核心类有:

Directory:索引对象,常用有RAMDirectory和FSDirectory两种,前者代表一个内存中的索引文件,后者代表一个本地的索引文件。

Filed:字段,由name和value组成,常用的字段分为三种:

StoredFiled:仅用来存储数据的字段,该字段的数据不会建立索引。
StringFiled、LongFiled等:将数据整体建立为索引的字段。
TextFiled:将数据分词并建立索引的字段。

Document:索引中存储的文档结构,一个文档由多个字段组成。

Term:词元,相当于索引中的键,每个Term都指向一个由文档组成的链表。

IndexReader:索引的读取流,可以从索引中读取出需要的文档。

IndexWriter:索引的输出流,将文档写入索引。

IndexSearcher:索引的搜索功能。

Query:搜索条件。

Analyzer:分词器,可以将字段中的数据分解成多个词元。

Lucene的流程:



写入:将数据源转换为文档,然后使用IndexWriter的addDocument方法将文档添加到索引。

查询:使用IndexReader获取一个IndexSearcher对象,并创建一个Query对象指定查询类型,然后使用IndexSearcher的search方法得到文档。

代码实例:

添加索引:
public static void init() throws IOException {
//索引文件
Directory dir = FSDirectory.open(new File("E:/index"));
//索引配置(指定Lucene版本和分词器)
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_0, new StandardAnalyzer());
//得到输出流
IndexWriter writer = new IndexWriter(dir, config);
//创建文档
Document doc = new Document();
//id会以一个整体被作为词元被索引 并且会被存储在文档中
doc.add(new StringField("id", "123", Field.Store.YES));
//content会被分词器分割成数个词元被索引 但不会存储在文档中
doc.add(new TextField("content", "Lucene是apache软件基金会4 jakarta" +
"项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎," +
"而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎," +
"部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件" +
"开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的" +
"功能,或者是以此为基础建立起完整的全文检索引擎。", Field.Store.NO));
//address会被分词器分割成数个词元被索引 并且会存储在文档中
doc.add(new TextField("address", "北京市海淀区翠微路凯德大厦", Field.Store.YES));
//将文档添加到索引
writer.addDocument(doc);
//打印当前已经被索引的文档个数
System.out.println("被索引的文档个数:" + writer.numDocs());
writer.close();
}


遍历索引中所有的文档:

public static void ergodic() throws IOException {
//索引文件
Directory dir = FSDirectory.open(new File("E:/index"));
//得到输入流
IndexReader reader = DirectoryReader.open(dir);
IndexSearcher searcher = new IndexSearcher(reader);
Document doc = null;
for (int i = 0; i < reader.maxDoc(); i++) {
doc = searcher.doc(i);
System.out.println("Doc [" + i + "] : id: "
+ doc.get("id") + ", desc: " + doc.get("content"));
}

}


搜索文档:
public static void search() throws IOException, ParseException {
//索引文件
Directory dir = FSDirectory.open(new File("E:/index.txt"));
//输入流
IndexReader reader = DirectoryReader.open(dir);
IndexSearcher searcher = new IndexSearcher(reader);
// 搜索条件
QueryParser parser = new QueryParser("desc",
new StandardAnalyzer());
Query query = parser.parse("索引文件");
// 搜索结果
TopDocs hits = searcher.search(query, 2);
System.out.println("查询出来的总数是:" + hits.totalHits);
// 获取搜索结果
Document doc = null;
for (ScoreDoc scoreDoc : hits.scoreDocs) {
doc = searcher.doc(scoreDoc.doc);
System.out.println("Doc [" + scoreDoc.doc + "] : id: "
+ doc.get("id") + ", desc: " + doc.get("content"));
}
}


一些细节:

对于一个索引文件,同时只能有一个输出流对它进行操作.
为了避免频繁的I/O操作,可以先将索引建立在RAMDirectory中,然后一次性写入本地文件。
中文分词库比较好用的有Ansj和IK,可以自行百度了解。
Lucene不支持去重,DuplicateFilter会先将索引进行去重后在进行条件查询,这样会造成数据缺失。
索引的更新可以先根据词元删除原本的文档后再添加新的文档,在批量操作时效率很高。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: