还有诸如搜索结果分页,我要总计首要词找出的频率高的词

10.五.二 火热搜索

十.5.二.壹 体现热点搜索

骨子里正是从表SearchTotals中服从搜索次数进行降序排列,然后抽出数条记下而已。

LastSearch调控器中的Index方法中增添如下代码:

var keyWords = db.SearchTotal.OrderByDescending(a => a.SearchCounts).Select(x => x.KeyWords).Skip(0).Take(6).ToList();
            ViewBag.KeyWords = keyWords;

View视图中

<div id="divKeyWords">热门搜索:@if (ViewBag.KeyWords != null) {
             foreach (string v in ViewBag.KeyWords) { 
              <a href="#">@v</a>
             }
         }</div>

接下去,笔者想要落成如下图十-二一所示的功能:

图片 1 

图10-21

当小编点击三个热词的时候,自动加载到文本框,并点击“搜索”开关。

在View中加多代码:

<script type="text/javascript">
    $(function () {
        $("#divKeyWords a").click(function () {
            $("#txtSearch").val($(this).html());
            $("#btnSearch").click();
        });
});
</script>

10.五.壹 热词总括

思路:

壹、 
首先,大家脑公里要强烈一点:找出关键字的总计,实时性是不高的。也便是说我们能够定时的去进行计算。

2、  客户的每叁遍寻觅记录,大家都供给存起来,那样才具够计算获得。

从第三点,大家脑海中就会议及展览现一张汇总总结表,从第二点中,大家会想到利用一张搜索记录明细表。那方案就很明知道,只供给定时的从明细表中Group
by查询,然后把询问结构放到汇总表中。怎么放到汇总表中?是直接Update更新吗?其实大家得以有越来越高速的点子,那正是对聚焦表先进行truncate,然后再开展insert操作。

表拾-1 寻找汇总总括表SearchTotals

字段名称

字段类型

说明

Id

char(36)

主键,采用Guid方式存储

KeyWords

nvarchar(50)

搜索关键字

SearchCounts

int

搜索次数

表10-二 找出明细表SearchDetails

字段名称

字段类型

说明

Id

char(36)

主键,采用Guid方式存储

KeyWords

nvarchar(50)

搜索关键字

SearchDateTime

datetime

搜索时间

操作步骤:

(一)在Models文件夹中,新建多少个类SearchTotal、SearchDetail。

SearchTotal.cs代码:

using System;
using System.ComponentModel.DataAnnotations;

namespace SearchDemo.Models
{
    public class SearchTotal
    {
        public Guid Id { get; set; }
        [StringLength(50)]
        public string KeyWords { get; set; }
        public int SearchCounts { get; set; }
    }
}

SearchDetail.cs代码:

using System;
using System.ComponentModel.DataAnnotations;

namespace SearchDemo.Models
{
    public class SearchDetail
    {
        public Guid Id { get; set; }
        [StringLength(50)]
        public string KeyWords { get; set; }
        public Nullable<DateTime> SearchDateTime { get; set; }
    }
}

(二)修改Search德姆oContext类,新添了品质SearchTotal、SearchDetail。

using System.Data.Entity;

namespace SearchDemo.Models
{
    public class SearchDemoContext : DbContext
    {
        public SearchDemoContext() : base("name=SearchDemoContext") { }
        public DbSet<Article> Article { get; set; }
        //下面两个属性是新增加的
        public DbSet<SearchTotal> SearchTotal { get; set; }
        public DbSet<SearchDetail> SearchDetail { get; set; }
    }
}

3)更新数据库

出于修改了EF上下文,新扩展了几个模型类,所以须求开始展览搬迁更新数据库操作。

将应用程序重新编写翻译,然后选用工具->库程序包管理器->程序包管控台。

开发调整台,输入enable-migrations -force
,然后回车。回车后会在类型类别能源管理器中会出现Migrations文件夹,打开Configuration.cs
文件,将AutomaticMigrationsEnabled 值改为 true,然后在调控巴尔的摩输入
update-database
运营。操作完结之后,会在数据库SearchDemo中多新建两张表SearchTotals、SearchDetails,而原来的Articles表保持不改变。如图十-20所示。

 图片 2

图10-20

(四)保存寻觅记录

用户在每便搜寻的时候,要把寻觅记录存入SearchDetails表中。为了便利,那里本人是在用户每一趟点击寻觅之后就当下往SearchDetails表中插入记录了,也正是同步操作,而实际,假若为了进步查找的功能,我们能够使用异步操作,即把找寻记录的数目先写入redis队列中,后台再开辟二个线程来监听redis队列,然后把队列中的寻找记录数据写入到数码表中。因为在每回点击寻找的时候,大家把记录往redis写和把记录第三手往关系型数据库中写的频率是离开相当的大的。

 //先将搜索的词插入到明细表。
            SearchDetail _SearchDetail = new SearchDetail { Id = Guid.NewGuid(), KeyWords = kw, SearchDateTime = DateTime.Now };
            db.SearchDetail.Add(_SearchDetail);
            int r = db.SaveChanges();

(伍)按期更新SearchTotals表记录

见到那种定期职务操作,那里可以利用Quartz.Net框架,为了便于,小编把Quartz.Net的Job寄宿在调控台程序中,而其实职业中,作者则更赞成于将其寄宿在Windows服务中。要是有必要,能够把那几个定时更新SearchTotals表记录的顺序布置到独门的服务器,那样能够缓慢解决Web服务器的下压力。

  1. 新建调节台程序QuartzNet,增多Quartz.dll和Common.Logging.dll的先后集引用,那里运用Database
    First的章程,增多ADO.NET实体数据模型,把表SearchTotals、SearchDetails加多进来。

贰.加多KeyWordsTotalService.cs类,里面封装多个主意,清空SearchTotals表,然后把SearchDetails表的分组查询结构插入到SearchTotals表,那里本身只计算近30天内的探索明细。

