天天看點

一步步開發自己的部落格 .NET版(5、Lucenne.Net 和 必應站内搜尋)

一步步開發自己的部落格 .NET版(5、Lucenne.Net 和 必應站内搜尋)

今天來分析下 嗨-部落格 中的搜尋功能。搜尋功能在個人網站裡面要有這麼個東西,但又不是特别重要。是以我們需要有,可以不用太深入了解,畢竟我們不是專門做搜尋這塊的。

是以,我打算把搜尋分兩塊。一塊是,用Lucene.Net實作站内搜尋。一塊是利用第三方搜尋引擎來 實作站内搜尋。

前言 

    這次開發的部落客要功能或特點:

    第一:可以相容各終端,特别是手機端。

    第二:到時會用到大量html5,炫啊。

    第三:導入部落格園的精華文章,并做分類。(不要封我)

    第四:做個插件,任何網站上的技術文章都可以轉發收藏 到本部落格。

是以打算寫個系類:《一步步搭建自己的部落格》

  • 一步步開發自己的部落格  .NET版(1、頁面布局、blog遷移、資料加載)
  • 一步步開發自己的部落格  .NET版(2、評論功能)
  • 一步步開發自己的部落格  .NET版(3、注冊登入功能)
  • 一步步開發自己的部落格  .NET版(4、文章釋出功能)
  • 一步步開發自己的部落格  .NET版(5、搜尋功能)
  • 一步步開發自己的部落格  .NET版(6、手機端的相容)

示範位址:http://haojima.net/      群内共享源碼:469075305 

一步步開發自己的部落格 .NET版(5、Lucenne.Net 和 必應站内搜尋)

Lucene.Net簡介

Lucene.net是Lucene的.net移植版本,是一個開源的全文檢索引擎開發包,即它不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎。開發人員可以基于Lucene.net實作全文檢索的功能。

Lucene.net是Apache軟體基金會贊助的開源項目,基于Apache License協定。

Lucene.net并不是一個爬行搜尋引擎,也不會自動地索引内容。我們得先将要索引的文檔中的文本抽取出來,然後再将其加到Lucene.net索引中。标準的步驟是先初始化一個Analyzer、打開一個IndexWriter、然後再将文檔一個接一個地加進去。一旦完成這些步驟,索引就可以在關閉前得到優化,同時所做的改變也會生效。這個過程可能比開發者習慣的方式更加手工化一些,但卻在資料的索引上給予你更多的靈活性,而且其效率也很高。(來源百度百科)

Lucene幫助類

其實 在之前 我也是接觸到過Lucene.net,那也是自己 做的個小玩意(部落格備份小工具3)  瞎折騰的。但是 這次打算遷移到這個系統中,不知怎麼的 報錯了。可能是這次用的是 .net 4.5。Lucene這東西太高深,我也沒打算深究。于是 在網上收索了一把,資料還挺多的。《lucene.net 3.0.3、結合盤古分詞進行搜尋的小例子(分頁功能)》 我随意看了下,這裡有個 幫助類 挺不錯的,也還符合 我這樣想要的效果。這裡來分析下這個幫助類。 

1.首先建立索引。      

IndexWriter writer = new IndexWriter(directory_luce, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);
Document doc = new Document();
doc.Add(new Field(name, value, Field.Store.YES, Field.Index.NOT_ANALYZED));
writer.AddDocument(doc);      

這裡的 

directory_luce 是索引建立路徑

analyzer 分析器

value 是對應 存入索引額名字和值

2.從索引裡面搜尋       

