目录javascript
Lucene.net站内搜索—一、SEO优化
Lucene.net站内搜索—二、Lucene.Net简介和分词
Lucene.net站内搜索—三、最简单搜索引擎代码
Lucene.net站内搜索—四、搜索引擎初版技术储备(简单介绍Log4Net、生产者消费者模式)
Lucene.net站内搜索—五、搜索引擎初版实现
Lucene.net站内搜索—六、站内搜索第二版css
咱们先假设用一张表来存储用户全部的关键字搜索和次数,以下: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是一个定时任务框架,能够实现异常灵活的定时任务,开发人员只要编写少许的代码就能够实现“每隔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无刷新分页。
这里我只作简单介绍,有兴趣的朋友能够本身去研究下。
(*) IndexSearcher是Searcher类的一个子类,Searcher类还有其余子类,MultiSearcher(在多个索引上搜索),ParallelMultiSearcher(在多个索引上并行搜索,速度更快),作更大的搜索引擎会用到。