namespace QuartzNet
{
    public class KeyWordsTotalService
    {
        private SearchDemoEntities db = new SearchDemoEntities();
        /// <summary>
        /// 将统计的明细表的数据插入。
        /// </summary>
        /// <returns></returns>
        public bool InsertKeyWordsRank()
        {
            string sql = "insert into SearchTotals(Id,KeyWords,SearchCounts) select newid(),KeyWords,count(*)  from SearchDetails where DateDiff(day,SearchDetails.SearchDateTime,
getdate())<=30 group by SearchDetails.KeyWords";
            return this.db.Database.ExecuteSqlCommand(sql) > 0;
        }
        /// <summary>
        /// 删除汇总中的数据。
        /// </summary>
        /// <returns></returns>
        public bool DeleteAllKeyWordsRank()
        {
            string sql = "truncate table SearchTotals";
            return this.db.Database.ExecuteSqlCommand(sql) > 0;
        }
    }
}
  1. 添加TotalJob.cs类,继承Ijob接口,并实现Execute方法。

    namespace QuartzNet
    {

     public class TotalJob : IJob
     {
         /// <summary>
         /// 将明细表中的数据插入到汇总表中。
         /// </summary>
         /// <param name="context"></param>
         public void Execute(JobExecutionContext context)
         {
             KeyWordsTotalService bll = new KeyWordsTotalService();
             bll.DeleteAllKeyWordsRank();
             bll.InsertKeyWordsRank();
         }
     }
    

    }

4.修改Program.cs类

using Quartz;
using Quartz.Impl;
using System;

namespace QuartzNet
{
    class Program
    {
        static void Main(string[] args)
        {
            IScheduler sched;
            ISchedulerFactory sf = new StdSchedulerFactory();
            sched = sf.GetScheduler();
            JobDetail job = new JobDetail("job1", "group1", typeof(TotalJob));//IndexJob为实现了IJob接口的类
            DateTime ts = TriggerUtils.GetNextGivenSecondDate(null, 5);//5秒后开始第一次运行
            TimeSpan interval = TimeSpan.FromSeconds(50);//每隔50秒执行一次
            Trigger trigger = new SimpleTrigger("trigger1", "group1", "job1", "group1", ts, null,
                                                    SimpleTrigger.RepeatIndefinitely, interval);//每若干时间运行一次,时间间隔可以放到配置文件中指定

            sched.AddJob(job, true);
            sched.ScheduleJob(trigger);
            sched.Start();
            Console.ReadKey();
        }
    }
}

此地自个儿是间接把Job和安顿都平昔写到代码中了,理由依旧因为便宜。而实际专门的学问中,大家应该把这几个音信尽量写到配置文件中,那样前面退换起来方便,不需要修改代码,只须求修改配置文件。

为了赶紧看到效果,作者这边是每隔50秒就进展了一遍总计操作,而在实际上利用中,大家的时刻间隔大概是多少个时辰以致一天,因为像这么的大数目总括,对实时性的须要不高,大家能够尽量收缩对数据库的IO读写次数。

保持运维调控台程序QuartzNet,然后我们去开始展览搜寻操作,那样后台就定时的变迁了追寻总计记录。

10.5.4 与查询、或查询、分页

后面咱们在追寻的时候,其实选择的都以与查询,也正是说,作者输入“诸葛武侯周郎”,则只会招来出,既存在诸葛孔明,又存在周郎的记录。那么有时候,大家是想询问存在诸葛卧龙可能周郎的记录的,那也等于所谓的或询问。

本身在分界面添加三个复选框“或询问”,来让用户决定运用何种方法举行询问。

关于分页,那里运用MvcPager,关于MvcPager的运用方式请参见四.6.3。

View完整代码预览:

图片 3图片 4

