基于Lucene的文件检索

     基于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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
浅谈网络搜索引擎的实现 知识管理系统网络搜索模块开发实践交流 功能需求 可自定义要搜索的网站列表(以下简称目标列表) 可对目标列表网站的网页内容进行检索 可对目标列表网站的网页内容进行自动分类处理 可自定义更新周期及一些相关性能参数 系统主要功能模块 网络蜘蛛 采集、解析并保存目标列表网站的内容(网页) 全文索引/检索 为目标列表网站内容建立索引 提供内容的全文检索 自动分类 对目标列表网站内容进行分类 基本流程 网络蜘蛛 功能概要 目标文档地址队列 w/r 目标文档(网页)获取 目标文档保存 文档解析并得到新的目标文档地址队列和文档正文内容 网络蜘蛛 当前版本的实现 多线程 Apache HttpClient Hsql HTML Parser 全文索引/搜索 什么是全文索引? 为了快速搜索大量的文本文件 为一本书建立关键词的索引“书签” 什么是全文搜索? 在索引查找关键字的过程,找到关键字在哪些地方出现 全文索引/搜索 Lucene简介 高性能、可扩展的信息检索工具库 为应用程序添加索引/搜索功能 一个典型的应用: 全文索引/搜索 全文索引/搜索 Lucene索引过程的核心类 IndexWriter :提供对索引的写入操作 Directory:描述了索引存放的位置 Analyzer:对文本进行分析,提取词汇(token),剔除无用的信息 Document:虚拟的文档 Field:每个Document包含一个或多个不同命名的Field,每个Field对应一段数据,这些数据在搜索过程可能会被查询或在索引检索 全文索引/搜索 Lucene索引代码示例: Directory dir = FSDirectory.getDirectory(indexDir); Analyzer anlyzer = new SimpleAnalyzer(); IndexWriter writer = new IndexWriter(dir, analyzer, true); Document doc = new Document(); doc.add(Field.Keyword(“id”, “1000”); doc.add(Field.UnIndexed(“name”, “Yao Ming”); doc.add(Field.UnStored(“intro”, “Yao Ming is a player of Houseton Rockets.”); writer.addDocument(doc); writer.close(); 全文索引/搜索 Lucene搜索过程的核心类 IndexSearcher:用于搜索IndexWriter创建的索引 Term:用于搜索的一个基本单元包括了一对字符串元素,与Field相对应 Query :抽象的查询类 TermQuery:最基本的查询类型,用来匹配特定Field包含特定值的文档 Hits:存放有序搜索结果指针的简单容器 全文索引/搜索 Lucene搜索代码示例: IndexSearcher searcher = new IndexSearcher(directory); Term t = new Term(“intro”, “Yao”); Query query = new TermQuery(t); Hits hits = searcher.search(query); assertEquals(“JUnit test”, 1, hits.length()); Lucene的线程安全性 不允许使用多个IndexWriter或IndexReader实例同时对一个索引进行修改 IndexWriter和IndexReader是线程安全的,可以被多线程共享 全文索引/搜索 文分词器 最大匹配法(机械分词):按照一定的策略将待分析的汉字串与一个“充分大的”机器词典的词条进行配,若在词典找到某个字符串,则匹配成功。 二元分词 一元分词 自动分类 向量距离分类算法 根据算术平均,为每类文本集生成一个代表该类的特征向量 提取待分类文本的特征向量 计算该向量与每类特征向量之间的相似度 判定文本属于与文本距离最近相似度最大的类别 自动分类 相似度计算公式: 系统基础类图 Road map 自动分类学习 文分词算法改进 支持多种格式的文档(doc, pdf…) 海量网站搜索的支持(分布式处理) 系统框架的优化和迭代改进
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值