先上一个使用Lucene读写文件的DEMO
import java.io.IOException;
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.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
public class IndexAndSearchExample {
public static void main(String[] args) throws IOException {
// 创建内存中的索引目录
Directory indexDir = new RAMDirectory();
// 创建分词器。
Analyzer analyzer = new StandardAnalyzer();
// 配置IndexWriter
IndexWriterConfig config = new IndexWriterConfig(analyzer);
//IndexWriter构建时会检查目录下是否有索引,没有则写入新索引。如果有则只向索引添加内容
IndexWriter writer = new IndexWriter(indexDir, config);
// 创建文档
Document doc1 = new Document();
doc1.add(new TextField("title", "Lucene in Action", Field.Store.YES));
doc1.add(new TextField("description", "Lucene is a powerful search library", Field.Store.YES));
writer.addDocument(doc1);
Document doc2 = new Document();
doc2.add(new TextField("title", "Java Development with Ant", Field.Store.YES));
doc2.add(new TextField("description", "Learn how to use Ant to build, test, and deploy your Java applications", Field.Store.YES));
writer.addDocument(doc2);
// 提交文档,IndexWriter会向Directory提交写入变化。IndexWriter还可以继续使用
writer.commit();
//关闭IndexWriter.也会触发提交文档
writer.close();
// 创建IndexSearcher,能够对指定Directory搜索
DirectoryReader reader = DirectoryReader.open(indexDir);
IndexSearcher searcher = new IndexSearcher(reader);
// 构建查询
Query query = new TermQuery(new Term("title", "lucene"));
// 执行查询
ScoreDoc[] hits = searcher.search(query, 10).scoreDocs;
// 遍历结果
for (ScoreDoc hit : hits) {
Document result = searcher.doc(hit.doc);
System.out.println(result.get("title") + " : " + result.get("description"));
}
// 关闭IndexReader
reader.close();
}
}
索引文件所在目录,存储一批文件的抽象层。提供文件增删查改的方法。
分词器。用于将text分割成更小的term(词汇单元),还可能会执行大小写转换、无用词删除等操作
document组成部分,有name,type,value属性。值可以是string、number、byte[]。包含以下实例化选项
索引和查询的单元,由一些field组成
Lucene的Index通过DocId来唯一标识一个Doc.
IndexWriter创建并维护索引。同一时间一个索引只能有一个IndexWriter,该功能通过文件锁实现。
每个更改索引的方法都会返回一个序列号,它表示应用每个更改的有效顺序。 commit 还返回一个序列号,描述哪些更改在提交点中,哪些不在。序列号是暂时的(不会以任何方式保存到索引中)并且仅在单个 IndexWriter 实例中有效。
这些数据修改缓存在内存中并周期性的flush到Directory,自上次flush之后当有足够的doc时将触发flush。flush只是将缓存的数据修改移动到索引,但这些数据修改对Reader不可见,直到调用commit或close。
DWPT线程的数量等于调用IndexWriter的写接口的线程数量
将doc加到索引中。这个方法周期性调用flush和segment merge。
IndexWriter.optimize()可以进行段合并,可以提升搜索速度,合并期间会消耗大量的CPU和IO资源,并且需要额外的磁盘空间保存新的段,调用commit之前旧的段不会被删除,结束之后占用的磁盘空间比之前要少
将所有内存中的segments移动到Directory(有FSDirectory,RAMDirectory),不会等待数据真正写入磁盘(对于linux数据会先写到filesystem cache),但不会进行commit,所以数据不可读。
IndexWriter.commit()将提交所有pending的更改(add doc\delete doc\ segment merge)到索引,并同步相关的索引文件(会等待文件真正的持久存储而不是写到filesystem cache就返回),所以这些更改对IndexReader来说是可见的。并且更新内容不会因为系统崩溃而丢失。
换句话说,commit会触发flush并使数据可读
flush内存中缓存的doc,创建并返回一个包含这些doc的Reader,涵盖对索引的所有已提交(commited)和未提交(un-commited)的更改,这些更改可读并且不需要调用commit。
请注意,这在功能(结果而不是过程)上等同于调用 {flush} 然后打开一个新的reader。但是这种方法的周转时间应该更快,因为它避免了可能代价高昂的commit。
这提供了near real-time search,无需commit就能使数据可以搜索。叫做近实时的原因是——没有保证当对IndexWriter进行更改后你能多快的获得新的Reader。
提供接口访问某一时间点的索引。直到新的IndexReader被打开前,所有通过IndexWriter完成的更改都不会可见。同一时间一个索引可以有多个reader
获取一个新Reader,包含最新的数据。
DirectoryReader.openIfChanged底层会调用IndexWriter.getReader,该方法会使IndexWriter立马刷新出新的段内容(flush),而不是等到内存缓冲区满。
通过IndexReader实现查询。出于性能的原因,如果索引未更改应该在多个查询之间共享IndexSearcher,而不是创建新的索引。如果索引更改了,需要调用DirectoryReader.openIfChanged并创建新的IndexSearcher。