@{
    ViewBag.Title = "Index";
}
@model PagedList<SearchDemo.Models.SearchResult>
@using Webdiyer.WebControls.Mvc;
@using SearchDemo.Models;
<style type="text/css">
.search-text2{ display:block; width:528px; height:26px; line-height:26px; float:left; margin:3px 5px; border:1px solid gray; outline:none; font-family:'Microsoft Yahei'; font-size:14px;}
.search-btn2{width:102px; height:32px; line-height:32px; cursor:pointer; border:0px; background-color:#d6000f;font-family:'Microsoft Yahei'; font-size:16px;color:#f3f3f3;}
.search-list-con{width:640px; background-color:#fff; overflow:hidden; margin-top:0px; padding-bottom:15px; padding-top:5px;}
.search-list{width:600px; overflow:hidden; margin:15px 20px 0px 20px;}
.search-list dt{font-family:'Microsoft Yahei'; font-size:16px; line-height:20px; margin-bottom:7px; font-weight:normal;}
.search-list dt a{color:#2981a9;}
.search-list dt a em{ font-style:normal; color:#cc0000;}
#divKeyWords {text-align:left;width:520px;padding-left:4px;}
#divKeyWords a {text-decoration:none;}
#divKeyWords a:hover {color:red;}
</style>
<link href="~/lib/Autocomplete/css/ui-lightness/jquery-ui-1.8.17.custom.css" rel="stylesheet" />
@using(@Html.BeginForm(null, null, FormMethod.Get))
{
    @Html.Hidden("hidfIsOr")
    <div>@Html.TextBox("txtSearch", null, new { @class="search-text2"})<input type="submit" value="搜索" name="btnSearch" id="btnSearch"  class="search-btn2"/><input type="checkbox" id="isOr" value="false"/>或查询</div>
    <div id="divKeyWords">热门搜索:@if (ViewBag.KeyWords != null) {
             foreach (string v in ViewBag.KeyWords) { 
              <a href="#">@v</a>
             }
         }</div>
    <div class="search-list-con">
        <dl class="search-list">
            @if (Model != null&& Model.Count > 0)
            {
                foreach (var viewModel in Model)
                {
                <dt><a href="@viewModel.Url" target="_blank">@MvcHtmlString.Create(viewModel.Title)</a>@viewModel.CreateTime</dt>
                <dd>@MvcHtmlString.Create(viewModel.Msg)</dd>
                }
            } 
              @Html.Pager(Model, new PagerOptions
 {
     PageIndexParameterName = "id",
     ShowPageIndexBox = true,
     FirstPageText = "首页",
     PrevPageText = "上一页",
     NextPageText = "下一页",
     LastPageText = "末页",
     PageIndexBoxType = PageIndexBoxType.TextBox,
     PageIndexBoxWrapperFormatString = "请输入页数{0}",
     GoButtonText = "转到"
 })
     <br />
     >>分页 共有 @(Model==null? 0: Model.TotalItemCount) 篇文章 @(Model==null?0:Model.CurrentPageIndex)/@(Model==null?0:Model.TotalPageCount)
        </dl>
    </div>
    <div>@ViewData["ShowInfo"]</div>
}
<script type="text/javascript">
    $(function () {
        $("#divKeyWords a").click(function () {
            $("#txtSearch").val($(this).html());
            $("#btnSearch").click();
        });
        getKeyWordsList("txtSearch");
        $("#isOr").click(function () {
            if ($(this).attr("checked") == "checked") {
                $("#hidfIsOr").val(true);
            }
            else {
                $("#hidfIsOr").val(false);
            }
        });
        if ($("#hidfIsOr").val() == "true") {
            $("input[type='checkbox']").prop("checked", true);
        }
    });
    //自动加载搜索列表
    function getKeyWordsList(txt) {
        if (txt == undefined || txt == "")
            return;
        $("#" + txt).autocomplete({
            source: "/LastSearch/GetKeyWordsList",
            minLength: 1
        });
    }
</script>
<script src="~/lib/Autocomplete/js/jquery-ui-1.8.17.custom.min.js"></script>

View Code

接下来,各位看官请再看LastSearch调整器中的方法:

图片 5图片 6

 public class LastSearchController : Controller
    {
        //
        // GET: /LastSearch/

        string indexPath = System.Configuration.ConfigurationManager.AppSettings["lucenedir"];
        private SearchDemoContext db = new SearchDemoContext();

              public ActionResult Index(string txtSearch, bool? hidfIsOr, int id = 1)
        {
            PagedList<SearchResult> list = null;
            if (!string.IsNullOrEmpty(txtSearch))//如果点击的是查询按钮
            {
                //list = Search(txtSearch);
                list = (hidfIsOr == null || hidfIsOr.Value == false) ? OrSearch(txtSearch, id) : AndSearch(txtSearch, id);
            }
            var keyWords = db.SearchTotal.OrderByDescending(a => a.SearchCounts).Select(x => x.KeyWords).Skip(0).Take(6).ToList();
            ViewBag.KeyWords = keyWords;
            return View(list);
        }
        //与查询
        PagedList<SearchResult> AndSearch(String kw, int pageNo, int pageLen = 4)
        {
            FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());
            IndexReader reader = IndexReader.Open(directory, true);
            IndexSearcher searcher = new IndexSearcher(reader);
            PhraseQuery query = new PhraseQuery();//查询条件
            PhraseQuery titleQuery = new PhraseQuery();//标题查询条件
            List<string> lstkw = LuceneHelper.PanGuSplitWord(kw);//对用户输入的搜索条件进行拆分。

            foreach (string word in lstkw)
            {
                query.Add(new Term("Content", word));//contains("Content",word)
                titleQuery.Add(new Term("Title", word));
            }
            query.SetSlop(100);//两个词的距离大于100(经验值)就不放入搜索结果,因为距离太远相关度就不高了

            BooleanQuery bq = new BooleanQuery();
            //Occur.Should 表示 Or , Must 表示 and 运算
            bq.Add(query, BooleanClause.Occur.SHOULD);
            bq.Add(titleQuery, BooleanClause.Occur.SHOULD);

            TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);//盛放查询结果的容器
            searcher.Search(bq, null, collector);//使用query这个查询条件进行搜索,搜索结果放入collector

            int recCount=collector.GetTotalHits();//总的结果条数
            ScoreDoc[] docs = collector.TopDocs((pageNo - 1) * pageLen, pageNo*pageLen).scoreDocs;//从查询结果中取出第m条到第n条的数据

            List<SearchResult> list = new List<SearchResult>();
            string msg = string.Empty;
            string title = string.Empty;

            for (int i = 0; i < docs.Length; i++)//遍历查询结果
            {
                int docId = docs[i].doc;//拿到文档的id,因为Document可能非常占内存(思考DataSet和DataReader的区别)
                //所以查询结果中只有id,具体内容需要二次查询
                Document doc = searcher.Doc(docId);//根据id查询内容。放进去的是Document,查出来的还是Document
                SearchResult result = new SearchResult();
                result.Id = Convert.ToInt32(doc.Get("Id"));
                msg = doc.Get("Content");//只有 Field.Store.YES的字段才能用Get查出来
                result.Msg = LuceneHelper.CreateHightLight(kw, msg);//将搜索的关键字高亮显示。
                title = doc.Get("Title");
                foreach (string word in lstkw)
                {
                    title=title.Replace(word,""+word+"");
                }
                //result.Title=LuceneHelper.CreateHightLight(kw, title);
                result.Title = title;
                result.CreateTime = Convert.ToDateTime(doc.Get("CreateTime"));
                result.Url = "/Article/Details?Id=" + result.Id + "&kw=" + kw;
                list.Add(result);
            }
            //先将搜索的词插入到明细表。
            SearchDetail _SearchDetail = new SearchDetail { Id = Guid.NewGuid(), KeyWords = kw, SearchDateTime = DateTime.Now };
            db.SearchDetail.Add(_SearchDetail);
            int r = db.SaveChanges();

            PagedList<SearchResult> lst = new PagedList<SearchResult>(list, pageNo, pageLen, recCount);
            lst.TotalItemCount = recCount;
            lst.CurrentPageIndex = pageNo;

            return lst;
        }
        //或查询
        PagedList<SearchResult> OrSearch(String kw, int pageNo, int pageLen = 4)
        {
            FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());
            IndexReader reader = IndexReader.Open(directory, true);
            IndexSearcher searcher = new IndexSearcher(reader);
            List<PhraseQuery> lstQuery = new List<PhraseQuery>();
            List<string> lstkw = LuceneHelper.PanGuSplitWord(kw);//对用户输入的搜索条件进行拆分。

            foreach (string word in lstkw)
            {
                PhraseQuery query = new PhraseQuery();//查询条件
                query.SetSlop(100);//两个词的距离大于100(经验值)就不放入搜索结果,因为距离太远相关度就不高了
                query.Add(new Term("Content", word));//contains("Content",word)

                PhraseQuery titleQuery = new PhraseQuery();//查询条件
                titleQuery.Add(new Term("Title", word));

                lstQuery.Add(query);
                lstQuery.Add(titleQuery);
            }

            BooleanQuery bq = new BooleanQuery();
            foreach (var v in lstQuery)
            {
                //Occur.Should 表示 Or , Must 表示 and 运算
                bq.Add(v, BooleanClause.Occur.SHOULD);
            }
            TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);//盛放查询结果的容器
            searcher.Search(bq, null, collector);//使用query这个查询条件进行搜索,搜索结果放入collector

            int recCount = collector.GetTotalHits();//总的结果条数
            ScoreDoc[] docs = collector.TopDocs((pageNo - 1) * pageLen, pageNo * pageLen).scoreDocs;//从查询结果中取出第m条到第n条的数据

            List<SearchResult> list = new List<SearchResult>();
            string msg = string.Empty;
            string title = string.Empty;

            for (int i = 0; i < docs.Length; i++)//遍历查询结果
            {
                int docId = docs[i].doc;//拿到文档的id,因为Document可能非常占内存(思考DataSet和DataReader的区别)
                //所以查询结果中只有id,具体内容需要二次查询
                Document doc = searcher.Doc(docId);//根据id查询内容。放进去的是Document,查出来的还是Document
                SearchResult result = new SearchResult();
                result.Id = Convert.ToInt32(doc.Get("Id"));
                msg = doc.Get("Content");//只有 Field.Store.YES的字段才能用Get查出来
                result.Msg = LuceneHelper.CreateHightLight(kw, msg);//将搜索的关键字高亮显示。
                title = doc.Get("Title");
                foreach (string word in lstkw)
                {
                    title = title.Replace(word, "" + word + "");
                }
                //result.Title=LuceneHelper.CreateHightLight(kw, title);
                result.Title = title;
                result.CreateTime = Convert.ToDateTime(doc.Get("CreateTime"));
                result.Url = "/Article/Details?Id=" + result.Id + "&kw=" + kw;
                list.Add(result);
            }
            //先将搜索的词插入到明细表。
            SearchDetail _SearchDetail = new SearchDetail { Id = Guid.NewGuid(), KeyWords = kw, SearchDateTime = DateTime.Now };
            db.SearchDetail.Add(_SearchDetail);
            int r = db.SaveChanges();

            PagedList<SearchResult> lst = new PagedList<SearchResult>(list, pageNo, pageLen, recCount);
            lst.TotalItemCount = recCount;
            lst.CurrentPageIndex = pageNo;

            return lst;
        }

        /// <summary>
        /// 获取客户列表 模糊查询
        /// </summary>
        /// <param name="term"></param>
        /// <returns></returns>
        public string GetKeyWordsList(string term)
        {
            if (string.IsNullOrWhiteSpace(term))
                return null;

            var list = new KeyWordsTotalService().GetSearchMsg(term);
            //序列化对象
            //尽量不要用JavaScriptSerializer,为什么?性能差,完全可用Newtonsoft.Json来代替
            //System.Web.Script.Serialization.JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer();
            //return js.Serialize(list.ToArray());
            return JsonConvert.SerializeObject(list.ToArray());
        }

View Code

时于今日,站内寻找的基本作用均已做到。

10.5.贰.壹 体现火热搜索

实际上便是从表SearchTotals中根据搜索次数举行降序排列,然后收取数条记下而已。

LastSearch调整器中的Index方法中增多如下代码:

var keyWords = db.SearchTotal.OrderByDescending(a => a.SearchCounts).Select(x => x.KeyWords).Skip(0).Take(6).ToList();
            ViewBag.KeyWords = keyWords;

View视图中

<div id="divKeyWords">热门搜索:@if (ViewBag.KeyWords != null) {
             foreach (string v in ViewBag.KeyWords) { 
              <a href="#">@v</a>
             }
         }</div>

接下去,作者想要落成如下图10-2一所示的成效:

图片 7 

图10-21

当自个儿点击二个热词的时候,自动加载到文本框,并点击“找寻”按键。

在View中加多代码:

<script type="text/javascript">
    $(function () {
        $("#divKeyWords a").click(function () {
            $("#txtSearch").val($(this).html());
            $("#btnSearch").click();
        });
});
</script>

10.五.1 热词总计

思路:

1、 
首先,我们脑英里要肯定一点:搜索关键字的总括,实时性是不高的。也正是说大家得以按期的去开始展览总括。

2、  客户的每二回搜索记录,大家都需求存起来,那样本事够总括获得。

从第二点,大家脑海中就会显示一张汇总总括表,从第二点中,大家会想到利用一张搜索记录明细表。那方案就很明知道,只要求定时的从明细表中Group
by查询,然后把询问结构放到汇总表中。怎么放到汇总表中?是一向Update更新吗?其实大家能够有越来越高效的诀窍,那正是对集中表先进行truncate,然后再实行insert操作。

表拾-一 找出汇总总结表SearchTotals

字段名称

字段类型

说明

Id

char(36)

主键,采用Guid方式存储

KeyWords

nvarchar(50)

搜索关键字

SearchCounts

int

搜索次数

表拾-2 寻觅明细表SearchDetails

字段名称

字段类型

说明

Id

char(36)

主键,采用Guid方式存储

KeyWords

nvarchar(50)

搜索关键字

SearchDateTime

datetime

搜索时间

操作步骤:

(一)在Models文件夹中,新建三个类SearchTotal、SearchDetail。

SearchTotal.cs代码:

using System;
using System.ComponentModel.DataAnnotations;

namespace SearchDemo.Models
{
    public class SearchTotal
    {
        public Guid Id { get; set; }
        [StringLength(50)]
        public string KeyWords { get; set; }
        public int SearchCounts { get; set; }
    }
}

SearchDetail.cs代码:

using System;
using System.ComponentModel.DataAnnotations;

namespace SearchDemo.Models
{
    public class SearchDetail
    {
        public Guid Id { get; set; }
        [StringLength(50)]
        public string KeyWords { get; set; }
        public Nullable<DateTime> SearchDateTime { get; set; }
    }
}

(二)修改Search德姆oContext类,新扩大了质量SearchTotal、SearchDetail。

using System.Data.Entity;

namespace SearchDemo.Models
{
    public class SearchDemoContext : DbContext
    {
        public SearchDemoContext() : base("name=SearchDemoContext") { }
        public DbSet<Article> Article { get; set; }
        //下面两个属性是新增加的
        public DbSet<SearchTotal> SearchTotal { get; set; }
        public DbSet<SearchDetail> SearchDetail { get; set; }
    }
}

叁)更新数据库

