Lucene.net站内搜索—5、搜索引擎第一版实现

目录

Lucene.net站内搜索—1、SEO优化
Lucene.net站内搜索—2、Lucene.Net简介和分词
Lucene.net站内搜索—3、最简单搜索引擎代码
Lucene.net站内搜索—4、搜索引擎第一版技术储备(简单介绍Log4Net、生产者消费者模式)
Lucene.net站内搜索—5、搜索引擎第一版实现
Lucene.net站内搜索—6、站内搜索第二版

  •  站内搜索模块:生产者、消费者,多线程。复习多线程,用多线程做一个winform的生产者、消费者的例子,有任务的时候(点按钮给整数)就处理任务,没任务的时候就每次扫描都说“还是没任务,睡会再看”,用Sleep模拟耗时操作,线程中操作UI线程的代码见备注。
  •  派一个人来管理索引库,想向索引库中写数据的地方都向这个人来发出请求。
  •  由于索引库同时只能有一个IndexWriter进行写,所以有一个消费者线程一直保持对IndexWriter写的状态,有新任务进入的时候对IndexWriter写入。如果IndexWriter一直保持打开状态的话,新添加的文档是不会被搜索到的,因此必须处理完队列中的任务后关闭writer,然后下次while循环扫描的时候判断如果队列汇总没有任务,则sleep5秒钟后再判断,防止不断判断给服务器cpu压力
  •  IndexManager做成单例。维持一个任务的Queue,Thread thread = new Thread(ScanThread); thread.Start();启动一个线程,在ScanThread方法中不断遍历Queue ,当有新任务加入的时候把新任务加入索引库,当要删除文章的时候也是加入一个jobType == JobType.Delete的内容。UpdateDocument
  • 文章的更新和删除。

1、线程访问UI线程:

 ParameterizedThreadStart threadStart = (obj) =>{txtLog.AppendText(obj + "\n");};txtLog.Invoke(threadStart, item);

