1.建立索引
爲60篇記事本文檔的中文小說建立索引,分析器採用Lucene.Net.Analysis.Cn.ChineseAnalyzer()(這個索引器是從http://www.cnblogs.com/dudu/archive/2004/06/22/17783.aspx下載的,是dudu修正bug後的版本,感謝dudu.)統計索引的建立時間.同時,會更改IndexWriter的參數以感受相關參數對索引建立速度的影響.
2.關鍵字檢索
當索引建立完畢後,對索引進行簡單關鍵字的檢索,查看響應時間
3.多線程檢索
採用多線程對索引的檢索,以查看多線程環境下lucene的工作效率
1.構建Document
在建立索引之前,首先要構建Document類型,它把文本文檔轉變成lucene可以識別的Document格式.
{
public static Document getDocument(FileInfo file)
{
Document doc = new Document();
//爲文件路徑構建一個字段
doc.Add(new Field("path", file.FullName, Field.Store.YES, Field.Index.UN_TOKENIZED));
//爲文件名構建一個字段
doc.Add(Field.Keyword("title",file.Name));
//爲文件內容建一個字段
doc.Add(new Field("content",new StreamReader(file.FullName,Encoding.Default)));
//爲文本的最後修改時間構建一個字段
doc.Add(new Field("modified", DateTools.TimeToString(file.LastWriteTime.Ticks, DateTools.Resolution.MINUTE), Field.Store.YES, Field.Index.UN_TOKENIZED));
return doc;
}
}
在上述代碼中,一個共有的靜態方法返回一個Document類型的對象,它的參數是FileInfo類型,在建立索引的時候,將獲得的文件對象傳入就可以得到與lucene相對應的Document類型.上面的代碼一添加了四個不同的字段.
2.建立索引的代碼
using System.Collections.Generic;
using System.Text;
using Lucene.Net.Analysis.Cn;
using Lucene.Net.Index;
using Lucene.Net.Store;
using Lucene.Net.Analysis;
using System.IO;
namespace IndexDemo
{
class IndexTest
{
static readonly System.IO.FileInfo INDEX_DIR = new System.IO.FileInfo("index2");
//索引存放位置
public static String INDEX_STORE_PATH = "c://index";
//合併索引前,內存中最大的文件數量
public static int DEFAULT_MAX_DOCS_IN_RAM = 40;
//最大的字段長度
public static readonly int DEFAULT_MAX_FIELD_LENGTH = int.MaxValue;
//單例模式
private static IndexTest indextest = null;
//兩個索引器
private IndexWriter ramWriter = null;
private IndexWriter fsWriter = null;
//內存中已經有的文檔數量
private int docs_in_ram;
//內存中最大的文檔數量
private int ramMaxFiles = DEFAULT_MAX_DOCS_IN_RAM;
//內存是否被刷新過
private Boolean freshed = true;
//索引存放的文件系統目錄
FSDirectory fsDir = null;
//索引存放的內存目錄
RAMDirectory ramDir = null;
//私有構造函數
private IndexTest() { }
// 靜態方法構造一個單例
public static IndexTest getInstance()
{
if (indextest == null)
{
indextest = new IndexTest();
}
return indextest;
}
//構造索引器
public void newWriter()
{
if (fsWriter != null || ramWriter != null)
{
Console.WriteLine("some indexer has builded");
return;
}
try
{
Boolean rebuild = true;
ramDir = new RAMDirectory();
Analyzer analyser = new ChineseAnalyzer();
ramWriter = new IndexWriter(ramDir,analyser,true);
fsDir = FSDirectory.GetDirectory("C://index", rebuild);
fsWriter = new IndexWriter(fsDir,analyser,rebuild);
initWriter();
}
catch { }
}
//初始化索引器
private void initWriter()
{
fsWriter.maxFieldLength = DEFAULT_MAX_FIELD_LENGTH;
}
//優化索引
public void optimizeIndex()
{
if(fsWriter== null||ramWriter== null)
{
Console.WriteLine("initialize a new indexer fist");
return;
}
refreshRam();
fsWriter.Optimize();
}
//索引某個目錄下的文件
public void toIndex(String path)
{
toIndex(new FileInfo(path));
}
//索引某個File對象
public void toIndex(FileInfo file)
{
if (fsWriter== null || ramWriter == null)
{
Console.WriteLine("some indexer has builded");
return;
}
freshed = false;
DateTime start = DateTime.Now;
int number = indexFiles(file);
DateTime end = DateTime.Now;
long time=end.Ticks-start.Ticks;
Console.WriteLine("總共耗時{0}毫秒",Convert.ToString(time));
Console.WriteLine("一共爲{0}個文件建立索引", number);
}
//關閉索引
public void close()
{
if (fsWriter == null || ramWriter == null)
{
Console.WriteLine("use newwriter() method to initialize a new indexerfirsrt");
return;
}
refreshRam();
ramWriter.Close();
fsWriter.Close();
}
//刷新內存
private void refreshRam()
{
if (!freshed)
{
Console.WriteLine("Refreshing");
fsWriter.AddIndexes(new Lucene.Net.Store.Directory[] { ramDir});
}
ramDir.Close();
ramDir = new RAMDirectory();
ramWriter = new IndexWriter(ramDir,new ChineseAnalyzer(),true);
docs_in_ram = 0;
freshed = true;
}
//向索引中加入文檔
private void addDocument(FileInfo file)
{
if (docs_in_ram >= ramMaxFiles)
{
refreshRam();
}
ramWriter.AddDocument(FileDocument.getDocument(file));
docs_in_ram++;
freshed = false;
}
//遞歸的遍歷文件目錄來建立索引
private int indexFiles(FileInfo file)
{
if (System.IO.Directory.Exists(file.FullName))
{
string[] files = System.IO.Directory.GetFiles(file.FullName);
int num = 0;
if (files != null)
{
for (int i = 0; i < files.Length; i++)
{
num+=indexFiles(new FileInfo(files[i]));
}
}
return num;
}
else
{
if (file.FullName.EndsWith(".txt"))
{
Console.WriteLine("正在搜索:"+file.Name);
addDocument(file);
return 1;
}
else
{
Console.WriteLine("文件類型不支持");
return 0;
}
}
}
static void Main(string[] args)
{
IndexTest test = IndexTest.getInstance();
test.newWriter();
test.toIndex("e://source");
test.close();
}
}
}
在上面的代碼中,當通過getInstance()方法得到一個該類的實例後,則可以調用newWriter()方法來獲得索引器的實例.在newWriter()方法中獲取了兩個IndexWriter的實例.一個是向文件系統創建的索引器,另一個則向內存中創建索引的索引器,因此對對應的創建了一個RAMDirectory和一貫FSDirectory的對象.這麼做的目的是希望減少磁盤的I/O次數,當內存中累積的文檔到達一定數量時候,就自動刷新內存,將其寫入文件系統中,因此,需要一個內存中最大文檔數量的限制,該值就是由私有類變量ramMaxFiles控制,它的默認爲64.
addDocument(File file)是真正將文檔加入索引的的代碼,在它之中首先要判斷當前內存中的文檔數量是否已經大雨最大的文檔數量.如果已經達到,則調用refreshRam方法刷新內存中的文檔到磁盤上.如果未達到,則繼續將文檔假如內存中.
3:開始建立索引
在代碼最後,有一個Main方法,他指定在e://source目錄上建立索引.當運行它時,就可以執行索引建立的過程
上面測試中initWriter中僅僅調置了一個fsWriter的最大字段長度.如果用戶有興趣,可以調整mergeFactor和maxMergeDocs等參數來查看索引的建立速度