是因为修改了EF上下文,新扩张了七个模型类,所以须要开始展览搬迁更新数据库操作。

将应用程序重新编写翻译,然后选用工具->库程序包管理器->程序包管控台。

开垦调节台,输入enable-migrations -force
,然后回车。回车后会在项目项目财富管理器中会出现Migrations文件夹,张开Configuration.cs
文件,将AutomaticMigrationsEnabled 值改为 true,然后在调整哈博罗内输入
update-database
运营。操作完毕未来,会在数据库SearchDemo中多新建两张表SearchTotals、SearchDetails,而原来的Articles表保持不变。如图10-20所示。

 图片 8

图10-20

(四)保存寻觅记录

用户在每一趟搜寻的时候,要把寻找记录存入SearchDetails表中。为了有利于,那里本身是在用户每一回点击搜索之后就及时往SearchDetails表中插入记录了,约等于同步操作,而实质上,若是为了进步查找的效能,大家能够运用异步操作,即把找出记录的数额先写入redis队列中,后台再开垦3个线程来监听redis队列,然后把队列中的找出记录数据写入到数量表中。因为在每便点击搜索的时候,大家把记录往redis写和把记录第三手往关系型数据库中写的频率是距离极大的。

 //先将搜索的词插入到明细表。
            SearchDetail _SearchDetail = new SearchDetail { Id = Guid.NewGuid(), KeyWords = kw, SearchDateTime = DateTime.Now };
            db.SearchDetail.Add(_SearchDetail);
            int r = db.SaveChanges();

