zoukankan      html  css  js  c++  java
  • Lucene.net+盘古分词 做站内搜索

    Lucene.Net简介:

    Lucene.Net是由Java版本的Lucene(卢思银)移植过来的,所有的类、方法都几乎和Lucene一模一样,因此使用时参考Lucene即可。

    Lucene.Net只是一个全文检索开发包,不是一个成型的搜索引擎,它的功能就是把数据扔给Lucene.Net,查询数据的时候从Lucene.Net中查询数据,可以看做是提供了全文检索功能的数据库。Lucene.Net不管文本数据怎么来的。用户可以基于Lucene.Net开发满足自己需求的搜索引擎。Lucene.Net只能对文本信息进行检索。如果不是文本信息,要转换为文本信息。

    Lucene.Net内置一元分词算法,例:“北京欢迎你”,分词之后“北”  ”京”  欢”  ”迎 ” ”你”。

    明显不适用中文分词,所以这里需要用到一些中文的分词算法:庖丁解牛,盘古分词

    下面介绍Lucene.Net+盘古分词如何在项目中应用

    第一步:准备相关资料

    盘古分词: 链接:https://pan.baidu.com/s/1kUBe95X 密码:mrqi

    Lucene.Net :链接:https://pan.baidu.com/s/1eRSjLJ0 密码:z3zs

    第二步:添加

    1、将PanGu_Release_V2.3.1.0文件下的Dictionaries添加到项目根路径下并改名为Dict,添加PanGu.dll,PanGu.Lucene.Analyzer的引用

    2、把Dict目录下的所有文件右击“属性”->“复制到输出目录”设定为“如果较新则赋值”,这样每次生成的时候都会自动把文件拷贝到“binDebug”下

    3、添加Lucene.dll的引用

    第三步:

     1    //对输入的搜索条件进行分词
     2       public static string[] PanGuSplitWord(string str)
     3       {
     4           List<string> list = new List<string>();
     5            Analyzer analyzer = new PanGuAnalyzer();
     6             TokenStream tokenStream = analyzer.TokenStream("", new StringReader(str));
     7             Lucene.Net.Analysis.Token token = null;
     8             while ((token = tokenStream.Next()) != null)
     9             {
    10                 list.Add(token.TermText());
    11             }
    12             return list.ToArray();
    13       }
    14 
    15 
    16       // /创建HTMLFormatter,参数为高亮单词的前后缀
    17       public static string CreateHightLight(string keywords, string Content)
    18       {
    19           PanGu.HighLight.SimpleHTMLFormatter simpleHTMLFormatter =
    20            new PanGu.HighLight.SimpleHTMLFormatter("<font color="red">", "</font>");
    21           //创建Highlighter ,输入HTMLFormatter 和盘古分词对象Semgent
    22           PanGu.HighLight.Highlighter highlighter =
    23           new PanGu.HighLight.Highlighter(simpleHTMLFormatter,
    24           new Segment());
    25           //设置每个摘要段的字符数
    26           highlighter.FragmentSize = 150;
    27           //获取最匹配的摘要段
    28           return highlighter.GetBestFragment(keywords, Content);
    29 
    30       }
     1 public enum LuceneEnumType
     2     {
     3        Add,//向添加
     4        Delete//删除
     5     } 
     6 
     7 
     8 private  void WriteSearchContent()
     9         {
    10             string indexPath = @"C:lucenedir";//注意和磁盘上文件夹的大小写一致,否则会报错。将创建的分词内容放在该目录下。
    11             FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NativeFSLockFactory());//指定索引文件(打开索引目录) FS指的是就是FileSystem
    12             bool isUpdate = IndexReader.IndexExists(directory);//IndexReader:对索引进行读取的类。该语句的作用:判断索引库文件夹是否存在以及索引特征文件是否存在。
    13             if (isUpdate)
    14             {
    15                 //同时只能有一段代码对索引库进行写操作。当使用IndexWriter打开directory时会自动对索引库文件上锁。
    16                 //如果索引目录被锁定(比如索引过程中程序异常退出),则首先解锁(提示一下:如果我现在正在写着已经加锁了,但是还没有写完,这时候又来一个请求,那么不就解锁了吗?这个问题后面会解决)
    17                 if (IndexWriter.IsLocked(directory))
    18                 {
    19                     IndexWriter.Unlock(directory);
    20                 }
    21             }
    22             IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);//向索引库中写索引。这时在这里加锁。
    23             while (queue.Count > 0)
    24             {
    25               IndexContent indexContent =queue.Dequeue();//出队
    26               writer.DeleteDocuments(new Term("id", indexContent.Id.ToString()));
    27               if (indexContent.LuceneEnumType == LuceneEnumType.Delete)
    28               {
    29                   continue;
    30               }
    31                 Document document = new Document();//表示一篇文档。
    32 
    33                 //Field.Store.YES:表示是否存储原值。只有当Field.Store.YES在后面才能用doc.Get("number")取出值来.Field.Index. NOT_ANALYZED:不进行分词保存
    34                 document.Add(new Field("id", indexContent.Id.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
    35 
    36                 //Field.Index. ANALYZED:进行分词保存:也就是要进行全文的字段要设置分词 保存(因为要进行模糊查询)
    37 
    38                 //Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS:不仅保存分词还保存分词的距离。
    39                 document.Add(new Field("title", indexContent.Title, Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
    40 
    41                 document.Add(new Field("content", indexContent.Content, Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
    42                 writer.AddDocument(document);
    43             }
    44 
    45             writer.Close();//会自动解锁。
    46             directory.Close();//不要忘了Close,否则索引结果搜不到
    47         }
     1    /// <summary>
     2         /// 搜索
     3         /// </summary>
     4         public List<SearchResultViewModel> SearchBookContent()
     5         {
     6             string indexPath = @"C:lucenedir";
     7             string kw = Request["txtSearchContent"];
     8             string[] keywords = Common.WebCommon.PanGuSplitWord(kw);
     9             FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());
    10             IndexReader reader = IndexReader.Open(directory, true);
    11             IndexSearcher searcher = new IndexSearcher(reader);
    12             //搜索条件
    13             PhraseQuery query = new PhraseQuery();
    14             foreach (string word in keywords)//先用空格,让用户去分词,空格分隔的就是词“计算机   专业”
    15             {
    16                 query.Add(new Term("content", word));
    17             }
    18             //query.Add(new Term("body","语言"));--可以添加查询条件,两者是add关系.顺序没有关系.
    19             // query.Add(new Term("body", "大学生"));
    20          //   query.Add(new Term("content", kw));//body中含有kw的文章
    21             query.SetSlop(100);//多个查询条件的词之间的最大距离.在文章中相隔太远 也就无意义.(例如 “大学生”这个查询条件和"简历"这个查询条件之间如果间隔的词太多也就没有意义了。)
    22             //TopScoreDocCollector是盛放查询结果的容器
    23             TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);
    24             searcher.Search(query, null, collector);//根据query查询条件进行查询,查询结果放入collector容器
    25             ScoreDoc[] docs = collector.TopDocs(0, collector.GetTotalHits()).scoreDocs;//得到所有查询结果中的文档,GetTotalHits():表示总条数   TopDocs(300, 20);//表示得到300(从300开始),到320(结束)的文档内容.
    26             //可以用来实现分页功能
    27             List<SearchResultViewModel> searchResultList = new List<SearchResultViewModel>();
    28             for (int i = 0; i < docs.Length; i++)
    29             {
    30                 //
    31                 //搜索ScoreDoc[]只能获得文档的id,这样不会把查询结果的Document一次性加载到内存中。降低了内存压力,需要获得文档的详细内容的时候通过searcher.Doc来根据文档id来获得文档的详细内容对象Document.
    32                 int docId = docs[i].doc;//得到查询结果文档的id(Lucene内部分配的id)
    33                 Document doc = searcher.Doc(docId);//找到文档id对应的文档详细信息
    34                 SearchResultViewModel viewModel = new SearchResultViewModel();
    35                 viewModel.Id = int.Parse(doc.Get("id"));
    36                 viewModel.Title = doc.Get("title");
    37                 viewModel.Url = "/Book/ShowDetail/?id=" + viewModel.Id;
    38                 viewModel.Content =Common.WebCommon.CreateHightLight(kw, doc.Get("content"));
    39                 searchResultList.Add(viewModel);
    40             }
    41 
    42             SearchDetails searchDetail = new SearchDetails();
    43             searchDetail.KeyWords = kw;
    44             searchDetail.Id = Guid.NewGuid();
    45             searchDetail.SearchDateTime = DateTime.Now;
    46             searchDetailService.AddEntity(searchDetail);
    47             return searchResultList;
    48 
    49         }
      public class IndexContent
        {
            public string Id { get; set; }
            public string Title { get; set; }
            public string Content { get; set; }
            public LuceneEnumType LuceneEnumType { get; set; }
        }
    
      public enum DeleteEnumType
        {
            /// <summary>
            /// 正常显示
            /// </summary>
            Normal=0,
            /// <summary>
            /// 逻辑删除
            /// </summary>
            LogicDelete=1,
            /// <summary>
            /// 物理删除
            /// </summary>
            PhyicDelete=2
        }
     1 public sealed class IndexManager
     2     {
     3         private static readonly IndexManager indexManager = new IndexManager();
     4         private IndexManager()
     5         {
     6         }
     7         public static IndexManager GetInstance()
     8         {
     9             return indexManager;
    10         }
    11         Queue<IndexContent> queue = new Queue<IndexContent>();
    12         /// <summary>
    13         /// 调用该方法,向队列中添加数据
    14         /// </summary>
    15         /// <param name="id"></param>
    16         /// <param name="title"></param>
    17         /// <param name="content"></param>
    18         public  void AddOrEditQueue(string id,string title,string content)
    19         {
    20             IndexContent indexContent = new IndexContent();
    21             indexContent.Content = content;
    22             indexContent.Id = id;
    23             indexContent.Title = title;
    24             indexContent.LuceneEnumType = LuceneEnumType.Add;
    25             queue.Enqueue(indexContent);
    26         }
    27         /// <summary>
    28         /// 删除
    29         /// </summary>
    30         /// <param name="id"></param>
    31         public  void DeleteQueue(string id)
    32         {
    33             IndexContent indexContent = new IndexContent();
    34             indexContent.Id = id;
    35             indexContent.LuceneEnumType = LuceneEnumType.Delete;
    36             queue.Enqueue(indexContent);
    37         }
    38 
    39         /// <summary>
    40         /// 创建线程
    41         /// </summary>
    42         public  void CreateThread()
    43         {
    44             Thread myThread = new Thread(CreateSearchIndex);
    45             myThread.IsBackground = true;
    46             myThread.Start();
    47         }
    48 }

    第四步:

    在程序开始时

    IndexManager.GetInstance().CreateThread();//开启线程,扫描队列获取信息写到Lucene.Net中。

  • 相关阅读:
    401. Binary Watch
    46. Permutations
    61. Rotate List
    142. Linked List Cycle II
    86. Partition List
    234. Palindrome Linked List
    19. Remove Nth Node From End of List
    141. Linked List Cycle
    524. Longest Word in Dictionary through Deleting
    android ListView详解
  • 原文地址:https://www.cnblogs.com/zhhwDavidblog/p/8066983.html
Copyright © 2011-2022 走看看