string[] fileds = { "title", "content" };//查詢字段           
            QueryParser parser = null;
            parser = new MultiFieldQueryParser(version, fileds, analyzer);//多個字段查詢
            Query query = parser.Parse(keyword);
            int n = 1000;
            IndexSearcher searcher = new IndexSearcher(directory_luce, true);//true-表示隻讀
            TopDocs docs = searcher.Search(query, (Filter)null, n);
            if (docs == null || docs.TotalHits == 0)
            {
                return null;
            }
            else
            {
                List<SearchResult> list = new List<SearchResult>();
                int counter = 1;
                foreach (ScoreDoc sd in docs.ScoreDocs)//周遊搜尋到的結果
                {
                    try
                    {
                        Document doc = searcher.Doc(sd.Doc);
                        int id = int.Parse(doc.Get("id"));
                        string title = doc.Get("title");
                        string content = doc.Get("content");
                        string blogTag = doc.Get("blogTag");
                        string url = doc.Get("url");
                        int flag = int.Parse(doc.Get("flag"));
                        int clickQuantity = int.Parse(doc.Get("clickQuantity"));

                        string createdate = doc.Get("createdate");
                        PanGu.HighLight.SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color=\"red\">", "</font>");
                        PanGu.HighLight.Highlighter highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new PanGu.Segment());
                        highlighter.FragmentSize = 50;
                        content = highlighter.GetBestFragment(keyword, content);
                        string titlehighlight = highlighter.GetBestFragment(keyword, title);
                        if (titlehighlight != "") title = titlehighlight;

                        list.Add(new SearchResult(title, content, url, blogTag, id, clickQuantity, flag));
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    counter++;
                }
                return list;      

3.完整代碼