(5)定时更新SearchTotals表记录

总的来看那种定期职责操作,那里能够动用Quartz.Net框架,为了便于,我把Quartz.Net的Job寄宿在调节台程序中,而实在工作中,小编则更赞成于将其寄宿在Windows服务中。若是有必不可缺,能够把那些定期更新SearchTotals表记录的程序陈设到独门的服务器,那样能够缓慢消除Web服务器的压力。

  1. 新建调节台程序QuartzNet,增加Quartz.dll和Common.Logging.dll的先后集引用,那里运用Database
    First的点子,增多ADO.NET实体数据模型,把表SearchTotals、SearchDetails加多进来。

二.增添KeyWordsTotalService.cs类,里面封装多少个措施,清空SearchTotals表,然后把SearchDetails表的分组查询结构插入到SearchTotals表,那里自身只总括近30天内的检索明细。

namespace QuartzNet
{
    public class KeyWordsTotalService
    {
        private SearchDemoEntities db = new SearchDemoEntities();
        /// <summary>
        /// 将统计的明细表的数据插入。
        /// </summary>
        /// <returns></returns>
        public bool InsertKeyWordsRank()
        {
            string sql = "insert into SearchTotals(Id,KeyWords,SearchCounts) select newid(),KeyWords,count(*)  from SearchDetails where DateDiff(day,SearchDetails.SearchDateTime,
getdate())<=30 group by SearchDetails.KeyWords";
            return this.db.Database.ExecuteSqlCommand(sql) > 0;
        }
        /// <summary>
        /// 删除汇总中的数据。
        /// </summary>
        /// <returns></returns>
        public bool DeleteAllKeyWordsRank()
        {
            string sql = "truncate table SearchTotals";
            return this.db.Database.ExecuteSqlCommand(sql) > 0;
        }
    }
}
  1. 添加TotalJob.cs类,继承Ijob接口,并实现Execute方法。

    namespace QuartzNet
    {

     public class TotalJob : IJob
     {
         /// <summary>
         /// 将明细表中的数据插入到汇总表中。
         /// </summary>
         /// <param name="context"></param>
         public void Execute(JobExecutionContext context)
         {
             KeyWordsTotalService bll = new KeyWordsTotalService();
             bll.DeleteAllKeyWordsRank();
             bll.InsertKeyWordsRank();
         }
     }
    

    }

4.修改Program.cs类

using Quartz;
using Quartz.Impl;
using System;

namespace QuartzNet
{
    class Program
    {
        static void Main(string[] args)
        {
            IScheduler sched;
            ISchedulerFactory sf = new StdSchedulerFactory();
            sched = sf.GetScheduler();
            JobDetail job = new JobDetail("job1", "group1", typeof(TotalJob));//IndexJob为实现了IJob接口的类
            DateTime ts = TriggerUtils.GetNextGivenSecondDate(null, 5);//5秒后开始第一次运行
            TimeSpan interval = TimeSpan.FromSeconds(50);//每隔50秒执行一次
            Trigger trigger = new SimpleTrigger("trigger1", "group1", "job1", "group1", ts, null,
                                                    SimpleTrigger.RepeatIndefinitely, interval);//每若干时间运行一次,时间间隔可以放到配置文件中指定

            sched.AddJob(job, true);
            sched.ScheduleJob(trigger);
            sched.Start();
            Console.ReadKey();
        }
    }
}

那里自个儿是直接把Job和安插都平素写到代码中了,理由依旧因为便宜。而实质上工作中,大家相应把那一个消息尽量写到配置文件中,那样前边改动起来方便,不须要修改代码,只要求修改配置文件。

为了尽快看到效果,小编那边是每隔50秒就张开了三次计算操作,而在骨子里运用中,大家的时辰间隔恐怕是多少个钟头以致壹天,因为像这样的大数额总计,对实时性的渴求不高,大家得以尽量缩小对数据库的IO读写次数。

维持运营调节台程序QuartzNet,然后大家去实行查找操作,那样后台就定时的改造了查找总括记录。

目录:ASP.NET MVC公司级实战目录

像www.verycd.com、天涯论坛、Tmall、京东都有得以达成站内寻觅功用,站内寻找无论在性质和用户体验上都万分精确,本节,通过应用Lucene.Net来落成站内寻找。

演示效果预览如下图十-22~10-24所示。

图片 9

图10-22

 图片 10

图10-23

 图片 11

图10-24

在拾.四节,已经实现了寻觅的首先个版本,可是还有好些个地方需求优化。比方说,作者要总结首要词寻觅的频率高的词,也即热词,以及像百度找出那样,在输加入关贸总协定组织键字后,会活动把搜索相关的热词自动以下拉列表的方式带出去。还有诸如搜索结果分页,查看小表达细等。

10.5.叁 题目和剧情都支持搜索并高亮展现

在10.四中,只辅助在内容中对重大词进行搜寻,而事实上,大家也许既要帮忙在题目中找寻,也要在内容中搜寻。

此间引进了BooleanQuery,大家的询问条件也增加了多少个titleQuery。

探求方法中,如下代码有修改:

 PhraseQuery query = new PhraseQuery();//查询条件
            PhraseQuery titleQuery = new PhraseQuery();//标题查询条件
            List<string> lstkw = LuceneHelper.PanGuSplitWord(kw);//对用户输入的搜索条件进行拆分。

            foreach (string word in lstkw)            {
                query.Add(new Term("Content", word));//contains("Content",word)
                titleQuery.Add(new Term("Title", word));
            }
            query.SetSlop(100);//两个词的距离大于100(经验值)就不放入搜索结果,因为距离太远相关度就不高了

            BooleanQuery bq = new BooleanQuery();
            //Occur.Should 表示 Or , Must 表示 and 运算
            bq.Add(query, BooleanClause.Occur.SHOULD);
            bq.Add(titleQuery, BooleanClause.Occur.SHOULD);

            TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);//盛放查询结果的容器
            searcher.Search(bq, null, collector);//使用query这个查询条件进行搜索,搜索结果放入collector

10.5.4 与查询、或查询、分页

