基于Java的全文索引/检索引擎——Lucene
Lucene不是一个完整的全文索引应用,而是是一个用Java写的全文索引引擎工具包,它可以方便的嵌入到各种应用中实现针对应用的全文索引/检索功能。
Lucene的作者:Lucene的贡献者Doug Cutting是一位资深全文索引/检索专家,曾经是V-Twin搜索引擎(Apple的Copland操作系统的成就之一)的主要开发者,后在Excite担任高级系统架构设计师,目前从事于一些INTERNET底层架构的研究。他贡献出的Lucene的目标是为各种中小型应用程序加入全文检索功能。
Lucene的发展历程:早先发布在作者自己的www.lucene.com,后来发布在SourceForge,2001年年底成为APACHE基金会jakarta的一个子项目:http://jakarta.apache.org/lucene/ 已经有很多Java项目都使用了Lucene作为其后台的全文索引引擎。
现在也有很多用.NET做的Lucene,其索引/检索的效果还是不错的。
近期由于做项目的需要,也对Lucene进行了研究,小有一些心得。
其关键步骤为:
一、建立索引
从源数据文件夹中取出所有要进行索引的文件,循环为每个文件建立索引: 注意DLL的引用(using StandardAnalyzer = Lucene.Net.Analysis.Standard.StandardAnalyzer;using IndexWriter = Lucene.Net.Index.IndexWriter;using Lucene.Net.Demo;) IndexWriter writer = new IndexWriter(indexPath, new StandardAnalyzer(), true);//index indexPath 为存放索引文件的路径 IndexDocs(writer, new System.IO.FileInfo(sourcePath)); //索引方法 sourcePath 为存放源数据文件的路径
下面是实现索引的方法: #region Index Documets public void IndexDocs(IndexWriter writer, System.IO.FileInfo file) { if (System.IO.Directory.Exists(file.FullName)) { System.String[] files = System.IO.Directory.GetFileSystemEntries(file.FullName); // an IO error could occur if (files != null) { for (int i = 0; i < files.Length; i++) { IndexDocs(writer, new System.IO.FileInfo(files[i])); } } } else { try { writer.AddDocument(FileDocument.Document(file)); index++; this.listBoxControl.Items.Add(file.Name+" "+DateTime.Now.ToString());//recorder successful file } // at least on windows, some temporary files raise this exception with an "access denied" message // checking if the file can be read doesn't help catch (System.IO.FileNotFoundException fnfe) { MessageBox.Show((fnfe.GetType()+fnfe.Message),"错误",MessageBoxButtons.OK,MessageBoxIcon.Error); return; } } } #endregion
在这里要注意的是,由于需求的原因我对源数据文件加过密,所以我把索引的具休法中添加了解密方法。也就是说,在索引文件的时候首先要把源加密文件解密后再进行索引,这样就要以把真正没加密前的信息加到索引里面了。(当然在查到相应文件查看时,还要对文件进行解密的)
修改类FileDocument中的函数: public static Document Document(System.IO.FileInfo f) { // make a new, empty document Document doc = new Document(); // Add the path of the file as a Field named "path". Use a Text Field, so // that the index stores the path, and so that the path is searchable doc.Add(Field.Text("path", f.FullName)); // Add the last modified date of the file a Field named "modified". Use a // Keyword Field, so that it's searchable, but so that no attempt is made // to tokenize the Field into words. doc.Add(Field.Keyword("modified", DateField.TimeToString(((f.LastWriteTime.Ticks - 621355968000000000) / 10000)))); // Add the contents of the file a Field named "contents". Use a Text // Field, specifying a Reader, so that the text of the file is tokenized. // ?? why doesn't FileReader work here ??
//read file from source FileStream fs = new FileStream(f.FullName,FileMode.Open); StreamReader sr = new StreamReader(fs,Encoding.Default); string filetemp = sr.ReadToEnd(); sr.Close(); fs.Close();
//open pass //此处为自己写的加密/解密方法 Cryptography op = new Cryptography(); filetemp = op.DesDecrypt(filetemp,"xxxxxxxxx"); // Save a copy string tempFile = @"c:/temp.htm"; if (File.Exists(tempFile)) { File.Delete(tempFile); } try { using (StreamWriter sw = new StreamWriter(tempFile,false,Encoding.UTF8)) { sw.Write(filetemp); } } catch { throw new IOException(); }
System.IO.FileStream is_Renamed = new System.IO.FileStream(tempFile, System.IO.FileMode.Open, System.IO.FileAccess.Read); System.IO.StreamReader reader = new System.IO.StreamReader(new System.IO.StreamReader(is_Renamed, System.Text.Encoding.Default).BaseStream, new System.IO.StreamReader(is_Renamed, System.Text.Encoding.Default).CurrentEncoding); doc.Add(Field.Text("contents", reader)); // return the document return doc; } 此处是建了临时文件,因为法在执行时一直在使用reader,所以不能在当前这个方法为执行删除临时文件,我把它加到了调用索引方法的主函数中。(也就是说要在所有索引建完之后去删除昨临时文件)到此索引就告一段落。
二、文件检索
在这里文件检索就相对比较简单一些,直接利用建好的索引文件进行检索就可以了。同时也要注意命名空间的引用:using Analyzer = Lucene.Net.Analysis.Analyzer;using StandardAnalyzer = Lucene.Net.Analysis.Standard.StandardAnalyzer;using Document = Lucene.Net.Documents.Document;using QueryParser = Lucene.Net.QueryParsers.QueryParser;using Hits = Lucene.Net.Search.Hits;using IndexSearcher = Lucene.Net.Search.IndexSearcher;using Query = Lucene.Net.Search.Query;using Searcher = Lucene.Net.Search.Searcher;
下面为具体的检索方法:
private void Search() { try { DateTime starttime = DateTime.Now; //begin analyse file string analysepath = Application.StartupPath+"//"+analyseConfigPath; //index file config xml path string analysefolder = xo.ReadFileConfig(analysepath); //index file folder path string indexPath = Application.StartupPath+"//"+analysefolder; //index folder path
Searcher searcher = new IndexSearcher(indexPath); Analyzer analyzer = new StandardAnalyzer(); System.String line = this.txtWord.Text.Trim(); if(listSearchResult.Items.Count > 0) listSearchResult.Items.Clear();
if (line.Length == 0) return;; Query query = QueryParser.Parse(line, "contents", analyzer);
this.listSearchResult.Items.Add("查找关键词: " + query.ToString("contents")); Hits hits = searcher.Search(query); this.listSearchResult.Items.Add("找到相关文件约 "+hits.Length()+" 篇"); int HITS_PER_PAGE = 10; for (int start = 0; start < hits.Length(); start += HITS_PER_PAGE) { int end = System.Math.Min(hits.Length(), start + HITS_PER_PAGE); for (int i = start; i < end; i++) { Document doc = hits.Doc(i); System.String path = doc.Get("path"); if (path != null) { this.listSearchResult.Items.Add(i + ". " + path); } else { System.String url = doc.Get("url"); if (url != null) { this.listSearchResult.Items.Add(i + ". " + url); this.listSearchResult.Items.Add(" - " + doc.Get("title")); } else { this.listSearchResult.Items.Add(i + ". " + "No path nor URL for this document"); } } } } searcher.Close(); DateTime endtime = System.DateTime.Now; TimeSpan time = endtime - starttime; double timestr = time.TotalSeconds; this.laFileNum.Text = "找到相关文件约"+hits.Length().ToString()+"篇,用时"+timestr.ToString()+"秒 "; } catch //(System.Exception ecp) { // MessageBox.Show((ecp.GetType()+ecp.Message),"错误",MessageBoxButtons.OK,MessageBoxIcon.Error);// return; } }
可以把检索到的文件以列表的形式显示出来,选择自己需要的文件进行查看。下面的处理可以根据自己的具休情况来处理。
通过以上的应用,可以看到,其实使用lucene很简单。因其代码是开源的可以下载下来对其进一步扩展加工。
相关链接:
1、 http://www.dotlucene.net/
2、http://sourceforge.net
作者:jinru2560@gmail.com QQ: 55854548