??xml version="1.0" encoding="utf-8" standalone="yes"?> 最q遇C个很奇怪的问题Q写了一个界面程序,刚开始没?讄字体Q效率还可以Q但是默认字体看着比较隄Q就改用了一个字体,谁知道在jdk1.4扚w试q程中,效率居然比原来要低非帔R常的多?br />
后来发现如果是jdk1.5及以上版本两者效率几乎一P见附件截图?br />
而且Swing效率和增强功能来ԌJDK1.6u10及以上版本有非常大的提高Q?br />
所以如果条件运行,q是都改成JDK1.6u10及以上版?/font> 试代码如下:
public class FontDemo extends JPanel {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setTitle("TWaver中文C");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new FontDemo());
f.setSize(800, 600);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private TDataBox box = new TDataBox();
private BarChart chart = new BarChart(box);
private static final int times = 1000;
private static final int style = Font.BOLD;
private static final int size = 16;
public FontDemo() {
initBox();
initChart();
initGUI();
}
private void initGUI() {
this.setLayout(new BorderLayout());
JScrollPane pane = new JScrollPane(chart.getLegendPane());
this.add(chart, BorderLayout.CENTER);
this.add(pane, BorderLayout.EAST);
}
private void initBox() {
final List localFonts = new ArrayList();
List nativeFonts = new ArrayList();
// get all available fontFamily names
Font[] fonts = SunGraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
for (int i = 0; i < fonts.length; i++) {
// separate logical and native font
if (SunGraphicsEnvironment.isLogicalFont(fonts[i])) {
localFonts.add(fonts[i]);
}
else {
nativeFonts.add(fonts[i]);
}
}
System.out.println("///////////// localFonts test /////////////");
for (int i = 0; i < localFonts.size(); i++) {
Font font = (Font) localFonts.get(i);
long start = System.currentTimeMillis();
for (int k = 0; k < times; k++) {
createFont(font);
}
long spendTime = System.currentTimeMillis() - start;
Node n = new Node();
n.setName(font.getName());
n.putChartValue(spendTime);
n.putChartColor(Color.GREEN);
box.addElement(n);
// System.out.println(">" + spendTime + "\t" + font.getName());
}
System.out.println("\n///////////// nativeFonts test /////////////");
for (int i = 0; i < nativeFonts.size(); i++) {
Font font = (Font) nativeFonts.get(i);
long start = System.currentTimeMillis();
for (int k = 0; k < times; k++) {
createFont(font);
}
long spendTime = System.currentTimeMillis() - start;
Node n = new Node();
n.setName(font.getName());
n.putChartValue(spendTime);
n.putChartColor(Color.RED);
box.addElement(n);
// System.out.println(">" + spendTime + "\t" + font.getName());
}
System.out.println("\n$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
}
private void createFont(Font font) {
// font.deriveFont(style, size);
new Font(font.getName(), style, size);
}
private void initChart() {
chart.setLegendLayout(TWaverConst.LEGEND_LAYOUT_VERTICAL);
chart.setLegendOrientation(TWaverConst.LABEL_ORIENTATION_HORIZONTAL);
chart.setYScaleTextVisible(true);
chart.setShadowOffset(1);
}
}
1.4试l果
1.6试l果
long free = runtime.freeMemory();
System.out.println(total+"-"+free);
(?
本文首先介绍了Lucene的一些基本概念,然后开发了一个应用程序演CZ利用Lucene建立索引q在该烦引上q行搜烦的过E?/span>
Lucene 是一个基?Java 的全文信息检索工具包Q它不是一个完整的搜烦应用E序Q而是Z的应用程序提供烦引和搜烦功能。Lucene 目前?Apache Jakarta 家族中的一个开源项目。也是目前最为流行的Z Java 开源全文检索工具包?/span>
目前已经有很多应用程序的搜烦功能是基?Lucene 的,比如 Eclipse 的帮助系l的搜烦功能。Lucene 能够为文本类型的数据建立索引Q所以你只要能把你要索引的数据格式{化的文本的,Lucene p对你的文档进行烦引和搜烦。比如你要对一?HTML 文档QPDF 文q行索引的话你就首先需要把 HTML 文?PDF 文转化成文本格式的Q然后将转化后的内容交给 Lucene q行索引Q然后把创徏好的索引文g保存到磁盘或者内存中Q最后根据用戯入的查询条g在烦引文件上q行查询。不指定要烦引的文档的格式也?Lucene 能够几乎适用于所有的搜烦应用E序?/span>
?1 表示了搜索应用程序和 Lucene 之间的关p,也反映了利用 Lucene 构徏搜烦应用E序的流E:
![]() ![]() |
索引是现代搜索引擎的核心Q徏立烦引的q程是把源数据处理成非常方便查询的索引文g的过E。ؓ什么烦引这么重要呢Q试想你现在要在大量的文中搜烦含有某个关键词的文Q那么如果不建立索引的话你就需要把q些文档序的读入内存,然后查这个文章中是不是含有要查找的关键词Q这L话就会耗费非常多的旉Q想x索引擎可是在毫秒U的旉内查扑և要搜索的l果的。这是׃建立了烦引的原因Q你可以把烦引想象成q样一U数据结构,他能够你快速的随机讉K存储在烦引中的关键词Q进而找到该关键词所兌的文。Lucene 采用的是一U称为反向烦引(inverted indexQ的机制。反向烦引就是说我们l护了一个词/短语表,对于q个表中的每个词/短语Q都有一个链表描qC有哪些文包含了q个?短语。这样在用户输入查询条g的时候,p非常快的得到搜烦l果。我们将在本pd文章的第二部分详l介l?Lucene 的烦引机Ӟ׃ Lucene 提供了简单易用的 APIQ所以即使读者刚开始对全文本进行烦引的机制q不太了解,也可以非常容易的使用 Lucene 对你的文实现烦引?/span>
Ҏ档徏立好索引后,可以在q些索引上面q行搜烦了。搜索引擎首先会Ҏ索的关键词进行解析,然后再在建立好的索引上面q行查找Q最l返回和用户输入的关键词相关联的文?/span>
![]() ![]() |
Lucene 软g包的发布形式是一?JAR 文gQ下面我们分析一下这?JAR 文g里面的主要的 JAVA 包,使读者对之有个初步的了解?/span>
Package: org.apache.lucene.document
q个包提供了一些ؓ装要烦引的文所需要的c,比如 Document, Field。这P每一个文档最l被装成了一?Document 对象?/span>
Package: org.apache.lucene.analysis
q个包主要功能是Ҏ进行分词,因ؓ文在徏立烦引之前必要q行分词Q所以这个包的作用可以看成是为徏立烦引做准备工作?/span>
Package: org.apache.lucene.index
q个包提供了一些类来协助创建烦引以及对创徏好的索引q行更新。这里面有两个基的类QIndexWriter ?IndexReaderQ其?IndexWriter 是用来创建烦引ƈd文档到烦引中的,IndexReader 是用来删除烦引中的文的?/span>
Package: org.apache.lucene.search
q个包提供了对在建立好的索引上进行搜索所需要的cR比?IndexSearcher ?Hits, IndexSearcher 定义了在指定的烦引上q行搜烦的方法,Hits 用来保存搜烦得到的结果?/span>
![]() ![]() |
假设我们的电脑的目录中含有很多文本文,我们需要查扑֓些文档含有某个关键词。ؓ了实现这U功能,我们首先利用 Lucene 对这个目录中的文徏立烦引,然后在徏立好的烦引中搜烦我们所要查扄文。通过q个例子读者会对如何利?Lucene 构徏自己的搜索应用程序有个比较清楚的认识?/span>
![]() ![]() |
ZҎ进行烦引,Lucene 提供了五个基的类Q他们分别是 Document, Field, IndexWriter, Analyzer, Directory。下面我们分别介l一下这五个cȝ用途:
Document
Document 是用来描q文档的Q这里的文可以指一?HTML 面Q一电子邮Ӟ或者是一个文本文件。一?Document 对象由多?Field 对象l成的。可以把一?Document 对象惌成数据库中的一个记录,而每?Field 对象是记录的一个字Dc?/span>
Field
Field 对象是用来描qC个文的某个属性的Q比如一电子邮件的标题和内容可以用两个 Field 对象分别描述?/span>
Analyzer
在一个文档被索引之前Q首先需要对文档内容q行分词处理Q这部分工作是?Analyzer 来做的。Analyzer cL一个抽象类Q它有多个实现。针对不同的语言和应用需要选择适合?Analyzer。Analyzer 把分词后的内容交l?IndexWriter 来徏立烦引?/span>
IndexWriter
IndexWriter ?Lucene 用来创徏索引的一个核心的c,他的作用是把一个个?Document 对象加到索引中来?/span>
Directory
q个cM表了 Lucene 的烦引的存储的位|,q是一个抽象类Q它目前有两个实玎ͼW一个是 FSDirectoryQ它表示一个存储在文gpȝ中的索引的位|。第二个?RAMDirectoryQ它表示一个存储在内存当中的烦引的位置?/span>
熟悉了徏立烦引所需要的q些cdQ我们就开始对某个目录下面的文本文件徏立烦引了Q清?l出了对某个目录下的文本文g建立索引的源代码?/span>
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(new Field("path", dataFiles[i].getCanonicalPath(),
|
在清?中,我们注意到类 IndexWriter 的构造函数需要三个参敎ͼW一个参数指定了所创徏的烦引要存放的位|,他可以是一?File 对象Q也可以是一?FSDirectory 对象或?RAMDirectory 对象。第二个参数指定?Analyzer cȝ一个实玎ͼ也就是指定这个烦引是用哪个分词器Ҏ挡内容进行分词。第三个参数是一个布型的变量,如果?true 的话׃表创Z个新的烦引,?false 的话׃表在原来索引的基上进行操作。接着E序遍历了目录下面的所有文本文档,qؓ每一个文本文档创Z一?Document 对象。然后把文本文的两个属性:路径和内容加入到了两?Field 对象中,接着在把q两?Field 对象加入?Document 对象中,最后把q个文?IndexWriter cȝ add Ҏ加入到烦引中厅R这h们便完成了烦引的创徏。接下来我们q入在徏立好的烦引上q行搜烦的部分?/span>
![]() ![]() |
利用Luceneq行搜烦像建立索引一样也是非常方便的。在上面一部分中,我们已经Z个目录下的文本文档徏立好了烦引,现在我们p在这个烦引上q行搜烦以找到包含某个关键词或短语的文。Lucene提供了几个基的类来完成这个过E,它们分别是呢IndexSearcher, Term, Query, TermQuery, Hits. 下面我们分别介绍q几个类的功能?/span>
Query
q是一个抽象类Q他有多个实玎ͼ比如TermQuery, BooleanQuery, PrefixQuery. q个cȝ目的是把用户输入的查询字W串装成Lucene能够识别的Query?/span>
Term
Term是搜索的基本单位Q一个Term对象有两个Stringcd的域l成。生成一个Term对象可以有如下一条语句来完成QTerm term = new Term(“fieldName”,”queryWord”); 其中W一个参C表了要在文的哪一个Field上进行查找,W二个参C表了要查询的关键词?/span>
TermQuery
TermQuery是抽象类Query的一个子c,它同时也是Lucene支持的最为基本的一个查询类。生成一个TermQuery对象由如下语句完成: TermQuery termQuery = new TermQuery(new Term(“fieldName”,”queryWord”)); 它的构造函数只接受一个参敎ͼ那就是一个Term对象?/span>
IndexSearcher
IndexSearcher是用来在建立好的索引上进行搜索的。它只能以只ȝ方式打开一个烦引,所以可以有多个IndexSearcher的实例在一个烦引上q行操作?/span>
Hits
Hits是用来保存搜索的l果的?/span>
介绍完这些搜索所必须的类之后Q我们就开始在之前所建立的烦引上q行搜烦了,清单2l出了完成搜索功能所需要的代码?/span>
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"));
}
}
}
|
在清?中,cIndexSearcher的构造函数接受一个类型ؓDirectory的对象,Directory是一个抽象类Q它目前有两个子c:FSDirctory和RAMDirectory. 我们的程序中传入了一个FSDirctory对象作ؓ其参敎ͼ代表了一个存储在盘上的索引的位|。构造函数执行完成后Q代表了q个IndexSearcher以只ȝ方式打开了一个烦引。然后我们程序构造了一个Term对象Q通过q个Term对象Q我们指定了要在文档的内容中搜烦包含关键?#8221;lucene”的文档。接着利用q个Term对象构造出TermQuery对象q把q个TermQuery对象传入到IndexSearcher的searchҎ中进行查询,q回的结果保存在Hits对象中。最后我们用了一个@环语句把搜烦到的文档的\径都打印了出来。好了,我们的搜索应用程序已l开发完毕,怎么P利用Lucene开发搜索应用程序是不是很简单?/span>
![]() ![]() |
本文首先介绍?Lucene 的一些基本概念,然后开发了一个应用程序演CZ利用 Lucene 建立索引q在该烦引上q行搜烦的过E。希望本文能够ؓ学习 Lucene 的读者提供帮助?br />
图一昄?Lucene 的烦引机制的架构。Lucene 使用各种解析器对各种不同cd的文进行解析。比如对?HTML 文QHTML 解析器会做一些预处理的工作,比如qo文中的 HTML 标签{等。HTML 解析器的输出的是文本内容Q接着 Lucene 的分词器(Analyzer)从文本内容中提取出烦引项以及相关信息Q比如烦引项的出现频率。接着 Lucene 的分词器把这些信息写到烦引文件中?/p>
![]() ![]() |
接下来我一步一步的来演C如何利?Lucene Z的文档创建烦引。只要你能将要烦引的文g转化成文本格式,Lucene pZ的文档徏立烦引。比如,如果你想?HTML 文或?PDF 文建立索引Q那么首先你需要从q些文中提取出文本信息Q然后把文本信息交给 Lucene 建立索引。我们接下来的例子用来演C如何利?Lucene 为后~名ؓ txt 的文件徏立烦引?/p>
1Q?准备文本文g
首先把一些以 txt 为后~名的文本文g攑ֈ一个目录中Q比如在 Windows q_上,你可以放?C:\\files_to_index 下面?/p>
2Q?创徏索引
清单1是ؓ我们所准备的文档创建烦引的代码?/p>
package lucene.index; 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 demonstrates the process of creating an index with Lucene * for text files in a directory. */ public class TextFileIndexer { public static void main(String[] args) throws Exception{ //fileDir is the directory that contains the text files to be indexed File fileDir = new File("C:\\files_to_index "); //indexDir is the directory that hosts Lucene's index files File indexDir = new File("C:\\luceneIndex"); Analyzer luceneAnalyzer = new StandardAnalyzer(); IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true); File[] textFiles = fileDir.listFiles(); long startTime = new Date().getTime(); //Add documents to the index for(int i = 0; i < textFiles.length; i++){ if(textFiles[i].isFile() >> textFiles[i].getName().endsWith(".txt")){ System.out.println("File " + textFiles[i].getCanonicalPath() + " is being indexed"); Reader textReader = new FileReader(textFiles[i]); Document document = new Document(); document.add(Field.Text("content",textReader)); document.add(Field.Text("path",textFiles[i].getPath())); indexWriter.addDocument(document); } } indexWriter.optimize(); indexWriter.close(); long endTime = new Date().getTime(); System.out.println("It took " + (endTime - startTime) + " milliseconds to create an index for the files in the directory " + fileDir.getPath()); } } |
正如清单1所C,你可以利?Lucene 非常方便的ؓ文创徏索引。接下来我们分析一下清?中的比较关键的代码,我们先从下面的一条语句开始看赗?/p>
Analyzer luceneAnalyzer = new StandardAnalyzer(); |
q条语句创徏了类 StandardAnalyzer 的一个实例,q个cL用来从文本中提取出烦引项的。它只是抽象c?Analyzer 的其中一个实现。Analyzer 也有一些其它的子类Q比?SimpleAnalyzer {?/p>
我们接着看另外一条语句:
IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true); |
q条语句创徏了类 IndexWriter 的一个实例,该类也是 Lucene 索引机制里面的一个关键类。这个类能创Z个新的烦引或者打开一个已存在的烦引ƈ所引添加文档。我们注意到该类的构造函数接受三个参敎ͼW一个参数指定了存储索引文g的\径。第二个参数指定了在索引q程中用什么样的分词器。最后一个参数是个布变量,如果gؓ真,那么pC创徏一个新的烦引,如果gؓ假,pC打开一个已l存在的索引?/p>
接下来的代码演示了如何添加一个文到索引文g中?/p>
Document document = new Document(); document.add(Field.Text("content",textReader)); document.add(Field.Text("path",textFiles[i].getPath())); indexWriter.addDocument(document); |
首先W一行创Zc?Document 的一个实例,它由一个或者多个的?Field)l成。你可以把这个类惌成代表了一个实际的文Q比如一?HTML 面Q一?PDF 文Q或者一个文本文件。而类 Document 中的域一般就是实际文档的一些属性。比如对于一?HTML 面Q它的域可能包括标题Q内容,URL {。我们可以用不同cd?Field 来控制文档的哪些内容应该索引Q哪些内容应该存储。如果想获取更多的关?Lucene 的域的信息,可以参?Lucene 的帮助文档。代码的W二行和W三行ؓ文d了两个域Q每个域包含两个属性,分别是域的名字和域的内容。在我们的例子中两个域的名字分别?content"?path"。分别存储了我们需要烦引的文本文g的内容和路径。最后一行把准备好的文档dC索引当中?/p>
当我们把文档d到烦引中后,不要忘记关闭索引Q这h保证 Lucene 把添加的文写回到硬盘上。下面的一句代码演CZ如何关闭索引?/p>
indexWriter.close(); |
利用清单1中的代码Q你可以成功的文本文添加到索引中去。接下来我们看看对烦引进行的另外一U重要的操作Q从索引中删除文档?/p>
![]() ![]() |
cIndexReader负责从一个已l存在的索引中删除文档,如清?所C?/p>
File indexDir = new File("C:\\luceneIndex"); IndexReader ir = IndexReader.open(indexDir); ir.delete(1); ir.delete(new Term("path","C:\\file_to_index\lucene.txt")); ir.close(); |
在清?中,W二行用静态方?IndexReader.open(indexDir) 初始化了c?IndexReader 的一个实例,q个Ҏ的参数指定了索引的存储\径。类 IndexReader 提供了两U方法去删除一个文档,如程序中的第三行和第四行所C。第三行利用文的编h删除文。每个文都有一个系l自动生成的~号。第四行删除了\径ؓ"C:\\file_to_index\lucene.txt"的文档。你可以通过指定文g路径来方便的删除一个文档。值得注意的是虽然利用上述代码删除文档使得该文不能被索到Q但是ƈ没有物理上删除该文。Lucene 只是通过一个后~名ؓ .delete 的文件来标记哪些文档已经被删除。既然没有物理上删除Q我们可以方便的把这些标Cؓ删除的文恢复过来,如清?3 所C,首先打开一个烦引,然后调用Ҏ ir.undeleteAll() 来完成恢复工作?/p>
File indexDir = new File("C:\\luceneIndex"); IndexReader ir = IndexReader.open(indexDir); ir.undeleteAll(); ir.close(); |
你现在也许想知道如何物理上删除烦引中的文,Ҏ也非常简单。清?4 演示了这个过E?/p>
File indexDir = new File("C:\\luceneIndex"); Analyzer luceneAnalyzer = new StandardAnalyzer(); IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,false); indexWriter.optimize(); indexWriter.close(); |
在清?4 中,W三行创Zc?IndexWriter 的一个实例,q且打开了一个已l存在的索引。第 4 行对索引q行清理Q清理过E中把所有标Cؓ删除的文物理删除?/p>
Lucene 没有直接提供ҎҎ进行更斎ͼ如果你需要更C个文档,那么你首先需要把q个文从烦引中删除Q然后把新版本的文档加入到烦引中厅R?/p>
![]() ![]() |
利用 LuceneQ在创徏索引的工E中你可以充分利用机器的g资源来提高烦引的效率。当你需要烦引大量的文gӞ你会注意到烦引过E的瓉是在往盘上写索引文g的过E中。ؓ了解册个问? Lucene 在内存中持有一块缓冲区。但我们如何控制 Lucene 的缓冲区呢?q运的是QLucene 的类 IndexWriter 提供了三个参数用来调整缓冲区的大以及往盘上写索引文g的频率?/p>
1Q合q因子(mergeFactorQ?/p>
q个参数军_了在 Lucene 的一个烦引块中可以存攑֤文以及把盘上的索引块合q成一个大的烦引块的频率。比如,如果合ƈ因子的值是 10Q那么当内存中的文数达?10 的时候所有的文都必d到磁盘上的一个新的烦引块中。ƈ且,如果盘上的索引块的隔数辑ֈ 10 的话Q这 10 个烦引块会被合ƈ成一个新的烦引块。这个参数的默认值是 10Q如果需要烦引的文数非常多的话q个值将是非怸合适的。对批处理的索引来讲Qؓq个参数赋一个比较大的g得到比较好的索引效果?/p>
2Q最合q文数
q个参数也会影响索引的性能。它军_了内存中的文档数臛_辑ֈ多少才能它们写回磁盘。这个参数的默认值是10Q如果你有够的内存Q那么将q个值尽量设的比较大一些将会显著的提高索引性能?/p>
3Q最大合q文档数
q个参数军_了一个烦引块中的最大的文数。它的默认值是 Integer.MAX_VALUEQ将q个参数讄为比较大的值可以提高烦引效率和索速度Q由于该参数的默认值是整型的最大|所以我们一般不需要改动这个参数?/p>
清单 5 列出了这个三个参数用法,清单 5 和清?1 非常怼Q除了清?5 中会讄刚才提到的三个参数?/p>
/** * This class demonstrates how to improve the indexing performance * by adjusting the parameters provided by IndexWriter. */ public class AdvancedTextFileIndexer { public static void main(String[] args) throws Exception{ //fileDir is the directory that contains the text files to be indexed File fileDir = new File("C:\\files_to_index"); //indexDir is the directory that hosts Lucene's index files File indexDir = new File("C:\\luceneIndex"); Analyzer luceneAnalyzer = new StandardAnalyzer(); File[] textFiles = fileDir.listFiles(); long startTime = new Date().getTime(); int mergeFactor = 10; int minMergeDocs = 10; int maxMergeDocs = Integer.MAX_VALUE; IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true); indexWriter.mergeFactor = mergeFactor; indexWriter.minMergeDocs = minMergeDocs; indexWriter.maxMergeDocs = maxMergeDocs; //Add documents to the index for(int i = 0; i < textFiles.length; i++){ if(textFiles[i].isFile() >> textFiles[i].getName().endsWith(".txt")){ Reader textReader = new FileReader(textFiles[i]); Document document = new Document(); document.add(Field.Text("content",textReader)); document.add(Field.Keyword("path",textFiles[i].getPath())); indexWriter.addDocument(document); } } indexWriter.optimize(); indexWriter.close(); long endTime = new Date().getTime(); System.out.println("MergeFactor: " + indexWriter.mergeFactor); System.out.println("MinMergeDocs: " + indexWriter.minMergeDocs); System.out.println("MaxMergeDocs: " + indexWriter.maxMergeDocs); System.out.println("Document number: " + textFiles.length); System.out.println("Time consumed: " + (endTime - startTime) + " milliseconds"); } } |
通过q个例子Q我们注意到在调整缓冲区的大以及写盘的频率上?Lucene l我们提供了非常大的灉|性。现在我们来看一下代码中的关键语句。如下的代码首先创徏了类 IndexWriter 的一个实例,然后对它的三个参数进行赋倹{?/p>
int mergeFactor = 10; int minMergeDocs = 10; int maxMergeDocs = Integer.MAX_VALUE; IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true); indexWriter.mergeFactor = mergeFactor; indexWriter.minMergeDocs = minMergeDocs; indexWriter.maxMergeDocs = maxMergeDocs; |
下面我们来看一下这三个参数取不同的值对索引旉的媄响,注意参数值的不同和烦引之间的关系。我们ؓq个实验准备?10000 个测试文。表 1 昄了测试结果?/p>
通过?1Q你可以清楚地看C个参数对索引旉的媄响。在实践中,你会l常的改变合q因子和最合q文数的值来提高索引性能。只要你有够大的内存,你可以ؓ合ƈ因子和最合q文档数q两个参数赋量大的g提高索引效率Q另外我们一般无需更改最大合q文档数q个参数的|因ؓpȝ已经默认它讄成了最大?/p>
![]() ![]() |
在分?Lucene 的烦引文件结构之前,我们先要理解反向索引QInverted indexQ这个概念,反向索引是一U以索引ؓ中心来组l文档的方式Q每个烦引项指向一个文序列,q个序列中的文都包含该索引V相反,在正向烦引中Q文占据了中心的位|,每个文指向了一个它所包含的烦引项的序列。你可以利用反向索引L的找到那些文档包含了特定的烦引项。Lucene正是使用了反向烦引作为其基本的烦引结构?/p>
![]() ![]() |
在Lucene 中有索引块的概念Q每个烦引块包含了一定数目的文。我们能够对单独的烦引块q行索。图 2 昄?Lucene 索引l构的逻辑视图。烦引块的个数由索引的文的L以及每个索引块所能包含的最大文数来决定?/p>
![]() ![]() |
下面的部分将会分析Lucene中的主要的烦引文Ӟ可能分析有些索引文g的时候没有包含文件的所有的字段Q但不会影响到对索引文g的理解?/p>
1Q烦引块文g
q个文g包含了烦引中的烦引块信息Q这个文件包含了每个索引块的名字以及大小{信息。表 2 昄了这个文件的l构信息?/p>
2Q域信息文g
我们知道Q烦引中的文由一个或者多个域l成Q这个文件包含了每个索引块中的域的信息。表 3 昄了这个文件的l构?/p>
3Q烦引项信息文g
q是索引文g里面最核心的一个文Ӟ它存储了所有的索引的g及相关信息,q且以烦引项来排序。表 4 昄了这个文件的l构?/p>
4Q频率文?/p>
q个文g包含了包含烦引项的文档的列表Q以及烦引项在每个文中出现的频率信息。如果Lucene在烦引项信息文g中发现有索引和搜烦词相匚w。那?Lucene ׃在频率文件中找有哪些文g包含了该索引V表5昄了这个文件的一个大致的l构Qƈ没有包含q个文g的所有字Dc?/p>
5Q位|文?/p>
q个文g包含了烦引项在每个文中出现的位|信息,你可以利用这些信息来参与对烦引结果的排序。表 6 昄了这个文件的l构
到目前ؓ止我们介l了 Lucene 中的主要的烦引文件结构,希望能对你理?Lucene 的物理的存储l构有所帮助?/p>
![]() ![]() |
目前已经有非常多的知名的l织正在使用 LuceneQ比如,Lucene ?Eclipse 的帮助系l,ȝ理工学院?OpenCourseWare 提供了搜索功能。通过阅读q篇文章Q希望你能对 Lucene 的烦引机制有所了解Qƈ且你会发现利?Lucene 创徏索引是非常简单的事情?/p>
学习
获得产品和技?/strong>