后面我们在检索的时候,其实选取的都是与查询,也正是说,笔者输入“诸葛武侯周公瑾”,则只会招来出,既存在诸葛卧龙,又存在周郎的记录。那么有时候,大家是想询问存在诸葛孔明只怕周公瑾的记录的,那也正是所谓的或询问。

自家在界面加多三个复选框“或询问”,来让用户决定运用何种方法实行询问。

关于分页,那里运用MvcPager,关于MvcPager的行使情势请参见四.6.三。

View完整代码预览:

图片 12图片 13

@{
    ViewBag.Title = "Index";
}
@model PagedList<SearchDemo.Models.SearchResult>
@using Webdiyer.WebControls.Mvc;
@using SearchDemo.Models;
<style type="text/css">
.search-text2{ display:block; width:528px; height:26px; line-height:26px; float:left; margin:3px 5px; border:1px solid gray; outline:none; font-family:'Microsoft Yahei'; font-size:14px;}
.search-btn2{width:102px; height:32px; line-height:32px; cursor:pointer; border:0px; background-color:#d6000f;font-family:'Microsoft Yahei'; font-size:16px;color:#f3f3f3;}
.search-list-con{width:640px; background-color:#fff; overflow:hidden; margin-top:0px; padding-bottom:15px; padding-top:5px;}
.search-list{width:600px; overflow:hidden; margin:15px 20px 0px 20px;}
.search-list dt{font-family:'Microsoft Yahei'; font-size:16px; line-height:20px; margin-bottom:7px; font-weight:normal;}
.search-list dt a{color:#2981a9;}
.search-list dt a em{ font-style:normal; color:#cc0000;}
#divKeyWords {text-align:left;width:520px;padding-left:4px;}
#divKeyWords a {text-decoration:none;}
#divKeyWords a:hover {color:red;}
</style>
<link href="~/lib/Autocomplete/css/ui-lightness/jquery-ui-1.8.17.custom.css" rel="stylesheet" />
@using(@Html.BeginForm(null, null, FormMethod.Get))
{
    @Html.Hidden("hidfIsOr")
    <div>@Html.TextBox("txtSearch", null, new { @class="search-text2"})<input type="submit" value="搜索" name="btnSearch" id="btnSearch"  class="search-btn2"/><input type="checkbox" id="isOr" value="false"/>或查询</div>
    <div id="divKeyWords">热门搜索:@if (ViewBag.KeyWords != null) {
             foreach (string v in ViewBag.KeyWords) { 
              <a href="#">@v</a>
             }
         }</div>
    <div class="search-list-con">
        <dl class="search-list">
            @if (Model != null&& Model.Count > 0)
            {
                foreach (var viewModel in Model)
                {
                <dt><a href="@viewModel.Url" target="_blank">@MvcHtmlString.Create(viewModel.Title)</a>@viewModel.CreateTime</dt>
                <dd>@MvcHtmlString.Create(viewModel.Msg)</dd>
                }
            } 
              @Html.Pager(Model, new PagerOptions
 {
     PageIndexParameterName = "id",
     ShowPageIndexBox = true,
     FirstPageText = "首页",
     PrevPageText = "上一页",
     NextPageText = "下一页",
     LastPageText = "末页",
     PageIndexBoxType = PageIndexBoxType.TextBox,
     PageIndexBoxWrapperFormatString = "请输入页数{0}",
     GoButtonText = "转到"
 })
     <br />
     >>分页 共有 @(Model==null? 0: Model.TotalItemCount) 篇文章 @(Model==null?0:Model.CurrentPageIndex)/@(Model==null?0:Model.TotalPageCount)
        </dl>
    </div>
    <div>@ViewData["ShowInfo"]</div>
}
<script type="text/javascript">
    $(function () {
        $("#divKeyWords a").click(function () {
            $("#txtSearch").val($(this).html());
            $("#btnSearch").click();
        });
        getKeyWordsList("txtSearch");
        $("#isOr").click(function () {
            if ($(this).attr("checked") == "checked") {
                $("#hidfIsOr").val(true);
            }
            else {
                $("#hidfIsOr").val(false);
            }
        });
        if ($("#hidfIsOr").val() == "true") {
            $("input[type='checkbox']").prop("checked", true);
        }
    });
    //自动加载搜索列表
    function getKeyWordsList(txt) {
        if (txt == undefined || txt == "")
            return;
        $("#" + txt).autocomplete({
            source: "/LastSearch/GetKeyWordsList",
            minLength: 1
        });
    }
</script>
<script src="~/lib/Autocomplete/js/jquery-ui-1.8.17.custom.min.js"></script>

View Code

接下来,各位看官请再看LastSearch调整器中的方法:

图片 14图片 15

 public class LastSearchController : Controller
    {
        //
        // GET: /LastSearch/

        string indexPath = System.Configuration.ConfigurationManager.AppSettings["lucenedir"];
        private SearchDemoContext db = new SearchDemoContext();

              public ActionResult Index(string txtSearch, bool? hidfIsOr, int id = 1)
        {
            PagedList<SearchResult> list = null;
            if (!string.IsNullOrEmpty(txtSearch))//如果点击的是查询按钮
            {
                //list = Search(txtSearch);
                list = (hidfIsOr == null || hidfIsOr.Value == false) ? OrSearch(txtSearch, id) : AndSearch(txtSearch, id);
            }
            var keyWords = db.SearchTotal.OrderByDescending(a => a.SearchCounts).Select(x => x.KeyWords).Skip(0).Take(6).ToList();
            ViewBag.KeyWords = keyWords;
            return View(list);
        }
        //与查询
        PagedList<SearchResult> AndSearch(String kw, int pageNo, int pageLen = 4)
        {
            FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());
            IndexReader reader = IndexReader.Open(directory, true);
            IndexSearcher searcher = new IndexSearcher(reader);
            PhraseQuery query = new PhraseQuery();//查询条件
            PhraseQuery titleQuery = new PhraseQuery();//标题查询条件
            List<string> lstkw = LuceneHelper.PanGuSplitWord(kw);//对用户输入的搜索条件进行拆分。

            foreach (string word in lstkw)
            {
                query.Add(new Term("Content", word));//contains("Content",word)
                titleQuery.Add(new Term("Title", word));
            }
            query.SetSlop(100);//两个词的距离大于100(经验值)就不放入搜索结果,因为距离太远相关度就不高了

            BooleanQuery bq = new BooleanQuery();
            //Occur.Should 表示 Or , Must 表示 and 运算
            bq.Add(query, BooleanClause.Occur.SHOULD);
            bq.Add(titleQuery, BooleanClause.Occur.SHOULD);

            TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);//盛放查询结果的容器
            searcher.Search(bq, null, collector);//使用query这个查询条件进行搜索,搜索结果放入collector

            int recCount=collector.GetTotalHits();//总的结果条数
            ScoreDoc[] docs = collector.TopDocs((pageNo - 1) * pageLen, pageNo*pageLen).scoreDocs;//从查询结果中取出第m条到第n条的数据

            List<SearchResult> list = new List<SearchResult>();
            string msg = string.Empty;
            string title = string.Empty;

            for (int i = 0; i < docs.Length; i++)//遍历查询结果
            {
                int docId = docs[i].doc;//拿到文档的id,因为Document可能非常占内存(思考DataSet和DataReader的区别)
                //所以查询结果中只有id,具体内容需要二次查询
                Document doc = searcher.Doc(docId);//根据id查询内容。放进去的是Document,查出来的还是Document
                SearchResult result = new SearchResult();
                result.Id = Convert.ToInt32(doc.Get("Id"));
                msg = doc.Get("Content");//只有 Field.Store.YES的字段才能用Get查出来
                result.Msg = LuceneHelper.CreateHightLight(kw, msg);//将搜索的关键字高亮显示。
                title = doc.Get("Title");
                foreach (string word in lstkw)
                {
                    title=title.Replace(word,""+word+"");
                }
                //result.Title=LuceneHelper.CreateHightLight(kw, title);
                result.Title = title;
                result.CreateTime = Convert.ToDateTime(doc.Get("CreateTime"));
                result.Url = "/Article/Details?Id=" + result.Id + "&kw=" + kw;
                list.Add(result);
            }
            //先将搜索的词插入到明细表。
            SearchDetail _SearchDetail = new SearchDetail { Id = Guid.NewGuid(), KeyWords = kw, SearchDateTime = DateTime.Now };
            db.SearchDetail.Add(_SearchDetail);
            int r = db.SaveChanges();

            PagedList<SearchResult> lst = new PagedList<SearchResult>(list, pageNo, pageLen, recCount);
            lst.TotalItemCount = recCount;
            lst.CurrentPageIndex = pageNo;

            return lst;
        }
        //或查询
        PagedList<SearchResult> OrSearch(String kw, int pageNo, int pageLen = 4)
        {
            FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());
            IndexReader reader = IndexReader.Open(directory, true);
            IndexSearcher searcher = new IndexSearcher(reader);
            List<PhraseQuery> lstQuery = new List<PhraseQuery>();
            List<string> lstkw = LuceneHelper.PanGuSplitWord(kw);//对用户输入的搜索条件进行拆分。

            foreach (string word in lstkw)
            {
                PhraseQuery query = new PhraseQuery();//查询条件
                query.SetSlop(100);//两个词的距离大于100(经验值)就不放入搜索结果,因为距离太远相关度就不高了
                query.Add(new Term("Content", word));//contains("Content",word)

                PhraseQuery titleQuery = new PhraseQuery();//查询条件
                titleQuery.Add(new Term("Title", word));

                lstQuery.Add(query);
                lstQuery.Add(titleQuery);
            }

            BooleanQuery bq = new BooleanQuery();
            foreach (var v in lstQuery)
            {
                //Occur.Should 表示 Or , Must 表示 and 运算
                bq.Add(v, BooleanClause.Occur.SHOULD);
            }
            TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);//盛放查询结果的容器
            searcher.Search(bq, null, collector);//使用query这个查询条件进行搜索,搜索结果放入collector

            int recCount = collector.GetTotalHits();//总的结果条数
            ScoreDoc[] docs = collector.TopDocs((pageNo - 1) * pageLen, pageNo * pageLen).scoreDocs;//从查询结果中取出第m条到第n条的数据

            List<SearchResult> list = new List<SearchResult>();
            string msg = string.Empty;
            string title = string.Empty;

            for (int i = 0; i < docs.Length; i++)//遍历查询结果
            {
                int docId = docs[i].doc;//拿到文档的id,因为Document可能非常占内存(思考DataSet和DataReader的区别)
                //所以查询结果中只有id,具体内容需要二次查询
                Document doc = searcher.Doc(docId);//根据id查询内容。放进去的是Document,查出来的还是Document
                SearchResult result = new SearchResult();
                result.Id = Convert.ToInt32(doc.Get("Id"));
                msg = doc.Get("Content");//只有 Field.Store.YES的字段才能用Get查出来
                result.Msg = LuceneHelper.CreateHightLight(kw, msg);//将搜索的关键字高亮显示。
                title = doc.Get("Title");
                foreach (string word in lstkw)
                {
                    title = title.Replace(word, "" + word + "");
                }
                //result.Title=LuceneHelper.CreateHightLight(kw, title);
                result.Title = title;
                result.CreateTime = Convert.ToDateTime(doc.Get("CreateTime"));
                result.Url = "/Article/Details?Id=" + result.Id + "&kw=" + kw;
                list.Add(result);
            }
            //先将搜索的词插入到明细表。
            SearchDetail _SearchDetail = new SearchDetail { Id = Guid.NewGuid(), KeyWords = kw, SearchDateTime = DateTime.Now };
            db.SearchDetail.Add(_SearchDetail);
            int r = db.SaveChanges();

            PagedList<SearchResult> lst = new PagedList<SearchResult>(list, pageNo, pageLen, recCount);
            lst.TotalItemCount = recCount;
            lst.CurrentPageIndex = pageNo;

            return lst;
        }

        /// <summary>
        /// 获取客户列表 模糊查询
        /// </summary>
        /// <param name="term"></param>
        /// <returns></returns>
        public string GetKeyWordsList(string term)
        {
            if (string.IsNullOrWhiteSpace(term))
                return null;

            var list = new KeyWordsTotalService().GetSearchMsg(term);
            //序列化对象
            //尽量不要用JavaScriptSerializer,为什么?性能差,完全可用Newtonsoft.Json来代替
            //System.Web.Script.Serialization.JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer();
            //return js.Serialize(list.ToArray());
            return JsonConvert.SerializeObject(list.ToArray());
        }

View Code

由来,站内寻找的基本功效均已做到。

拾.5.二 火爆找出

十.伍.2.2 寻觅下拉框

此间笔者引入3个第三方js框架Autocomplete,它能在文本框中输入文字的时候,自动从后台抓去数据下拉列表。

云盘中本人提供了Autocomplete.rar,将其解压,然后拷贝到Search德姆o项目中的lib目录下。

在Search德姆o项目中的KeyWordsTotalService.cs类中增多方法

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;

namespace SearchDemo.Common
{
    public class KeyWordsTotalService
    {
        private SearchDemoContext db = new SearchDemoContext();

        public List<string> GetSearchMsg(string term)
        {
            try
            {
                //存在SQL注入的安全隐患
                //string sql = "select KeyWords from SearchTotals where KeyWords like '"+term.Trim()+"%'";
                //return db.Database.SqlQuery<string>(sql).ToList();
                string sql = "select KeyWords from SearchTotals where KeyWords like @term";
                return db.Database.SqlQuery<string>(sql, new SqlParameter("@term", term+"%")).ToList();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
    }
}

下一场在LastSearch调整器中增添方法:

     /// <summary>
        /// 获取客户列表 模糊查询
        /// </summary>
        /// <param name="term"></param>
        /// <returns></returns>
        public string GetKeyWordsList(string term)
        {
            if (string.IsNullOrWhiteSpace(term))
                return null;

            var list = new KeyWordsTotalService().GetSearchMsg(term);
            //序列化对象
            //尽量不要用JavaScriptSerializer,为什么?性能差,完全可用Newtonsoft.Json来代替
            //System.Web.Script.Serialization.JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer();
            //return js.Serialize(list.ToArray());
            return JsonConvert.SerializeObject(list.ToArray());
        }

我们来看View:

<link href="~/lib/Autocomplete/css/ui-lightness/jquery-ui-1.8.17.custom.css" rel="stylesheet" />
<script src="~/lib/Autocomplete/js/jquery-ui-1.8.17.custom.min.js"></script>
<script type="text/javascript">
    $(function () {
        $("#divKeyWords a").click(function () {
            $("#txtSearch").val($(this).html());
            $("#btnSearch").click();
        });
        getKeyWordsList("txtSearch");
    });
    //自动加载搜索列表
    function getKeyWordsList(txt) {
        if (txt == undefined || txt == "")
            return;
        $("#" + txt).autocomplete({
            source: "/LastSearch/GetKeyWordsList",
            minLength: 1
        });
    }
</script>
拾.五.二.贰 寻找下拉框

那边本身引进1个第二方js框架Autocomplete,它能在文本框中输入文字的时候,自动从后台抓去数据下拉列表。

云盘中本身提供了Autocomplete.rar,将其解压,然后拷贝到SearchDemo项目中的lib目录下。

在Search德姆o项目中的KeyWordsTotalService.cs类中增加方法

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;

namespace SearchDemo.Common
{
    public class KeyWordsTotalService
    {
        private SearchDemoContext db = new SearchDemoContext();

        public List<string> GetSearchMsg(string term)
        {
            try
            {
                //存在SQL注入的安全隐患
                //string sql = "select KeyWords from SearchTotals where KeyWords like '"+term.Trim()+"%'";
                //return db.Database.SqlQuery<string>(sql).ToList();
                string sql = "select KeyWords from SearchTotals where KeyWords like @term";
                return db.Database.SqlQuery<string>(sql, new SqlParameter("@term", term+"%")).ToList();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
    }
}

下一场在LastSearch调节器中加多方法:

     /// <summary>
        /// 获取客户列表 模糊查询
        /// </summary>
        /// <param name="term"></param>
        /// <returns></returns>
        public string GetKeyWordsList(string term)
        {
            if (string.IsNullOrWhiteSpace(term))
                return null;

            var list = new KeyWordsTotalService().GetSearchMsg(term);
            //序列化对象
            //尽量不要用JavaScriptSerializer,为什么?性能差,完全可用Newtonsoft.Json来代替
            //System.Web.Script.Serialization.JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer();
            //return js.Serialize(list.ToArray());
            return JsonConvert.SerializeObject(list.ToArray());
        }

大家来看View:

<link href="~/lib/Autocomplete/css/ui-lightness/jquery-ui-1.8.17.custom.css" rel="stylesheet" />
<script src="~/lib/Autocomplete/js/jquery-ui-1.8.17.custom.min.js"></script>
<script type="text/javascript">
    $(function () {
        $("#divKeyWords a").click(function () {
            $("#txtSearch").val($(this).html());
            $("#btnSearch").click();
        });
        getKeyWordsList("txtSearch");
    });
    //自动加载搜索列表
    function getKeyWordsList(txt) {
        if (txt == undefined || txt == "")
            return;
        $("#" + txt).autocomplete({
            source: "/LastSearch/GetKeyWordsList",
            minLength: 1
        });
    }
</script>

十.五.叁 题目和剧情都援助寻找并高亮体现

在10.四中,只帮助在内容中对重要词进行搜寻,而实际上,大家恐怕既要接济在标题中搜索,也要在剧情中搜寻。

此间引进了BooleanQuery,我们的询问条件也增加了3个titleQuery。

查究方法中,如下代码有改动:

 PhraseQuery query = new PhraseQuery();//查询条件
            PhraseQuery titleQuery = new PhraseQuery();//标题查询条件
            List<string> lstkw = LuceneHelper.PanGuSplitWord(kw);//对用户输入的搜索条件进行拆分。

            foreach (string word in lstkw)            {
                query.Add(new Term("Content", word));//contains("Content",word)
                titleQuery.Add(new Term("Title", word));
            }
            query.SetSlop(100);//两个词的距离大于100(经验值)就不放入搜索结果,因为距离太远相关度就不高了

            BooleanQuery bq = new BooleanQuery();
            //Occur.Should 表示 Or , Must 表示 and 运算
            bq.Add(query, BooleanClause.Occur.SHOULD);
            bq.Add(titleQuery, BooleanClause.Occur.SHOULD);

            TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);//盛放查询结果的容器
            searcher.Search(bq, null, collector);//使用query这个查询条件进行搜索,搜索结果放入collector

目录:ASP.NET MVC集团级实战目录

像www.verycd.com、今日头条、天猫、京东都有落到实处站内搜索功用,站内搜索无论在性质和用户体验上都拾分不错,本节,通过运用Lucene.Net来贯彻站内寻找。

演示效果预览如下图拾-2二~10-24所示。

图片 16

图10-22

 图片 17

图10-23

 图片 18

图10-24

在10.四节,已经到位了追寻的首先个本子,然而还有不少地点须要优化。举例说,作者要计算主要词找出的效能高的词,也即热词,以及像百度搜索那样,在输加入关贸总协定组织键字后,会活动把寻觅相关的热词自动以下拉列表的款式带出来。还有诸如寻觅结果分页,查看小表明细等。

相关文章