一步步開發自己的部落格 .NET版(5、Lucenne.Net 和 必應站内搜尋)
一步步開發自己的部落格 .NET版(5、Lucenne.Net 和 必應站内搜尋)
public class PanGuLuceneHelper
    {
        private PanGuLuceneHelper() { }

        #region 單一執行個體
        private static PanGuLuceneHelper _instance = null;
        /// <summary>
        /// 單一執行個體
        /// </summary>
        public static PanGuLuceneHelper instance
        {
            get
            {
                if (_instance == null) _instance = new PanGuLuceneHelper();
                return _instance;
            }
        }
        #endregion

        #region 00一些屬性和參數
        #region Lucene.Net的目錄-參數
        private Lucene.Net.Store.Directory _directory_luce = null;
        /// <summary>
        /// Lucene.Net的目錄-參數
        /// </summary>
        public Lucene.Net.Store.Directory directory_luce
        {
            get
            {
                if (_directory_luce == null) _directory_luce = Lucene.Net.Store.FSDirectory.Open(directory);
                return _directory_luce;
            }
        }
        #endregion

        #region 索引在硬碟上的目錄
        private System.IO.DirectoryInfo _directory = null;
        /// <summary>
        /// 索引在硬碟上的目錄
        /// </summary>
        public System.IO.DirectoryInfo directory
        {
            get
            {
                if (_directory == null)
                {
                    string dirPath = AppDomain.CurrentDomain.BaseDirectory + "SearchIndex";
                    if (System.IO.Directory.Exists(dirPath) == false) _directory = System.IO.Directory.CreateDirectory(dirPath);
                    else _directory = new System.IO.DirectoryInfo(dirPath);
                }
                return _directory;
            }
        }
        #endregion

        #region 分析器
        private Analyzer _analyzer = null;
        /// <summary>
        /// 分析器
        /// </summary>
        public Analyzer analyzer
        {
            get
            {
                {
                    _analyzer = new Lucene.Net.Analysis.PanGu.PanGuAnalyzer();//                   
                }
                return _analyzer;
            }
        }
        #endregion

        #region 版本号枚舉類
        private static Lucene.Net.Util.Version _version = Lucene.Net.Util.Version.LUCENE_30;
        /// <summary>
        /// 版本号枚舉類
        /// </summary>
        public Lucene.Net.Util.Version version
        {
            get
            {
                return _version;
            }
        }
        #endregion
        #endregion

        #region 01建立索引
        /// <summary>
        /// 建立索引(先删 後更新)
        /// </summary>
        /// <param name="datalist"></param>
        /// <returns></returns>
        public bool CreateIndex(List<SearchResult> datalist)
        {
            IndexWriter writer = null;
            try
            {
                writer = new IndexWriter(directory_luce, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);//false表示追加(true表示删除之前的重新寫入)
            }
            catch
            {
                writer = new IndexWriter(directory_luce, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);//false表示追加(true表示删除之前的重新寫入)
            }
            foreach (SearchResult data in datalist)
            {
                writer.DeleteDocuments(new Term("id", data.id.ToString()));//新增前 删除  不然會有重複資料
                CreateIndex(writer, data);
            }
            writer.Optimize();
            writer.Dispose();
            return true;
        }
        public bool CreateIndex(SearchResult data)
        {
            List<SearchResult> datalist = new List<SearchResult>();
            datalist.Add(data);
            return CreateIndex(datalist);
        } 

        public bool CreateIndex(IndexWriter writer, SearchResult data)
        {
            try
            {

                if (data == null) return false;
                Document doc = new Document();
                Type type = data.GetType();//assembly.GetType("Reflect_test.PurchaseOrderHeadManageModel", true, true); //命名空間名稱 + 類名    

                //建立類的執行個體    
                //object obj = Activator.CreateInstance(type, true);  
                //擷取公共屬性    
                PropertyInfo[] Propertys = type.GetProperties();
                for (int i = 0; i < Propertys.Length; i++)
                {
                    //Propertys[i].SetValue(Propertys[i], i, null); //設定值
                    PropertyInfo pi = Propertys[i];
                    string name = pi.Name;
                    object objval = pi.GetValue(data, null);
                    string value = objval == null ? "" : objval.ToString(); //值                   
                    if (name == "id" || name == "flag")//id在寫入索引時必是不分詞,否則是模糊搜尋和删除,會出現混亂
                    {
                        doc.Add(new Field(name, value, Field.Store.YES, Field.Index.NOT_ANALYZED));//id不分詞
                    }
                    else
                    {
                        doc.Add(new Field(name, value, Field.Store.YES, Field.Index.ANALYZED));
                    }
                }
                writer.AddDocument(doc);
            }
            catch (System.IO.FileNotFoundException fnfe)
            {
                throw fnfe;
            }
            return true;
        }
        #endregion

        #region 02在title和content字段中查詢資料
        /// <summary>
        /// 在title和content字段中查詢資料
        /// </summary>
        /// <param name="keyword"></param>
        /// <returns></returns>
        public List<SearchResult> Search(string keyword)
        {
            string[] fileds = { "title", "content" };//查詢字段           
            QueryParser parser = null;
            parser = new MultiFieldQueryParser(version, fileds, analyzer);//多個字段查詢
            Query query = parser.Parse(keyword);
            int n = 1000;
            IndexSearcher searcher = new IndexSearcher(directory_luce, true);//true-表示隻讀
            TopDocs docs = searcher.Search(query, (Filter)null, n);
            if (docs == null || docs.TotalHits == 0)
            {
                return null;
            }
            else
            {
                List<SearchResult> list = new List<SearchResult>();
                int counter = 1;
                foreach (ScoreDoc sd in docs.ScoreDocs)//周遊搜尋到的結果
                {
                    try
                    {
                        Document doc = searcher.Doc(sd.Doc);
                        int id = int.Parse(doc.Get("id"));
                        string title = doc.Get("title");
                        string content = doc.Get("content");
                        string blogTag = doc.Get("blogTag");
                        string url = doc.Get("url");
                        int flag = int.Parse(doc.Get("flag"));
                        int clickQuantity = int.Parse(doc.Get("clickQuantity"));

                        string createdate = doc.Get("createdate");
                        PanGu.HighLight.SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color=\"red\">", "</font>");
                        PanGu.HighLight.Highlighter highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new PanGu.Segment());
                        highlighter.FragmentSize = 50;
                        content = highlighter.GetBestFragment(keyword, content);
                        string titlehighlight = highlighter.GetBestFragment(keyword, title);
                        if (titlehighlight != "") title = titlehighlight;

                        list.Add(new SearchResult(title, content, url, blogTag, id, clickQuantity, flag));
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    counter++;
                }
                return list;
            }
            //st.Stop();
            //Response.Write("查詢時間:" + st.ElapsedMilliseconds + " 毫秒<br/>");

        }
        #endregion

        #region 03在不同的分類下再根據title和content字段中查詢資料(分頁)
        /// <summary>
        /// 在不同的類型下再根據title和content字段中查詢資料(分頁)
        /// </summary>
        /// <param name="_flag">分類,傳空值查詢全部</param>
        /// <param name="keyword"></param>
        /// <param name="PageIndex"></param>
        /// <param name="PageSize"></param>
        /// <param name="TotalCount"></param>
        /// <returns></returns>
        public List<SearchResult> Search(string _flag, string keyword, int PageIndex, int PageSize)
        {
            if (PageIndex < 1) PageIndex = 1;
            Stopwatch st = Stopwatch.StartNew();
            st.Start();
            BooleanQuery bq = new BooleanQuery();
            if (_flag != "")
            {
                QueryParser qpflag = new QueryParser(version, "flag", analyzer);
                Query qflag = qpflag.Parse(_flag);
                bq.Add(qflag, Occur.MUST);//與運算
            }
            if (keyword != "")
            {
                string[] fileds = { "blogTag", "title", "content" };//查詢字段
                QueryParser parser = null;// new QueryParser(version, field, analyzer);//一個字段查詢
                parser = new MultiFieldQueryParser(version, fileds, analyzer);//多個字段查詢
                Query queryKeyword = parser.Parse(keyword);
                bq.Add(queryKeyword, Occur.MUST);//與運算
            }

            TopScoreDocCollector collector = TopScoreDocCollector.Create(PageIndex * PageSize, false);
            IndexSearcher searcher = new IndexSearcher(directory_luce, true);//true-表示隻讀
            searcher.Search(bq, collector);

            if (collector == null || collector.TotalHits == 0)
            {
                //TotalCount = 0;
                return null;
            }
            else
            {
                int start = PageSize * (PageIndex - 1);
                //結束數
                int limit = PageSize;
                ScoreDoc[] hits = collector.TopDocs(start, limit).ScoreDocs;
                List<SearchResult> list = new List<SearchResult>();
                int counter = 1;
                //TotalCount = collector.TotalHits;
                st.Stop();
                //st.ElapsedMilliseconds;//毫秒
                foreach (ScoreDoc sd in hits)//周遊搜尋到的結果
                {
                    try
                    {
                        Document doc = searcher.Doc(sd.Doc);
                        int id = int.Parse(doc.Get("id"));
                        string title = doc.Get("title");
                        string content = doc.Get("content");
                        string blogTag = doc.Get("blogTag");
                        string url = doc.Get("url");
                        int flag = int.Parse(doc.Get("flag"));
                        int clickQuantity = int.Parse(doc.Get("clickQuantity"));
                        content = Highlight(keyword, content);
                        //string titlehighlight = Highlight(keyword, title);
                        //if (titlehighlight != "") title = titlehighlight;
                        list.Add(new SearchResult(title, content, url, blogTag, id, clickQuantity, flag));
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    counter++;
                }
                return list;
            }
        }
        #endregion

        #region 把content按照keywords進行高亮
        /// <summary>
        /// 把content按照keywords進行高亮
        /// </summary>
        /// <param name="keywords"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        private static string Highlight(string keywords, string content)
        {
            SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<strong>", "</strong>");
            Highlighter highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new Segment());
            highlighter.FragmentSize = 200;
            return highlighter.GetBestFragment(keywords, content);
        }
        #endregion

        #region 04删除索引
        #region 删除索引資料(根據id)
        /// <summary>
        /// 删除索引資料(根據id)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool Delete(string id)
        {
            bool IsSuccess = false;
            Term term = new Term("id", id);
            IndexWriter writer = new IndexWriter(directory_luce, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);
            writer.DeleteDocuments(term); // writer.DeleteDocuments(term)或者writer.DeleteDocuments(query);            
            writer.Commit();
            IsSuccess = writer.HasDeletions();
            writer.Dispose();
            return IsSuccess;
        }
        #endregion

        #region 删除全部索引資料
        /// <summary>
        /// 删除全部索引資料
        /// </summary>
        /// <returns></returns>
        public bool DeleteAll()
        {
            bool IsSuccess = true;
            try
            {
                IndexWriter writer = new IndexWriter(directory_luce, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);
                writer.DeleteAll();
                writer.Commit();
                IsSuccess = writer.HasDeletions();
                writer.Dispose();
            }
            catch
            {
                IsSuccess = false;
            }
            return IsSuccess;
        }
        #endregion
        #endregion

        #region 分詞測試
        /// <summary>
        /// 分詞測試
        /// </summary>
        /// <param name="keyword"></param>
        /// <returns></returns>
        public string Token(string keyword)
        {
            string ret = "";
            System.IO.StringReader reader = new System.IO.StringReader(keyword);
            Lucene.Net.Analysis.TokenStream ts = analyzer.TokenStream(keyword, reader);
            bool hasNext = ts.IncrementToken();
            Lucene.Net.Analysis.Tokenattributes.ITermAttribute ita;
            while (hasNext)
            {
                ita = ts.GetAttribute<Lucene.Net.Analysis.Tokenattributes.ITermAttribute>();
                ret += ita.Term + "|";
                hasNext = ts.IncrementToken();
            }
            ts.CloneAttributes();
            reader.Close();
            analyzer.Close();
            return ret;
        }
        #endregion

    }      

View Code

一步步開發自己的部落格 .NET版(5、Lucenne.Net 和 必應站内搜尋)
一步步開發自己的部落格 .NET版(5、Lucenne.Net 和 必應站内搜尋)
public class SearchResult
    {
        public SearchResult() { }

        public SearchResult(string title, string content, string url, string blogTag, int id, int clickQuantity, int flag)
        {
            this.blogTag = blogTag;
            this.clickQuantity = clickQuantity;
            this.content = content;
            this.id = id;
            this.url = url;
            this.title = title;
            this.flag = flag;
        }
        /// <summary>
        /// 标題
        /// </summary>
        public string title { get; set; }
        /// <summary>
        /// 正文内容
        /// </summary>
        public string content { get; set; }
        /// <summary>
        /// url位址
        /// </summary>
        public string url { get; set; }
        /// <summary>
        /// tag标簽
        /// </summary>
        public string blogTag { get; set; }
        /// <summary>
        /// 唯一id
        /// </summary>
        public int id { get; set; }
        /// <summary>
        /// 點選量
        /// </summary>
        public int clickQuantity { get; set; }
        /// <summary>
        /// 标記(使用者) 
        /// </summary>
        public int flag { get; set; }
    }      

必應站内搜尋

1.為什麼要用必應搜尋?

因為我們現在做的主要功能是部落格系統,搜尋隻是其中的一小塊環節。而 我對這搜尋并不了解,是以就用第三方搜尋,省事嘛。

2.為什麼不用别的三方收索呢?

百度?不用說了,咱們程式員都懂的。谷歌?我倒是想用,可生在天朝,也是沒得辦法。選來選去 還是選了必應。

3.怎麼來使用第三方的站内搜尋?

格式如下:http://cn.bing.com/search?q=關鍵字+site:網站位址 

例如:http://cn.bing.com/search?q=部落格+site:blog.haojima.net 

效果圖:

一步步開發自己的部落格 .NET版(5、Lucenne.Net 和 必應站内搜尋)

嘿嘿,如此之簡單。既然都已經看到效果了,那麼 我們可以幹些什麼呢?

一步步開發自己的部落格 .NET版(5、Lucenne.Net 和 必應站内搜尋)

 我打算 直接把結果 顯示在我的 站内搜尋結果。為什麼 不直接跳轉到這個頁面顯示 搜尋結果?因為 這個頁面有廣告什麼的,不能按照我自己的方式顯示。我直接把結果放我的搜尋頁面 可以和 我上面用Lucene.net的搜尋結果一起顯示,這樣豈不是 顯得更專業。

一步步開發自己的部落格 .NET版(5、Lucenne.Net 和 必應站内搜尋)

,不知道的 還以為 是我自己怎麼弄出來的。那麼 我們怎麼解析 搜到的結果呢?我這裡推薦下  Jumony  之前我一直是用 HtmlAgilityPack  ,現在為什麼不用了,因為有了更好的。HtmlAgilityPack 缺點是 要去xpath,然 如果頁面存在js動态改變文檔結構的話,我們直接F12 複制出來的 xpath是不準的。那麼有人 會說  HtmlAgilityPack  我已經用習慣了,不想 重新學習Jumony 。這裡我告訴你錯了,根本就需要重新學習,如果你會jquery 的話。常用功能文法基本一樣,還支援拉姆達表達式,爽的一逼。

我們來看看 怎麼使用Jumony 解析 解鎖結果吧。

var document = jumony.LoadDocument(url);
var list = document.Find("#b_results .b_algo").ToList().Select(t => t.ToString()).ToList();      

兩行代碼搞定,還直接轉成了list集合。在頁面循環加載就ok了。

站内下的某個使用者内搜尋

 我個人覺得 這是個蠻實用的功能,我們有時候 寫了部落格(很多時候我們寫部落格就是把自己怕會忘記的知識點 整理記錄),而後期找不到。那麼通過這個功能 可以很好的解決我們的問題。我們不想全站搜尋,隻搜尋自己的内容就可以了。

頁面還是用全站的搜尋頁面,我們直接在搜尋關鍵詞上做手腳就可以了。比如,我們想搜尋  zhaopei  使用者下的内容,那麼我們可以要搜尋的關鍵字前面加上  blog:zhaopei   那麼完整的搜尋關鍵字就成了  blog:zhaopei 關鍵字 

 那麼  我們要做的就是 在使用者頁面 搜尋 就在關鍵字 前面加上  blog:使用者名  我們在搜尋 頁面解析的時候 需要做的就是 分解關鍵字 blog:使用者名 關鍵字  先用空格 分割 然後如果中間有 空格的話 ,然後判斷 前面五個字元是不是 blog: 然後截取 到使用者名和 關鍵字。

我們下面具體看看 在Lucene.net 和 必應搜尋裡面是怎麼做的。

1.Lucene.net 

#region 加載 Lucene.net 的搜尋結果
        /// <summary>
        /// 加載 Lucene.net 的搜尋結果
        /// </summary>
        /// <returns></returns>
        public ActionResult ShowLuceneResult()
        {
            if (!Request.QueryString.AllKeys.Contains("key"))
                return null;
            string key = Request.QueryString["key"];

            var zhankey = key.Split(' ');//分割關鍵字
            var blogName = string.Empty;
            if (zhankey.Length >= 2)
            {
                var str = zhankey[0].Trim();
                if (str.Length > 6 && str.Substring(0, 5) == "blog:")
                    blogName = str.Substring(5);//取得使用者名
            }

            string userid = Request.QueryString.AllKeys.Contains("userid") ? Request.QueryString["userid"] : "";

            //這裡判斷是否 使用者名不為空  然後取得使用者對應的 使用者ID  (因為 我在做Lucene 是用使用者id 來标記的)
            if (!string.IsNullOrEmpty(blogName))
            {
                key = key.Substring(key.IndexOf(' '));
                var userinfo = CacheData.GetAllUserInfo().Where(t => t.UserName == blogName).FirstOrDefault();
                if (null != userinfo)
                    userid = userinfo.Id.ToString();
            }

            string pIndex = Request.QueryString.AllKeys.Contains("p") ? Request.QueryString["p"] : "";
            int PageIndex = 1;
            int.TryParse(pIndex, out PageIndex);

            int PageSize = 10;
            var searchlist = PanGuLuceneHelper.instance.Search(userid, key, PageIndex, PageSize);
            return PartialView(searchlist);
        }
        #endregion      

 2.  必應搜尋

#region  加載 bing  的搜尋結果
        /// <summary>
        /// 加載 bing  的搜尋結果
        /// </summary>
        /// <returns></returns>
        public ActionResult ShowBingResult()
        {
            if (!Request.QueryString.AllKeys.Contains("key"))
                return null;
            string key = Request.QueryString["key"];//搜尋關鍵字
            JumonyParser jumony = new JumonyParser();
            //http://cn.bing.com/search?q=AJAX+site%3ablog.haojima.net&first=11&FORM=PERE
            string pIndex = Request.QueryString.AllKeys.Contains("p") ? Request.QueryString["p"] : "";
            int PageIndex = 1;
            int.TryParse(pIndex, out PageIndex);
            PageIndex--;

            //如:blog:JeffreyZhao 部落格
            var zhankey = key.Split(' ');//先用空格分割
            var blogName = string.Empty;
            if (zhankey.Length >= 2)
            {
                var str = zhankey[0].Trim();
                if (str.Length > 6 && str.Substring(0, 5) == "blog:")
                    blogName = "/" + str.Substring(5);//這裡取得 使用者名
            }
            if (!string.IsNullOrEmpty(blogName))
                key = key.Substring(key.IndexOf(' '));

            //如:
            var url = "http://cn.bing.com/search?q=" + key + "+site:" + siteUrl + blogName + "&first=" + PageIndex + "1&FORM=PERE";
            var document = jumony.LoadDocument(url);
            var list = document.Find("#b_results .b_algo").ToList().Select(t => t.ToString()).ToList();

            var listli = document.Find("li.b_pag nav ul li");
            if (PageIndex > 0 && listli.Count() == 0)
                return null;

            if (listli.Count() > 1)
            {
                var text = document.Find("li.b_pag nav ul li").Last().InnerText();
                int npage = -1;
                if (text == "下一頁")
                {
                    if (listli.Count() > 1)
                    {
                        var num = listli.ToList()[listli.Count() - 2].InnerText();
                        int.TryParse(num, out npage);
                    }
                }
                else
                    int.TryParse(text, out npage);
                if (npage <= PageIndex)
                    list = null;
            }

            return PartialView(list);
        }
        #endregion      

 看看 我們的搜尋結果的效果圖吧。

一步步開發自己的部落格 .NET版(5、Lucenne.Net 和 必應站内搜尋)

總結

首先 搜尋是必不可少的功能,但又不是主要功能。那麼我們可以直接用lucene.net 來做搜尋,然後用必應搜尋做備用。但是 用必應 有個弊端。就是  如果我們 的文章頁面 被使用者自己删除了,而 必應已經收錄了,那麼 我們在搜尋結果頁面 點選 可能就是404 或 500 了。當然 我們自己的 lucene.net 也會有這個 問題,我們可以在使用者删除 文章的時候 也删除 對應的那天搜尋索引就好了。

示範位址:http://blog.haojima.net/Search/Index?key=blog:zhaopei 部落格&p=1 

如果您對本篇文章感興趣,那就麻煩您點個贊,您的鼓勵将是我的動力。 當然您還可以加入QQ群:

一步步開發自己的部落格 .NET版(5、Lucenne.Net 和 必應站内搜尋)

讨論。

如果您有更好的處理方式,希望不要吝啬賜教。

一步步開發自己的部落格 .NET版系列:http://www.cnblogs.com/zhaopei/tag/Hi-Blogs/

本文連結:http://www.cnblogs.com/zhaopei/p/4783986.html

  • 學習本是一個不斷抄襲、模仿、練習、創新的過程。
  • 雖然,園中已有本人無法超越的同主題博文,為什麼還是要寫。
  • 對于自己,博文隻是總結。在總結的過程發現問題,解決問題。
  • 對于他人,在此過程如果還能附帶幫助他人,那就再好不過了。
  • 由于部落客能力有限,文中可能存在描述不正确,歡迎指正、補充!
  • 感謝您的閱讀。如果文章對您有用,那麼請輕輕點個贊,以資鼓勵。
  • 工控物聯Q群:995475200

繼續閱讀