• Lucene.net站内搜索—3、最简单搜索引擎代码


    目录

    Lucene.net站内搜索—1、SEO优化
    Lucene.net站内搜索—2、Lucene.Net简介和分词
    Lucene.net站内搜索—3、最简单搜索引擎代码
    Lucene.net站内搜索—4、搜索引擎第一版技术储备(简单介绍Log4Net、生产者消费者模式)
    Lucene.net站内搜索—5、搜索引擎第一版实现
    Lucene.net站内搜索—6、站内搜索第二版

    代码

    先看代码,后面再一一讲解

    引入命名空间:

    1. using Lucene.Net.Store;  
    2. using System.IO;  
    3. using Lucene.Net.Index;  
    4. using Lucene.Net.Analysis.PanGu;  
    5. using Lucene.Net.Documents;  
    6. using Lucene.Net.Search;  

    1、 对数据进行索引

    1. string indexPath = @"C:1017index";//注意和磁盘上文件夹的大小写一致,否则会报错。  
    2. FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NativeFSLockFactory());  
    3. bool isUpdate = IndexReader.IndexExists(directory);//判断索引库是否存在  
    4. if (isUpdate)  
    5. {  
    6.     //如果索引目录被锁定(比如索引过程中程序异常退出),则首先解锁  
    7.     //Lucene.Net在写索引库之前会自动加锁,在close的时候会自动解锁  
    8.     //不能多线程执行,只能处理意外被永远锁定的情况  
    9.     if (IndexWriter.IsLocked(directory))  
    10.     {  
    11.         IndexWriter.Unlock(directory);//un-否定。强制解锁  
    12.     }  
    13. }  
    14. IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);  
    15. for (int i = 1000; i < 1100; i++)  
    16. {  
    17.     string txt = File.ReadAllText(@"D:我的文档文章" + i + ".txt");  
    18.     Document document = new Document();//一条Document相当于一条记录  
    19.     document.Add(new Field("id", i.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));  
    20.     //每个Document可以有自己的属性(字段),所有字段名都是自定义的,值都是string类型  
    21.     //Field.Store.YES不仅要对文章进行分词记录,也要保存原文,就不用去数据库里查一次了  
    22.     //需要进行全文检索的字段加 Field.Index. ANALYZED  
    23.     document.Add(new Field("msg", txt, Field.Store.YES, Field.Index.ANALYZED, 
    24. Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));  
    25.     //防止重复索引  
    26.     writer.DeleteDocuments(new Term("id", i.ToString()));//防止存在的数据//delete from t where id=i  
    27.     //如果不存在则删除0条  
    28.     writer.AddDocument(document);//把文档写入索引库  
    29. }  
    30. writer.Close();  
    31. directory.Close();//不要忘了Close,否则索引结果搜不到  

    2、搜索的代码

    1. string indexPath = @"C:1017index";  
    2.   
    3. string kw = TextBox1.Text;  
    4. FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());  
    5. IndexReader reader = IndexReader.Open(directory, true);  
    6. IndexSearcher searcher = new IndexSearcher(reader);  
    7. PhraseQuery query = new PhraseQuery();//查询条件  
    8. query.Add(new Term("msg", kw));//where contains("msg",kw)  
    9. //foreach (string word in kw.Split(' '))//先用空格,让用户去分词,空格分隔的就是词“计算机 专业”  
    10. //{  
    11. //    query.Add(new Term("msg", word));//contains("msg",word)  
    12. //}  
    13. query.SetSlop(100);//两个词的距离大于100(经验值)就不放入搜索结果,因为距离太远相关度就不高了  
    14. TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);//盛放查询结果的容器  
    15. searcher.Search(query, null, collector);//使用query这个查询条件进行搜索,搜索结果放入collector  
    16. //collector.GetTotalHits()总的结果条数  
    17. ScoreDoc[] docs = collector.TopDocs(0, collector.GetTotalHits()).scoreDocs;//从查询结果中取出第m条到第n条的数据  
    18.   
    19. List<SearchResult> list = new List<SearchResult>();  
    20. for (int i = 0; i < docs.Length; i++)//遍历查询结果  
    21. {  
    22.     int docId = docs[i].doc;//拿到文档的id。因为Document可能非常占内存(DataSet和DataReader的区别)  
    23.     //所以查询结果中只有id,具体内容需要二次查询  
    24.     Document doc = searcher.Doc(docId);//根据id查询内容。放进去的是Document,查出来的还是Document  
    25.     //Console.WriteLine(doc.Get("id"));  
    26.     //Console.WriteLine(doc.Get("msg"));  
    27.     SearchResult result = new SearchResult();  
    28.     result.Id = Convert.ToInt32(doc.Get("id"));  
    29.     result.Msg = doc.Get("msg");//只有 Field.Store.YES的字段才能用Get查出来  
    30.     list.Add(result);  
    31. }  
    32.   
    33. Repeater1.DataSource = list;  
    34. Repeater1.DataBind();  

    aspx代码:

    1. <form id="form1" runat="server">  
    2. <div>  
    3.     <asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="创建索引" />  
    4.     <br />  
    5.     <br />  
    6.     <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>  
    7.     <asp:Button ID="Button2" runat="server" onclick="Button2_Click" Text="搜索" />  
    8.     <br />  
    9.     <ul>  
    10.     <asp:Repeater ID="Repeater1" runat="server">  
    11.         <ItemTemplate><li>Id:<%#Eval("Id") %><br /><%#Eval("Msg") %></li></ItemTemplate>  
    12.     </asp:Repeater>  
    13.     </ul>  
    14. </div>  
    15. </form

    Lucene.Net核心类简介

        先运行写好的索引的代码,再向下讲解各个类的作用,不用背代码。

       (*)Directory表示索引文件(Lucene.net用来保存用户扔过来的数据的地方)保存的地方,是抽象类,两个子类FSDirectory(文件中)、RAMDirectory (内存中)。使用的时候别和IO里的Directory弄混了。

        创建FSDirectory的方法,FSDirectory directory =FSDirectory.Open(new DirectoryInfo(indexPath),new NativeFSLockFactory()), path索引的文件夹路径

        IndexReader对索引进行读取的类,对IndexWriter进行写的类。IndexReader的静态方法bool IndexExists(Directory directory)判断目录directory是否是一个索引目录。IndexWriter的bool IsLocked(Directory directory) 判断目录是否锁定,在对目录写之前会先把目录锁定。两个IndexWriter没法同时写一个索引文件。IndexWriter在进行写操作的时候会自动 加锁,close的时候会自动解锁。IndexWriter.Unlock方法手动解锁(比如还没来得及close IndexWriter 程序就崩溃了,可能造成一直被锁定)。

    创建索引

        构造函数:IndexWriter(Directorydir, Analyzer a, bool create, MaxFieldLength mfl)因为IndexWriter把输入写入索引的时候,Lucene.net是把写入的文件用指定的分词器将文章分词(这样检索的时候才能查的快), 然后将词放入索引文件。

        void AddDocument(Document doc),向索引中添加文档(Insert)。Document类代表要索引的文档(文章),最重要的方法Add(Field field),向文档中添加字段。Document是一片文档,Field是字段(属性)。Document相当于一条记录,Field相当于字段。

        Field类的构造函数 Field(string name, string value, Field.Store store, Field.Indexindex, Field.TermVector termVector):name表示字段名; value表示字段值;

        store表示是否存储value值,可选值Field.Store.YES存储,Field.Store.NO不存 储,Field.Store.COMPRESS压缩存储;默认只保存分词以后的一堆词,而不保存分词之前的内容,搜索的时候无法根据分词后的东西还原原 文,因此如果要显示原文(比如文章正文)则需要设置存储。

        index表示如何创建索引,可选值Field.Index. NOT_ANALYZED,不创建索引,Field.Index. ANALYZED,创建索引;创建索引的字段才可以比较好的检索。是否碎尸万段!是否需要按照这个字段进行“全文检索”。

        termVector表示如何保存索引词之间的距离。“北京欢迎你们大家”,索引中是如何保存“北京”和“大家”之间“隔多少单词”。方便只检索在一定距离之内的词。

        为什么要把帖子的url做为一个Field,因为要在搜索展示的时候先帖子地址取出来构建超链接,所以Field.Store.YES;一般不需要 对url进行检索,所以Field.Index.NOT_ANALYZED 。根据《红楼梦》构建的“词:页数”纸,在构建完成后就可以把原文《红楼梦》扔了

    案例:对1000至1100号帖子进行索引。“只要能看懂例子和文档,稍作修改即可实现自己的需求”。除了基础知识外,第三方开发包只要“能看懂,改改即可”

    搜索

        IndexSearcher是进行搜索的类,构造函数传递一个IndexReader。IndexSearcher的void Search(Query query, Filter filter, Collector results)方法用来搜索,Query是查询条件, filter目前传递null, results是检索结果,TopScoreDocCollector.create(1000, true)方法创建一个Collector,1000表示最多结果条数,Collector就是一个结果收集器。


        搜索所采用的分词算法必须和索引的一致。Query有很多子类,PhraseQuery是一个子类。 PhraseQuery用来进行多个关键词的检索,调用Add方法添加关键词,query.Add(new Term("字段名", 关键词)),PhraseQuery. SetSlop(int slop)用来设置关键词之间的最大距离,默认是0,设置了Slop以后哪怕文档中两个关键词之间没有紧挨着也能找到。query.Add(new Term("字段名", 关键词))query.Add(new Term("字段名2", 关键词2))
    类似于:where 字段名 contains 关键词 and 字段名2 contains 关键词2


        如何实现字段名 contains 关键词 or 字段名2 contains 关键词2, BooleanQuery:MUST// 与运算;SHOULD // 或运算;MUST_NOT// 非运算

        调用TopScoreDocCollector的GetTotalHits()方法得到搜索结果条数,调用Hits的TopDocs TopDocs(int start, int howMany)得到一个范围内的结果(分页),TopDocs的scoreDocs字段是结果ScoreDoc数组, ScoreDoc 的doc字段为Lucene.Net为文档分配的id(为降低内存占用,只先返回文档id),根据这个id调用searcher的Doc方法就能拿到Document了(放进去的是Document,取出来的也是Document);

        调用doc.Get("字段名")可以得到文档指定字段的值,注意只有Store.YES的字段才能得到,因为Store.NO的没有保存全部内容,只保存了分割后的词。
    编写检索功能,搜索“网站 志愿者”。练习分词,用户不用空格。如果确定用盘古分词,那么用盘古的Segment类更方便。检索不出来的可能的原因:路径问题,分词是否正确、盘古分词如果指定忽略大小写,则需要统一按照小写进行搜索。Todo:第一个版本应该保存body和title,搜索结果形成超链接,不显示正文。
        文章重复索引的问题

    总结下执行顺序:发布文章的时候,创建索引,然后搜索文章的时候,就直接从索引库进行搜索。

    使用回顾

    1、解压PanGu4Lucene_V2.3.1.0.zip,把Dictionaries放到项目中,改名为Dict,然后把Dict文件夹下的文件都设置为“如果较新则复制。”(网站是没有那个选项的。都用Web应用程序)
    2、再添加对Lucene.Net.dll、PanGu.dll、PanGu.Lucene.Analyzer.dll(Pangu分词和Lucene的一个桥接)。
    设置断点查找问题,断点要设在关键性的行上,看是上面的问题还是下面的问题,二分法。

  • 相关阅读:
    【转】【SEE】基于SSE指令集的程序设计简介
    【转】【Asp.Net】asp.net服务器控件创建
    ControlTemplate in WPF ——ScrollBar
    ControlTemplate in WPF —— Menu
    ControlTemplate in WPF —— Expander
    ControlTemplate in WPF —— TreeView
    ControlTemplate in WPF —— ListBox
    ControlTemplate in WPF —— ComboBox
    ControlTemplate in WPF —— TextBox
    ControlTemplate in WPF —— RadioButton
  • 原文地址:https://www.cnblogs.com/jiekzou/p/4364780.html
Copyright © 2020-2023  润新知