详细代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading;
using log4net;
using System.Configuration;
using System.Web.Hosting;
using RuPeng.Utils;
using RuPengSite.DataTier.DataSetThreadTableAdapters;
using System.Text;
using Lucene.Net.Store;
using Lucene.Net.Index;
using System.IO;
using Lucene.Net.Analysis.PanGu;
using Lucene.Net.Documents;
namespace RuPengSite.Search
{public class IndexManager{public readonly static IndexManager Instance = new IndexManager();private HashSet<IndexJobItem> jobs = new HashSet<IndexJobItem>();//任务的集合private bool isStopped;//任务是否停止private static ILog log = LogManager.GetLogger(typeof(IndexManager));private IndexManager(){            }//启动任务public void Start(){isStopped = false;Thread thread = new Thread(ScanThread);thread.Start();            }//停止任务public void Stop(){isStopped = true;}/// <summary>/// 扫描线程/// </summary>private void ScanThread(){//如果停止,则不再无限循环while (!isStopped){Thread.Sleep(5000);//休息5秒钟,尽可能多的累积任务if (jobs.Count <= 0){continue;//如果没任务继续睡
                }log.Debug("开始索引预处理");string indexPath = SearchHelper.GetSearchIndexFullPath();log.Debug("索引路径是:" + indexPath);FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NativeFSLockFactory());//判断索引目录是否已经存在bool isUpdate = IndexReader.IndexExists(directory);log.Debug("索引路径存在状态是" + isUpdate);if (isUpdate){//如果索引目录被锁定(比如索引过程中程序异常退出),则首先解锁if (IndexWriter.IsLocked(directory)){log.Debug("开始解锁索引路径");IndexWriter.Unlock(directory);}}IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);try{ProcessJobItems(directory, writer);}finally{log.Debug("开始关闭reader、writer");writer.Close();directory.Close();log.Debug("完成关闭reader、writer");}                       }}/// <summary>/// 处理队列中的任务/// </summary>/// <param name="directory"></param>/// <param name="writer"></param>private void ProcessJobItems(FSDirectory directory, IndexWriter writer){log.Debug("开始处理队列中的"+jobs.Count+"个任务");foreach (var jobItem in jobs.ToArray())//转换为数组,避免读的时候不能修改的问题
            {try{ProcessJobItem(writer, jobItem);jobs.Remove(jobItem);//将处理完成的任务移除
                }catch (Exception ex){log.Error("对任务进行处理失败" + jobItem, ex);}                }log.Debug("队列中的任务处理完毕");}private static void ProcessJobItem(IndexWriter writer, IndexJobItem jobItem){long threadId = jobItem.ThreadId;JobType jobType = jobItem.ItemType;string url = SearchHelper.GetThreadUrl(threadId);if (jobType == JobType.Delete)//判断任务的类型
            {log.Debug("将帖子从索引中移除,threadId=" + threadId);writer.DeleteDocuments(new Term(SearchHelper.URL, url));//删除旧的收录
            }else if (jobType == JobType.Add){writer.DeleteDocuments(new Term(SearchHelper.URL, url));//删除旧的收录var threads = new rp_threadsTableAdapter().GetDataById(threadId);if (threads.Count <= 0){log.Debug("id为"+threadId+"的帖子不存在!");return;}string body = SearchHelper.GetThreadContent(threadId);//帖子内容string title = threads.Single().Subject;//主题Document document = new Document();document.Add(new Field(SearchHelper.URL, url, Field.Store.YES, Field.Index.NOT_ANALYZED));document.Add(new Field(SearchHelper.TITLE, title, Field.Store.YES, Field.Index.NOT_ANALYZED));document.Add(new Field(SearchHelper.BODY, body, Field.Store.YES, Field.Index.ANALYZED,
Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));writer.AddDocument(document);log.Debug(
"索引帖子" + threadId+"完成");}else{throw new Exception("错误的jobType:" + jobType);}}/// <summary>/// 添加帖子的索引任务/// </summary>/// <param name="threadId"></param>public void AddThread(long threadId){IndexJobItem jobItem = new IndexJobItem() { ItemType=JobType.Add,ThreadId=threadId};jobs.Add(jobItem);}/// <summary>/// 移除帖子的索引任务/// </summary>/// <param name="threadId"></param>public void DeleteThread(long threadId){IndexJobItem jobItem = new IndexJobItem() { ItemType = JobType.Delete, ThreadId = threadId };jobs.Add(jobItem);}class IndexJobItem{public JobType ItemType { get; set; }public long ThreadId { get; set; }public override bool Equals(object obj){IndexJobItem item = obj as IndexJobItem;if (item == null){return false;}return this.ItemType==item.ItemType&&this.ThreadId==item.ThreadId;}public override int GetHashCode(){return ToString().GetHashCode();}public override string ToString(){return ItemType+":"+ThreadId;}}enum JobType {Delete,Add }//任务类型 } }

多条件查询

我看了下淘宝,淘宝的站内搜索只实现了且条件:

或条件查询可以来看看百度,当然,百度是同时采用了且条件和或条件查询的:

在标题和正文中查找

PhraseQuery queryMsg = new PhraseQuery();foreach (string word in CommonHelper.SplitWords(txtKW.Text)){queryMsg.Add(new Term("msg", word));}queryMsg.SetSlop(100);
PhraseQuery queryTitle = new PhraseQuery();foreach (string word in CommonHelper.SplitWords(txtKW.Text)){queryTitle.Add(new Term("title", word));}queryTitle.SetSlop(100);
BooleanQuery query = new BooleanQuery();
query.Add(queryMsg, BooleanClause.Occur.SHOULD); query.Add(queryTitle, BooleanClause.Occur.SHOULD);

BooleanQuery相当于盛放其他查询条件的容器,类似于div。第二个参数:Must为必须有,Must_Not为必须没有,Should为可以有

高亮显示

  • 高亮显示,只显示包含关键词的部分。参考盘古分词的文档。
  • 从网上、文档找来的代码不用细读每行代码,先把它拿过来运行通过再说。
  • 不用每次改代码都重启,在项目的属性页面的Web中选中“启用编辑并继续(Enable Edit and Continue)”
  • 把font控制颜色改成通过style控制颜色,原则“不要在正文中控制格式”。不推荐使用font、b、i、br等。
