Lucene.net站內搜索—六、站內搜索第二版

目錄javascript

Lucene.net站內搜索—一、SEO優化
Lucene.net站內搜索—二、Lucene.Net簡介和分詞
Lucene.net站內搜索—三、最簡單搜索引擎代碼
Lucene.net站內搜索—四、搜索引擎初版技術儲備(簡單介紹Log4Net、生產者消費者模式)
Lucene.net站內搜索—五、搜索引擎初版實現
Lucene.net站內搜索—六、站內搜索第二版
css

第二版功能需求

  • 自動完成
  • 熱門詞彙(SEO)
  • 顯示分詞、執行耗時
  • 分頁
  • 頁面美化

咱們先假設用一張表來存儲用戶全部的關鍵字搜索和次數,以下:html

關鍵字名稱java

搜索次數jquery

新四大名捕面試

3ajax

新圓月彎刀數據庫

4json

北京愛情故事數組

6

這樣實現的缺點:一、沒法實現搜索「最近7天的熱詞」二、性能差,由於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

一、Like不必定會全表掃描。「%a%」會,而"a%"則不會。

二、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(在多個索引上並行搜索,速度更快),作更大的搜索引擎會用到。
(*)能夠對檢索過程過濾,能夠實現評分大於0.8的才顯示搜索結果,在搜索出的數據太多的狀況下調整。搜索排序也是默認根據評分。
(*)除了PhraseQuery,還有BooleanQuery(檢索包含「網絡」或者「志願者」;搜索標題或者正文中包含「搞笑電影」的資源)、FuzzyQuery(糾錯匹配,用戶輸入「Chjna」時候也能匹配「China」,須要提供額外的糾錯數據)、WildcardQuery (通配符檢索,包含「搞笑*電影」)等  #mailContentContainer .txt {height:auto;}
相關文章
相關標籤/搜索