目錄
Lucene.net站內搜索—1、SEO優化
Lucene.net站內搜索—2、Lucene.Net簡介和分詞
Lucene.net站內搜索—3、最簡單搜索引擎代碼
Lucene.net站內搜索—4、搜索引擎第一版技術儲備(簡單介紹Log4Net、生產者消費者模式)
Lucene.net站內搜索—5、搜索引擎第一版實現
Lucene.net站內搜索—6、站內搜索第二版
第二版功能需求
- 自動完成
- 熱門詞匯(SEO)
- 顯示分詞、執行耗時
- 分頁
- 頁面美化
我們先假設用一張表來存儲用戶所有的關鍵字搜索和次數,如下:
關鍵字名稱 |
搜索次數 |
新四大名捕 |
3 |
新圓月彎刀 |
4 |
北京愛情故事 |
6 |
這樣實現的缺點:1、無法實現搜索“最近7天的熱詞”2、性能差,因為update qCount=qCount+1 where Keyword=“新四大名捕”需要鎖定行。
搜索記錄表用Guid。自動增長(標識列)是需要依賴於“上一次的值”,所以需要排隊,性能差;而Guid的生成則是獨立的,不需要依賴,所以性能好。
select top 10 Keyword,count(*) from T_SearchRecords where Keyword like '新四大名捕%' group by Keyword order by Count(*) desc
1、Like不一定會全表掃描。“%a%”會,而"a%"則不會。
2、group by肯定非常消耗資源。
因為對於每次搜索都要:group by、order by、where like。所有的搜索的group by、order by都是一樣的,沒必要重復,所以應該吧“group by、order by”結果緩存起來。
因此進行數據的匯總結果插入:T_SearchRecordsSum(Keywords,SearchCount)表。每天匯總一次,這樣會有數據不及時的情況,但是並不是實時性非常強的,因此沒關系,大不了提高匯總的頻率。
Keywords SearchCount
新四大名捕 5
新圓月彎刀 3
delete from T_SearchRecordsSum; insert into T_SearchRecordsSum(Keywords,SearchCount) select Keyword,count(*) from T_SearchRecords group by Keyword order by Count(*) desc;
最熱搜索
兩張表,一張明細、一張匯總,定時把明細表的數據插入匯總表,查詢的時候到匯總表查詢。
由於明細表的主鍵不需要連續,而且用自動增長字段會排隊、加鎖從而降低效率,因此主鍵用Guid。(為啥文章用自動增長?url短、好看。)
insert into T_KeyWordsRank(Id,KeyWords,SearchTimes) select newid(), KeyWords,Count(*) from T_SearchDetails where DateDiff(day,SearchDateTime,GetDate())<=7 group by KeyWords
Group by效率低,寫SQLServer的是牛人,但不是神人
Quartz.Net
Quartz.Net是一個定時任務框架,可以實現異常靈活的定時任務,開發人員只要編寫少量的代碼就可以實現“每隔1小時執行”、“每天22點執行”、“每月18日的下午執行8次”等各種定時任務。
Quartz.Net中的概念:計划者(IScheduler)、工作(IJob)、觸發器(Trigger)。給計划者一個工作,讓他在Trigger(什么條件下做這件事)觸發的條件下執行這個工作
將要定時執行的任務的代碼寫到實現IJob接口的Execute方法中即可,時間到來的時候Execute方法會被調用。
CrondTrigger是通過Crond表達式設置的觸發器,還有 SimpleTrigger等簡單的觸發器。可以通過TriggerUtils的MakeDailyTrigger、MakeHourlyTrigger等方法簡化調用。調用代碼參考備注。
實現:用Quartz.Net完成定時搜索數據匯總。
第一個用戶訪問我們的WebApplication的時候,Application_Start才運行。
//0 15 10 ? * *" :Fire at 10:15am every day CronTrigger trigger = new CronTrigger("trigger1", "group1", "job1", "group1"); trigger.CronExpressionString = “0 15 10 ? * *”; //每隔一段時間執行任務 IScheduler sched; ISchedulerFactory sf = new StdSchedulerFactory(); sched = sf.GetScheduler(); JobDetail job = new JobDetail("job1", "group1", typeof(IndexJob));//IndexJob為實現了IJob接口的類 DateTime ts = TriggerUtils.GetNextGivenSecondDate(null, 5);//5秒后開始第一次運行 TimeSpan interval = TimeSpan.FromHours(1);//每隔1小時執行一次 Trigger trigger = new SimpleTrigger("trigger1", "group1", "job1", "group1", ts, null, SimpleTrigger.RepeatIndefinitely, interval);//每若干小時運行一次,小時間隔由appsettings中的IndexIntervalHour參數指定 sched.AddJob(job, true); sched.ScheduleJob(trigger); sched.Start();
要關閉任務定時則需要sched.Shutdown(true)
搜索記錄
搜索建議、最新熱門搜索都是基於已有的用戶搜索記錄。SEO的歪門邪道:刷百度搜相關詞匯(SEO最終目的還是讓用戶找到我們的網站)。定期清除舊的歷史數據,防止數據庫太大
每次有用戶搜索都把用戶的搜索行為記錄下來,供熱門搜索和搜索建議用。三個字段:搜索時間、搜索詞(一句話)、訪問者IP地址。因為自動增長字段(標識列)有加鎖的機制,所以慢,這里呢的Id也不會在邏輯中有,所以用Guid(不會加鎖)
使用三層,增加插入記錄的方法,在搜索的時候插入記錄,IP地址:Request.UserHostAddress。
todo:為了避免groupby耗時,每小時做一次group by
自動完成
關於自動搜索功能這里我使用jquery ui 來實現,先下載AutoComplete.rar下載路徑:http://files.cnblogs.com/files/jiekzou/AutoComplete.rar
當然,你也可以在google搜索“JQuery AutoComplete”,找到了JQueryUI庫中的AutoComplete組件。http://jqueryui.com/demos/autocomplete/
效果圖如下:
新建AutoComplete.aspx
要求服務器返回搜索建議詞匯的時候將詞匯以字符串數組的形式(JSon格式)返回給瀏覽器。
不要忘了引入jquery、jqueryui的js和css,注意順序。
autocomplete的source屬性指定自動完成數據的數據來源
生命周期的問題:在用戶敲入文字的時候,Autocomplete組件向ashx頁面發出ajax請求,並且將ashx返回的json格式的數組顯示出來。(*)defer請求
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AutoComplete.aspx.cs" Inherits="BookShop.Web.AutoComplete" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <link href="/Css/themes/ui-lightness/jquery-ui-1.8.2.custom.css" rel="stylesheet" type="text/css" /> <script src="/js/jquery-1.4.2.js" type="text/javascript"></script> <script src="/js/jquery-ui-1.8.2.custom.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { $("#<%=txtSearch.ClientID%>").focus(function () { if ($(this).val() == "請輸入搜索內容") { $(this).css("color", "black").val(""); } }).blur(function () { //光標離開 if ($(this).val() == "") { $(this).css("color", "Gray").val("請輸入搜索內容"); } }); $("#<%=txtSearch.ClientID%>").autocomplete({ source: "/ashx/AutoComplete.ashx", minLength: 1 }); }); </script> </head> <body> <form id="form1" runat="server"> <div> <asp:TextBox ID="txtSearch" runat="server" Width="432px" style="color:grey">請輸入搜索內容</asp:TextBox> <asp:Button ID="btnSearch" runat="server" Text="Search" /> </div> </form> </body> </html>
新建一般處理程序:AutoComplete.ashx
public class AutoComplete : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; string term = context.Request.QueryString["term"]; //BLL.BookManager bll = new BookShop.BLL.BookManager(); List<Book> bookList = new List<Book>();//bll.GetBooks(term); bookList.Add(new Book {Id=1,ISBN="01",PublishDate=DateTime.Now,Title="bad",UnitPrice=10.00m }); bookList.Add(new Book { Id = 2, ISBN = "02", PublishDate = DateTime.Now, Title = "Anple", UnitPrice = 10.00m }); bookList.Add(new Book { Id = 3, ISBN = "03", PublishDate = DateTime.Now, Title = "Acccd", UnitPrice = 10.00m }); bookList.Add(new Book { Id = 4, ISBN = "04", PublishDate = DateTime.Now, Title = "bcccd", UnitPrice = 10.00m }); List<string> list = new List<string>(); for (int i = 0; i < bookList.Count; i++) { if (bookList[i].Title.ToLower().LastIndexOf(term.ToLower())==0) { list.Add(bookList[i].Title); } } //序列化對象 System.Web.Script.Serialization.JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer(); context.Response.Write (js.Serialize(list.ToArray())); } public bool IsReusable { get { return false; } } }
熱門詞匯
在搜索框下方顯示搜索次數最多的語句,語句添加超鏈接,用戶可以點擊語句的超鏈接快捷的開始搜索。用ObjectDataSource和Repeater控件。
在搜索框下方顯示熱門詞匯有利於SEO,方便著名的搜索引擎收錄網站的搜索結果頁面,因為搜索引擎只認超鏈接。很多站內搜索都有熱門詞匯就是這么回事。
熱門詞匯是所有訪問者每次訪問頁面的時候都要顯示的,所以需要緩存。這個是緩存的一個很好的例子,面試的時候問到緩存的問題舉這個例子就很好。
顯示數據庫中所有搜索次數最多的語句,好嗎?不好,容易形成馬太效應。只取一周之內的最熱門。
在經常需要進行檢索的字段上添加索引,可以提高檢索速度。
<div class="rp_5equalcol"><asp:HyperLink Text='<%# Eval("KeyWord")%>' NavigateUrl='<%#EvalSearchURL(Eval("KeyWord").ToString()) %>' runat="server"></asp:HyperLink></div>
private string GetPageAbsolutePath() { string pageurl = this.AppRelativeVirtualPath; return this.ResolveUrl(pageurl); } public string EvalSearchURL(string kw) { string pageurl = GetPageAbsolutePath(); return string.Format("{0}?kw={1}", pageurl,HttpUtility.UrlEncode(kw)); }
搜索結果分頁
開發站內搜索的分頁功能。
能夠SEO的無刷新分頁。
這里你可以使用現有的第三方分頁控件,也可以自己寫一個或自己改造一個,注意使用ajax無刷新分頁。
Lucene.net高級
這里我只做簡單介紹,有興趣的朋友可以自己去研究下。
(*) IndexSearcher是Searcher類的一個子類,Searcher類還有其他子類,MultiSearcher(在多個索引上搜索),ParallelMultiSearcher(在多個索引上並行搜索,速度更快),做更大的搜索引擎會用到。