📄 search.aspx.cs
字号:
/*
* Copyright 2005 dotlucene.net
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Data;
using System.IO;
using System.Text.RegularExpressions;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Search.Highlight;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using ShootSearch.Helper;
using System.Configuration;
namespace Searcher
{
/// <summary>
/// Summary description for WebForm1.
/// </summary>
public class Search : System.Web.UI.Page
{
/// <summary>
/// Search results.
/// </summary>
protected DataTable Results = new DataTable();
/// <summary>
/// First item on page (index format).
/// </summary>
private int startAt;
/// <summary>
/// First item on page (user format).
/// </summary>
private int fromItem;
/// <summary>
/// Last item on page (user format).
/// </summary>
private int toItem;
/// <summary>
/// Total items returned by search.
/// </summary>
private int total;
/// <summary>
/// Time it took to make the search.
/// </summary>
private TimeSpan duration;
/// <summary>
/// How many items can be showed on one page.
/// </summary>
private readonly int maxResults = 10;
private bool EnableCache ;
private string CacheURL;
private string IndexDiectory ;
private string m_Query;
protected System.Web.UI.WebControls.TextBox TextBoxQuery;
protected System.Web.UI.WebControls.Repeater Repeater1;
protected System.Web.UI.WebControls.Label LabelSummary;
protected System.Web.UI.WebControls.Repeater Repeater2;
protected System.Web.UI.WebControls.Button ButtonSearch;
#region Page_Load
/// <summary>
/// Page_Load
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Page_Load(object sender, System.EventArgs e)
{
// Press ButtonSearch on enter
Page.RegisterHiddenField("__EVENTTARGET", "ButtonSearch");
try
{
Query = System.Web.HttpUtility.UrlDecode(this.Request["q"]).Trim();
}
catch
{
Query = null;
}
if (!IsPostBack)
{
// EnableCache = Convert.ToBoolean(ConfigurationSettings.AppSettings["EnableCache"]) ;
// CacheURL = ConfigurationSettings.AppSettings["Cache"];
// IndexDiectory = Server.MapPath(ConfigurationSettings.AppSettings["index"] );
EnableCache =true ;
CacheURL = "\\dotlucene\\cache";
IndexDiectory = Server.MapPath("index") ;
if (this.Query != null && Query!="")
{
search();
DataBind();
}
}
}
#endregion
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.ButtonSearch.Click += new System.EventHandler(this.ButtonSearch_Click);
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
#region Does the search and stores the information about the results.
/// <summary>
/// Does the search and stores the information about the results.
/// </summary>
private void search()
{
DateTime start = DateTime.Now;
// 索引目录
//string indexDirectory = Server.MapPath(ConfigurationSettings.AppSettings["EnableCache"] );
//创建一个Searcher用于搜索
IndexSearcher searcher = new IndexSearcher(IndexDiectory);
//从"body"字段搜索
Console.WriteLine(this.Query);
Query query = QueryParser.Parse(this.Query, "body", new StandardAnalyzer());
//创建结果记录集
//定义字段
this.Results.Columns.Add("title", typeof(string));
this.Results.Columns.Add("sample", typeof(string));
this.Results.Columns.Add("info", typeof(string));
this.Results.Columns.Add("url", typeof(string));
//Hits是搜索结果记录集,不过是Lucene自己的格式,需要格式化成标准输出
Hits hits = searcher.Search(query);
//结果个数
this.total = hits.Length();
//创建高亮显示
Formatter formatter = new SimpleHTMLFormatter("<font color=#C60A00>","</font>");
Highlighter highlighter = new Highlighter(formatter ,new QueryScorer(query));
highlighter.TextFragmenter= new SimpleFragmenter(40);
highlighter.MaxDocBytesToAnalyze = 512 ;
// initialize startAt
this.startAt = initStartAt();
// how many items we should show - less than defined at the end of the results
int resultsCount = smallerOf (total, this.maxResults + this.startAt);
for (int i = startAt; i < resultsCount; i++)
{
// get the document from index
Document doc = hits.Doc(i);
// get the document filename
// we can't get the text from the index because we didn't store it there
string url = doc.Get("url");
// this is the place where the documents are stored on the server
// instead, load it from the original location
string plainText;
plainText = doc.Get("body");
StandardAnalyzer analyzer= new StandardAnalyzer();
TokenStream tokenStream = analyzer.TokenStream("body", new StringReader(plainText));
// Get 3 best fragments and seperate with a "..."
string result ;
try
{
result = highlighter.GetBestFragments(tokenStream,plainText,3, "...");
}
catch
{
Console.WriteLine(plainText.Length);
//if(plainText.Length>500)
// plainText = plainText.Substring(0,500);
result = this.SimpleHighLighter( plainText ,this.Query,"<font color=#C60A00>","</font>"
,128) ;
//result = highlighter.GetBestFragments(tokenStream,plainText,3, "...");
}
// create a new row with the result data
DataRow row = this.Results.NewRow();
row["title"] = doc.Get("name");
//坐下面一行显示页面相关信息的
string info= Tools.GetLengthText(url,45,"...");
double length = Convert.ToDouble(doc.Get("length"))/ 1024.0 ;
string strLength = length.ToString();
if(strLength.Length >4 )
strLength = strLength.Substring(0,4);
info += " " + doc.Get("created") + " " + strLength + "k" ;
if(EnableCache)
{
info += " <a href = \"cache.aspx?cache=" + System.Web.HttpUtility.UrlEncode( this.CacheURL + doc.Get("cache") )
+ "&url=" + System.Web.HttpUtility.UrlEncode(doc.Get("url")) + "&key="
+ System.Web.HttpUtility.UrlEncode(this.Query) + " \" class=\"link\" target=\"_blank\" >射日快照</a>"
+ doc.Get("modified") ;
}
//各字段赋值
row["info"] = info;
row["url"] = url;
row["sample"] = result;
this.Results.Rows.Add(row);
}
searcher.Close();
// result information
this.duration = DateTime.Now - start;
this.fromItem = startAt + 1;
this.toItem = smallerOf(startAt + maxResults, total);
}
#endregion
#region Returns the smaller value of parameters.
/// <summary>
/// Returns the smaller value of parameters.
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns></returns>
private int smallerOf(int first, int second)
{
return first < second ? first : second;
}
#endregion
#region Page links
/// <summary>
/// Page links. DataTable might be overhead but there used to be more fields in previous version so I'm keeping it for now.
/// </summary>
protected DataTable Paging
{
get
{
// pageNumber starts at 1
int pageNumber = (startAt + maxResults - 1) / maxResults;
DataTable dt = new DataTable();
dt.Columns.Add("html", typeof(string));
DataRow ar = dt.NewRow();
ar["html"] = pagingItemHtml(startAt, pageNumber + 1, false);
dt.Rows.Add(ar);
int previousPagesCount = 4;
for (int i = pageNumber - 1; i >= 0 && i >= pageNumber - previousPagesCount; i--)
{
int step = i - pageNumber;
DataRow r = dt.NewRow();
r["html"] = pagingItemHtml(startAt + (maxResults * step), i + 1, true);
dt.Rows.InsertAt(r, 0);
}
int nextPagesCount = 4;
for (int i = pageNumber + 1; i <= pageCount && i <= pageNumber + nextPagesCount; i++)
{
int step = i - pageNumber;
DataRow r = dt.NewRow();
r["html"] = pagingItemHtml(startAt + (maxResults * step), i + 1, true);
dt.Rows.Add(r);
}
return dt;
}
}
#endregion
#region Prepares HTML of a paging item
/// <summary>
/// Prepares HTML of a paging item (bold number for current page, links for others).
/// </summary>
/// <param name="start"></param>
/// <param name="number"></param>
/// <param name="active"></param>
/// <returns></returns>
private string pagingItemHtml(int start, int number, bool active)
{
if (active)
return "<a href=\"Search.aspx?q=" + this.Query + "&start=" + start + "\">" + number + "</a>";
else
return "<b>" + number + "</b>";
}
#endregion
#region Prepares the string with seach summary information.
/// <summary>
/// Prepares the string with seach summary information.
/// </summary>
protected string Summary
{
get
{
if (total > 0)
return "Results <b>" + this.fromItem + " - " + this.toItem + "</b> of <b>" + this.total + "</b> for <b>" + this.Query + "</b>. (" + this.duration.TotalSeconds + " seconds)";
return "No results found";
}
}
#endregion
#region Return search query or null if not provided.
/// <summary>
/// Return search query or null if not provided.
/// </summary>
protected string Query
{
get
{
return m_Query ;
// string query = System.Web.HttpUtility.HtmlDecode(this.Request["q"]);
// if (query == String.Empty)
// return null;
// return query;
}
set
{
m_Query = value ;
}
}
#endregion
#region Initializes startAt value. Checks for bad values.
/// <summary>
/// Initializes startAt value. Checks for bad values.
/// </summary>
/// <returns></returns>
private int initStartAt()
{
try
{
int sa = Convert.ToInt32(this.Request.Params["start"]);
// too small starting item, return first page
if (sa < 0)
return 0;
// too big starting item, return last page
if (sa >= total - 1)
{
return lastPageStartsAt;
}
return sa;
}
catch
{
return 0;
}
}
#endregion
#region How many pages are there in the results.
/// <summary>
/// How many pages are there in the results.
/// </summary>
private int pageCount
{
get
{
return (total - 1) / maxResults; // floor
}
}
#endregion
#region First item of the last page
/// <summary>
/// First item of the last page
/// </summary>
private int lastPageStartsAt
{
get
{
return pageCount * maxResults;
}
}
#endregion
#region This should be replaced with a direct client-side get
/// <summary>
/// This should be replaced with a direct client-side get
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ButtonSearch_Click(object sender, System.EventArgs e)
{
this.Response.Redirect("Search.aspx?q=" + this.TextBoxQuery.Text);
}
#endregion
#region Very simple, inefficient, and memory consuming HTML parser. Take a look at Demo/HtmlParser in DotLucene package for a better HTML parser.
/// <summary>
/// Very simple, inefficient, and memory consuming HTML parser. Take a look at Demo/HtmlParser in DotLucene package for a better HTML parser.
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
private string parseHtml(string html)
{
string temp = Regex.Replace(html, "<[^>]*>", "");
return temp.Replace(" ", " ");
}
#endregion
#region SimpleHighLighter
/// <summary>
/// SimpleHighLighter
/// </summary>
/// <param name="p_Body"></param>
/// <param name="p_KeyWords"></param>
/// <returns></returns>
private string SimpleHighLighter(string p_Body , string p_KeyWords , string p_Before ,
string p_After , int p_MaxLength)
{
string [] KeyWords = p_KeyWords.Trim().Split(' ') ;
if(p_Body.Length > p_MaxLength)
{
if( p_Body.IndexOf(KeyWords[0]) > 10 )
{
try
{
if( (p_Body.Length -10 ) > p_MaxLength)
p_Body = "..." + p_Body.Substring(p_Body.IndexOf(KeyWords[0]) -10 ,p_MaxLength) + "...";
else
p_Body = "..." + p_Body.Substring(p_Body.IndexOf(KeyWords[0]) -10) + "...";
}
catch
{}
}
else
p_Body = p_Body.Substring(0 ,p_MaxLength) + "...";
//p_Body = p_Body.Substring(0,80) + "...";
}
for(int i = 0 ; i < KeyWords.Length ; i++)
{
p_Body = p_Body.Replace(KeyWords[i],p_Before + KeyWords[i] + p_After);
}
return p_Body;
}
#endregion
#region
private string SimpleHighLightHelper(string p_Body, string p_KeyWords)
{
return "";
}
#endregion
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -