目前在做一个winform小软件,其中有一个功能是能根据关键字检索本地保存的word文档。第一次是用com读取word方式(见上一篇文章),先遍历文件夹下的word文档,读取每个文档时循环关键字查找,结果可想而知效率很慢。检索结果是一条接一条显示出来的o(>_<)o ~~。连菜鸟级别的自己看到这效率都觉得很无语。然后想到计算机的本地搜索及google,百度搜索引擎,它们能做到在海量文件中快速搜到匹配某些关键字的文件,应该是运用其它比较先进成熟的技术来实现。于是上网搜了好多资料,发现有一种叫lucene的全文搜索引擎架构。连忙下了一些demo及源码来学,但对于在编程方面还是菜鸟级别的人来说,这些很高深!呼(~ o ~)~zZ……赶鸭子上架,还是硬着头皮慢慢弄了。。。

大致了解了下,我是用C#的,所以要用lucene.net框架,还需要有分词器,lucene.net可以在nuget组件管理中搜到,直接下载到项目中,分词器nuget上也可以搜到。。大概的思路是:遍历文件夹,读取文档内容,进行分词、建索引……

代码:

一、声明索引文件位置,名称,分词器

 string filesDirectory = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Files");
static string indexDirectory = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Index");
// Analyzer analyzer = new Lucene.Net.Analysis.Cn.ChineseAnalyzer();
static Analyzer analyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);//用standardAnalyzer分词器

StandardAnalyzer分词器与ChineseAnalyzer分词器的区别:

对“123木头人”这句话进行分词,StandardAnalyzer的分词结果:1 2 3 木 头 人;ChineseAnalyzer的分词结果:木 头 人,把数字过滤了。

二、遍历文件夹及文件,创建索引

         /// <summary>
/// 创建索引按钮事件
/// </summary>
private void btnSetIndex_Click(object sender, EventArgs e)
{
this.folderBrowserDialog1.ShowDialog();
string rootPath = this.folderBrowserDialog1.SelectedPath;
if(rootPath!="")
{
GetAllFiles(rootPath);
MessageBox.Show("创建索引完成!");
}
} /// <summary>
/// 获取指定根目录下的子目录及其文档
/// </summary>
/// <param name="rootPath">检索的文档根目录</param>
private void GetAllFiles(string rootPath)
{
List<FileInfo> files = new List<FileInfo>(); //声明一个files包,用来存储遍历出的word文档
if (!System.IO.Directory.Exists(rootPath))
{
MessageBox.Show("指定的目录不存在");
return;
}
GetAllFiles(rootPath, files);
CreateIndex(files); //创建索引方法
} /// <summary>
/// 获取指定根目录下的子目录及其文档
/// </summary>
/// <param name="rootPath">根目录路径</param>
/// <param name="files">word文档存储包</param>
private void GetAllFiles(string rootPath,List<FileInfo>files)
{
DirectoryInfo dir = new DirectoryInfo(rootPath);
string[] dirs = System.IO.Directory.GetDirectories(rootPath);//得到所有子目录
foreach (string di in dirs)
{
GetAllFiles(di,files); //递归调用
}
FileInfo[] file = dir.GetFiles("*.doc"); //查找word文件
//遍历每个word文档
foreach (FileInfo fi in file)
{
string filename = fi.Name;
string filePath = fi.FullName;
object filepath = filePath;
files.Add(fi);
}
} /// <summary>
/// 创建索引
/// </summary>
/// <param name="files">获得的文档包</param>
private void CreateIndex(List<FileInfo> files)
{
bool isCreate = false;
//判断是创建索引还是增量索引
if (!System.IO.Directory.Exists(indexDirectory))
{
isCreate = true;
}
IndexWriter writer = new IndexWriter(FSDirectory.Open(indexDirectory),analyzer,isCreate,IndexWriter.MaxFieldLength.UNLIMITED); //FSDirectory表示索引存放在硬盘上,RAMDirectory表示放在内存上
for (int i = ; i < files.Count(); i++)
{
//读取word文档内容
Microsoft.Office.Interop.Word.ApplicationClass wordapp = new Microsoft.Office.Interop.Word.ApplicationClass();
string filename = files[i].Name;
object file = files[i].DirectoryName + "\\" + filename;
object isreadonly = true;
object nullobj = System.Reflection.Missing.Value;
Microsoft.Office.Interop.Word._Document doct = wordapp.Documents.Open(ref file, ref nullobj, ref isreadonly, ref nullobj, ref nullobj, ref nullobj,
ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj);
//doct.ActiveWindow.Selection.WholeStory();
//doct.ActiveWindow.Selection.Copy();
//IDataObject data = Clipboard.GetDataObject();
////读出的内容赋给content变量
//string content = data.GetData(DataFormats.Text).ToString();
string content = doct.Content.Text;
FileInfo fi = new FileInfo(file.ToString());
string createTime = fi.CreationTime.ToString();
string filemark = files[i].DirectoryName + createTime;
//关闭word
object missingValue = Type.Missing;
object miss = System.Reflection.Missing.Value;
object saveChanges = WdSaveOptions.wdDoNotSaveChanges;
doct.Close(ref saveChanges, ref missingValue, ref missingValue);
wordapp.Quit(ref saveChanges, ref miss, ref miss);
// StreamReader reader = new StreamReader(fileInfo.FullName);读取txt文件的方法,如读word会出现乱码,不适用于word的读取
Lucene.Net.Documents.Document doc = new Lucene.Net.Documents.Document(); writer.DeleteDocuments(new Term("filemark", filemark)); //当索引文件中含有与filemark相等的field值时,会先删除再添加,以防出现重复
doc.Add(new Lucene.Net.Documents.Field("filemark", filemark, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED)); //不分词建索引
doc.Add(new Lucene.Net.Documents.Field("FileName", filename, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.ANALYZED)); //ANALYZED分词建索引
doc.Add(new Lucene.Net.Documents.Field("Content", content, Lucene.Net.Documents.Field.Store.NO, Lucene.Net.Documents.Field.Index.ANALYZED));
doc.Add(new Lucene.Net.Documents.Field("Path", file.ToString(), Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.ANALYZED));
writer.AddDocument(doc);
writer.Optimize();//优化索引
}
writer.Dispose();
}

三、根据关键字检索

         /// <summary>
/// 检索关键字
/// </summary>
/// <param name="strKey">关键字包</param>
private void SearchKey(List<string> strKey)
{
int num = ;
if (strKey.Count != )
{
IndexReader reader = null;
IndexSearcher searcher = null;
try
{
if (!System.IO.Directory.Exists(indexDirectory))
{
MessageBox.Show("首次使用该软件检索 必须先创建索引!"+ "\r\n"+"请点击右边【创建索引】按钮,选择要检索的文件夹进行创建索引。");
return;
}
reader = IndexReader.Open(FSDirectory.Open(new DirectoryInfo(indexDirectory)), false);
searcher = new IndexSearcher(reader); //创建查询
PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper(analyzer);
wrapper.AddAnalyzer("FileName", analyzer);
wrapper.AddAnalyzer("Content", analyzer);
wrapper.AddAnalyzer("Path", analyzer);
string[] fields = { "FileName", "Content", "Path" };
QueryParser parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30, fields, wrapper);
BooleanQuery Bquery = new BooleanQuery();
for (int i = ; i < strKey.Count; i++)
{
Query query = parser.Parse(strKey[i]);
Bquery.Add(query, Occur.MUST);
} TopScoreDocCollector collector = TopScoreDocCollector.Create(num, true);
searcher.Search(Bquery, collector);
var hits = collector.TopDocs().ScoreDocs;
//以后就可以对获取到的collector数据进行操作
int resultNum = ; //计算检索结果数量
for (int i = ; i < hits.Count(); i++)
{
var hit = hits[i];
Lucene.Net.Documents.Document doc = searcher.Doc(hit.Doc);
Lucene.Net.Documents.Field fileNameField = doc.GetField("FileName");
Lucene.Net.Documents.Field contentField = doc.GetField("Content");
Lucene.Net.Documents.Field pathField = doc.GetField("Path");
if (!System.IO.File.Exists(pathField.StringValue)) //判断本地是否存在该文件,存在则在检索结果栏里显示出来
{
int docId = hit.Doc; //该文件的在索引里的文档号,Doc是该文档进入索引时Lucene的编号,默认按照顺序编的
reader.DeleteDocument(docId);//删除该索引
reader.Commit();
continue;
}
dtBGMC.Rows.Add(fileNameField.StringValue, pathField.StringValue);
resultNum++;
}
MessageBox.Show("检索完成!共检索到" +resultNum+ "个符合条件的结果!", "success!");
}
finally
{
if (searcher != null)
searcher.Dispose(); if (reader != null)
reader.Dispose();
}
}
else
{
MessageBox.Show("请输入要查询的关键字!");
return;
}
}

作者:goodgirlmia
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

用lucene.net根据关键字检索本地word文档的更多相关文章

  1. Android开发——使用Jword生成本地word文档

    本文主要介绍如何使用Jword生成本地word文档,这里涉及到Jword的使用技巧,本文给出相应的代码,需要的朋友可以参考下. 为什么使用Jword呢?因为IText .Freemark在安卓平台上压 ...

  2. C#使用COM搜索本地word文档关键字

    /// <summary> /// 检索根目录下的子目录及其所有文件,并在datagridview中显示文档名称及路径--递归调用 /// </summary> /// < ...

  3. C# 利用Aspose.Words .dll将本地word文档转化成pdf(完美破解版 无水印 无中文乱码)

    下载Aspose.Words .dll  http://pan.baidu.com/s/1c8659k 在vs2010中新建窗体应用程序,命名为 wordtopdf 添加Aspose.Words .d ...

  4. java利用Aspose.words.jar将本地word文档转化成pdf(完美破解版 无水印 无中文乱码)

    package doc; import java.io.*; import junit.framework.Test; import com.aspose.words.*; public class ...

  5. 在项目中利用TX Text Control进行WORD文档的编辑显示处理

    在很多文档管理的功能模块里面,我们往往需要对WORD稳定进行展示.编辑等处理,而如果使用微软word控件进行处理,需要安装WORD组件,而且接口使用也不见得简单易用,因此如果有第三方且不用安装Offi ...

  6. asp.net 将word文档进行编辑并导出一个新的word

    最近做项目,需要多word文档进行编辑并导出一个新的word,在最初的word编辑中留下特定的字符串用来替换,然后在本地生成一个新的word文档,并且不修改服务器中的word文档,这样才能保证服务器中 ...

  7. JSP实现word文档的上传,在线预览,下载

    前两天帮同学实现在线预览word文档中的内容,而且需要提供可以下载的链接!在网上找了好久,都没有什么可行的方法,只得用最笨的方法来实现了.希望得到各位大神的指教.下面我就具体谈谈自己的实现过程,总结一 ...

  8. ASP.NET生成WORD文档,服务器部署注意事项

    网上转的,留查备用,我服务器装的office2007所以修改的是Microsoft Office word97 - 2003 文档这一个. ASP.NET生成WORD文档服务器部署注意事项 1.Asp ...

  9. Android中使用POI加载与显示word文档

    最近打算实现一个功能:在Android中加载显示Word文档,当然这里不是使用外部程序打开.查看一些资料后,打算采用poi实现,确定了以下实现思路: 将ftp中的word文档下载到本地. 调用poi将 ...

随机推荐

  1. ecshop广告调用方法

    在简单地概括ecshop广告调用该方法,已发表在博客上,在这里,我们总结了以下 :就是官方默认的方法.先加入广告位,然后加入模板的广告位区域,再在将两者相应上. 1.后台 > 广告管理 > ...

  2. 使用log4j日志-配置载入问题

    1.在eclipse中,把log4j.properties放在类路径下,在项目启动时就会自己主动载入. 2.在idea中.把log4j.properties放在类路径下,可是项目启动时不能直接载入(原 ...

  3. CodeForces 398B 概率DP 记忆化搜索

    题目:http://codeforces.com/contest/398/problem/B 有点似曾相识的感觉,记忆中上次那个跟这个相似的 我是用了 暴力搜索过掉的,今天这个肯定不行了,dp方程想了 ...

  4. Visual FoxPro 6.0~9.0解决方案和实例文档和CD写入原件下载

    自从微软宣布开发冻结Visual FoxPro之后,这样的图书出版已经成为一个问题,但仍有不少VFP小贴士.处处留心此8历史书.在此提供写作的原稿.它看起来非常舒服比扫描版淘宝.下载链接:http:/ ...

  5. 跨境移动互联网的魅力演绎,hao123无论成就下一个条目?

        使用"热"为了描述的情况在目前的移动互联网不夸张,背景下,越来越多的企业试图染指这一新兴领域.只是,巴菲特有句名言------"仅仅有退潮了,才知道谁在裸泳&qu ...

  6. EMVTag系列5《8E 持卡人验证方法(CVM)名单》

    L: var. up to 252 -R(需求):数据必须存在,在读应用数据过程中,终端不检查 依照优先顺序列出卡片应用支持的全部持卡人验证方法 注:一个应用中能够有多个CVM列表,比如一个用于国内交 ...

  7. 《CS:APP》 chapter 8 Exceptional Control Flow 注意事项

    Exceptional Control Flow The program counter assumes a sequence of values                            ...

  8. 基于注释配置bean和装饰bean

    1.组件扫描 Spring容器能够从classpath(类路径)下自动扫描.侦测和实例化具有特定注释的组件. 2.特定注释组件 –@Component: 基本注解, 标识了一个受 Spring 管理的 ...

  9. DevExpress XtraReports 入门五 创建交叉表报表

    原文:DevExpress XtraReports 入门五 创建交叉表报表 本文只是为了帮助初次接触或是需要DevExpress XtraReports报表的人群使用的,为了帮助更多的人不会像我这样浪 ...

  10. 【足迹C++primer】47、Moving Objects(1)

    Moving Objects(1) * 功能:Moving Objects * 时间:2014年7月17日08:46:45 * 作者:cutter_point */ #include<iostr ...