private static String highLight(string keyword,String content){PanGu.HighLight.SimpleHTMLFormatter formatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color='red'>", "</font>");PanGu.HighLight.Highlighter highlighter = new PanGu.HighLight.Highlighter(formatter, new Segment());highlighter.FragmentSize = 500;string msg = highlighter.GetBestFragment(keyword,content);
if (string.IsNullOrEmpty(msg)){return content;}else{return msg;}}String hightlightTitle = highLight(keyword, title);String hightlightBody = HttpUtility.HtmlEncode(body);//防止XSS攻击hightlightBody = highLight(keyword, hightlightBody);

路径可配置化

  • 连接配置信息放到Web.Config的ConnectionStrings段中,而普通的自定义配置则可以写到AppSettings段中,哪些需要配置:索引的路径,被索引的网站url,索引的时间间隔。
  • 读取string indexPath = ConfigurationManager.AppSettings["IndexPath"],使用ConfigurationManager添加引用System.Configuration
  • 使用request.MapPath或者Server.MapPath把相对于网站根路径的路径转换为绝对路径(不是转换为http://www.baidu.com/a.aspx,转换为c:/baidu_com/a.aspx)。在定时任务等不在Http线程中取HttpContext.Current得到的是null,因此在定时任务中不能用HttpContext.Current.Server.MapPath方法来转换,要用HostingEnvironment.MapPath,因此可以在其他地方也用HostingEnvironment.MapPath。
  • 修改Web.config会造成IIS重启,这样会立即加载新的任务

解决:地址无法发给好友

我们先看下淘宝的站内搜索:

细心看,我们会发现url是一连串的字符串,可以肯定这是采用了get请求的方式。

  • 用户没法把搜索结果页面发给好友,要用Get提交,这样才能得到搜索页面地址。如果采用Get方式的话,要删掉form的runat=server,变成HTML的form、method改为get,所有控件都要用HTML控件。因为只有去掉runat=server的form,才会完全去掉ViewState
  • 注意input不能只指定id,而应该指定name,否则不会出现在querystring中。Id是供Javascript用的,name是供querystring/Request用的。对于type=submit的input来说,只有被点击的input的name、value才会被提交给服务器。
  • method改为get
  • 1、要删掉form的runat=server。(唯一去掉viewstate的方法)
  • 2、所有除了DataBound控件(比如GridView、Repeater等)都要用HTML控件。Repeater、ObjectDataSource之类控件不需要runat=server的form也可以,但是VS总是提示,去源代码视图拖放、让他生成再手动删掉。
  • 3、控件注意要给表单name属性赋值。
  • 4、在后台Page_Load代码中进行响应
  • 5、IsPostBack不再有用,只能通过判断参数是否为空来判断是否是提交的页面。
  • 点搜索按钮以后如何显示搜索关键字:在aspx.cs中定义一个GetKeyWord方法,<input type="text" id="kw1" name="kw" value='<%=Request["kw"] %>'/>

只要有runat=server的form就会产生__VIEWSTATE等,所以去掉form的runat=server,这样除了Repeater等少数控件之外服务端控件都没法使用,只能使用html标签。这是为什么说“要求高的互联网项目不用服务端控件”。面试时候说:我在有的项目中没有用服务端控件的例子。

为了能让查询参数显示在地址栏中,方便传播地址,把form的method改为get;因为ViewState太长,所以影响美观,因此禁用ViewState;但是发现哪怕禁用ViewState,ViewState也没有完全消失;研究发现,只有去掉form的runat=server后才能完全干掉ViewState;但是,一旦去掉form的runat=server后几乎所有的WebForm控件都用不了(除了Repeater等少数几个和input无关的之外),只能用html控件,然后在Page_Load中进行响应。

转载于:https://www.cnblogs.com/jiekzou/p/4381649.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/359048.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

All your files have been encrypted

小弟的姑姑家的老板收银的电脑被黑客黑了,我来解决一下,小孩玩游戏玩电脑中的病毒, 方法很多种,仅供参考。 问题邮件截图: 参考方式: 方法一:给对方钱,一般比较贵,还不如重装系统。哈哈。 方法二:下载解密工具,尝试解密恢复数据, Ransomware File Decrypto Too…

8s yaml 配置生成_接口测试框架实战(六) | 配置的数据驱动

《Python 测试开发实战进阶》课程&#xff0c;4 个月挑战 BAT 大厂年薪 50W Offer&#xff0c;文末加群&#xff01;在实际工作中&#xff0c;为了便于维护&#xff0c;对于环境的切换和配置&#xff0c;通常不会使用硬编码的形式完成。在之前文章《多环境下的接口测试》中&…

使用JAXB和Jackson从XSD生成JSON模式

在本文中&#xff0c;我演示了一种从XML Schema &#xff08;XSD&#xff09;生成JSON Schema的 方法 。 在概述从XML Schema创建JSON Schema的方法的同时&#xff0c;本文还演示了JAXB实现的用法&#xff08;与JDK 9捆绑在一起的xjc版本2.2.12-b150331.1824 [build 1.9.0-ea-b…

Spring Integration完整示例

本文是我们名为“ Spring Integration for EAI ”的学院课程的一部分。 在本课程中&#xff0c;向您介绍了企业应用程序集成模式以及Spring Integration如何解决它们。 接下来&#xff0c;您将深入研究Spring Integration的基础知识&#xff0c;例如通道&#xff0c;转换器和适…

配置环境_JavaJDK环境变量配置

1.Java环境搭建1.1 JDK与JREJDK(Java Development Kit Java开发工具包)JDK是提供给Java开发人员使用的&#xff0c;其中包含了java的开发工具&#xff0c;也包括了JRE。所以安装了JDK&#xff0c;就不用在单独安装JRE了。其中开发工具&#xff1a;编译工具(javac.exe)打包工具(…

僵固式思维 OR 成长式思维

有意无意中&#xff0c;看到这样的一篇文章&#xff0c;觉得非常富有正能量&#xff0c;而且也比较有同感。而且&#xff0c;不仅仅对于职场暂时失落或者失意的人有帮助&#xff0c;就是对学生&#xff0c;也一样的。故特分享&#xff0c;以共勉之。 我想每个新人进入职场之后都…

Asp.net MVC 的一些总结(二)——图片显示

这里实现的是&#xff0c;如下图片所示的效果&#xff1a; 当然&#xff0c;当你看的下图的时候&#xff0c;请不要自己想当然的认为是简单的html布局&#xff01;&#xff01;&#xff01; &#xff08;1&#xff09;业务说明&#xff1a;图片地址是数据库里存的&#xff0c;图…

Spring整合基础

本文是我们名为“ Spring Integration for EAI ”的学院课程的一部分。 在本课程中&#xff0c;向您介绍了企业应用程序集成模式以及Spring Integration如何解决它们。 接下来&#xff0c;您将深入研究Spring Integration的基础知识&#xff0c;例如通道&#xff0c;转换器和适…

java 布局管理器_有时在Java中,一个布局管理器是不够的

java 布局管理器在开发Java Swing应用程序时&#xff0c;最经常的是&#xff0c;我们需要在多个嵌套面板中使用多个布局管理器。 这通常不是问题&#xff0c;被认为是几乎所有人类已知语言的所有UI开发的常规做法。 但是&#xff0c;大多数情况下&#xff0c;对于UI中的每个面板…

支付宝支付、微信支付(最详细教程)

对接支付宝支付接口&#xff0c;官方文档已经写的很清楚了&#xff0c;但是也有很多像我一样的小白&#xff0c;第一次对接支付宝支付接口&#xff0c;会有些迷茫&#xff0c;所以我在此写下这篇文章&#xff0c;给我和我一样的同学&#xff0c;一点思路吧。 第一步&#xff1…

降雨插值_ArcGIS计算土壤侵蚀模数(二)降雨侵蚀力因子R计算

本次采用中国土壤流失方程CSLE计算土壤侵蚀模数&#xff0c;计算公式为&#xff1a;ARKLSBET式中&#xff0c;式中&#xff1a;A—土壤侵蚀模数。thm-2a-1&#xff1b;R—降雨侵蚀力因子&#xff0c;MJmmhm-2h-1a-1&#xff1b;K—土壤可蚀性因子&#xff0c;thm2hhm-2MJmm-1&a…

购买阿里云ECS服务器忘记终端管理密码或者没有设置

自己开发一个APP,想把源码放到服务器上跑一跑,发现使用Xshell远程连接不上去,我记得买服务器的时候没有设置。 一般有两种方法: 1.买服务器的时候,阿里会给你发一份邮件,邮件里面有,这个是官方的说法,我是公司CTO,账号是老板开的,根本不可能看到邮件,所以对我来说不…

输出空格隔开换行_【前端干货】CSS 的空格处理

一空格规则HTML 代码的空格通常会被浏览器忽略。<p>◡◡hello◡◡world◡◡</p>上面是一行 HTML 代码&#xff0c;文字的前部、内部和后部各有两个空格。为了便于识别&#xff0c;这里使用半圆形符号◡表示空格。浏览器的输出结果如下。hello world可以看到&#x…

宝塔面板绑定域名导致无法访问

用这个命令rm -f /www/server/panel/data/domain.conf删除绑定域名后&#xff0c; 就能用ip端口进入面板了&#xff0c;以后还是不要绑定域名了 主要是因为我手残。 看重点&#xff0c;我是绑定了域名&#xff0c;用域名也无法访问。 现在终于进去啦

宝塔访问域名访问不到

首先说明一点&#xff0c;我这个问题不是宝塔面板绑定域名的那种情况。 浏览器输入域名会报上面的错误&#xff0c;经过各种尝试&#xff0c;发现是安全组没有放开&#xff0c;在阿里云控制台添加一个80/80的通用安全组规则即可&#xff0c;知道上行和下行的区别&#xff0c;打…

双千兆和双频千兆哪个好_关于千兆路由器的那些事儿!赶紧收藏

无线Wi-Fi已成为现代人生活、工作的标配&#xff0c;随着百兆乃至千兆的光纤网络普及&#xff0c;传统路由器已跟不上时代的速度了。不少用户的眼光已投向速度更快的千兆路由器&#xff0c;那么大家真的了解什么是千兆路由器吗&#xff1f;千兆路由器有哪几种&#xff1f;近期火…

华三ospf联动bfd_HCIE2020__路由交换专家__BFD综合实验

1.1.1 关于本实验本实验通过配置BFD与BGP协议联动及与VRRP协议联动&#xff0c;掌握BFD的功能和配置方法。1.1.2 实验目的理解BFD的工作原理。 掌握BFD与BGP联动的应用场景及配置方法。 掌握BFD与VRRP联动的应用场景及配置方法。1.1.3 实验组网介绍图1-1 BFD原理配置实验拓扑图…

大学生助学贷款如何还利息(本金+利息都可以)

生源地助学贷款还利息的步骤: 1、首先需要将钱转入支付宝,金额稍微高于应还款项即可。然后登陆电脑版支付宝,一定是要电脑登陆(手机上无法操作),如图所示 2、然后在支付宝主页中,点击右上角的“应用中心”,然后点击“生活服务”如图所示。

谷歌浏览器下载的内容老是自动打开

原因是每次下载内容在浏览器左下角都有提示&#xff0c;一般都是选择打开所在文件夹&#xff0c;一次手残&#xff0c;点了总是打开此文件导致一下载文件就自动打开。 解决方法。 1.点击右上角的... 2.找到设置-高级设置-下载 3.关掉我标红的位置信息即可。现在看不到啦&…

JBoss Fuse 6.2发布–指导如何快速尝试

在上周的红帽峰会上&#xff0c;宣布发布了JBoss Fuse 6.2 。 我要祝贺保险丝团队发布此版本。 我知道他们今年以来一直非常努力地进行质量检查&#xff0c;并确保质量检查通过了企业产品所期望的高品质壁垒。 因此&#xff0c;带着我的Camel帽子&#xff0c;很高兴看到包含最…