/// <summary>
/// 创建索引
/// </summary>
private void CreateIndexByData(HotLine12345.Model.KL_CONTENT_INFO model)
{
//索引文档保存位置
string indexPath = IndexDic;
if (!System.IO.Directory.Exists(indexPath))
{
System.IO.Directory.CreateDirectory(indexPath);
}
FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NativeFSLockFactory());
//IndexReader:对索引库进行读取的类
bool isExist = IndexReader.IndexExists(directory);
//是否存在索引库文件夹以及索引库特征文件
if (isExist)
{
//如果索引目录被锁定(比如索引过程中程序异常退出或另一进程在操作索引库),则解锁
//Q:存在问题 如果一个用户正在对索引库写操作 此时是上锁的 而另一个用户过来操作时 将锁解开了 于是产生冲突 --解决方法后续
if (IndexWriter.IsLocked(directory))
{
IndexWriter.Unlock(directory);
}
}
//创建向索引库写操作对象 IndexWriter(索引目录,指定使用盘古分词进行切词,最大写入长度限制)
//补充:使用IndexWriter打开directory时会自动对索引库文件上锁
IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isExist, IndexWriter.MaxFieldLength.UNLIMITED);
try
{
///
///写入开始
///
//new一篇文档对象 --一条记录对应索引库中的一个文档
Document document = new Document();
//向文档中添加字段 Add(字段,值,是否保存字段原始值,是否针对该列创建索引)
//NOT_ANALYZED不分词且索引
document.Add(new Field("id", model.KL_CONTENT_ID.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
//Field.Store:表示是否保存字段原值。指定Field.Store.YES的字段在检索时才能用document.Get取出原值
//Field.Index.NOT_ANALYZED:指定不按照分词后的结果保存
if (!string.IsNullOrEmpty(model.KL_CONTENT_TITLE))
document.Add(new Field("title", model.KL_CONTENT_TITLE, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
document.Add(new Field("fileid", "0", Field.Store.YES, Field.Index.NOT_ANALYZED));
if (!string.IsNullOrEmpty(model.KL_SORT_ID))
document.Add(new Field("type", Get_TypeName(Convert.ToInt32(model.KL_SORT_ID)), Field.Store.YES, Field.Index.NOT_ANALYZED));
//Field.Index.ANALYZED:指定文章内容按照分词后结果保存 否则无法实现后续的模糊查询
//WITH_POSITIONS_OFFSETS:指示不仅保存分割后的词 还保存词之间的距离
if (!string.IsNullOrEmpty(model.KL_CONTENT))
document.Add(new Field("content", model.KL_CONTENT, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
//文档写入索引库
writer.AddDocument(document);
///
///写入结束
///
//会自动解锁
writer.Close();
//不要忘了Close,否则索引结果搜不到
directory.Close();
}
catch (Exception ex)
{
writer.Close();
//不要忘了Close,否则索引结果搜不到
directory.Close();
}
}
//查询
public ActionResult Index()
{
List<HotLine12345.Model.KL_CONTENT_INFO> modelResult = new List<HotLine12345.Model.KL_CONTENT_INFO>();
string key = Request.Params["key"];
if (string.IsNullOrEmpty(key))
{
modelResult = null;
return View(modelResult);
}
ViewBag.key = key;
Dictionary<string, string> dic = new Dictionary<string, string>();
BooleanQuery bQuery = new BooleanQuery();
string title = string.Empty;
string content = string.Empty;
if (!string.IsNullOrEmpty(key))
{
key = key.Trim();
title = GetKeyWordsSplitBySpace(key);
if (string.IsNullOrEmpty(title))
{
return View(modelResult);
}
QueryParser parse = new QueryParser("title", PanGuAnalyzer);
Query query = parse.Parse(title);
parse.SetDefaultOperator(QueryParser.Operator.OR);
//BooleanClause用于表示布尔查询子句关系的类,包 括:MUST,MUST_NOT,SHOULD。 必须包含,不能包含,可以包含三种.
bQuery.Add(query, BooleanClause.Occur.SHOULD);
dic.Add("title", key);
txtTitle = key;
//content = GetKeyWordsSplitBySpace(key);
QueryParser parse2 = new QueryParser("content", PanGuAnalyzer);
Query query2 = parse2.Parse(title);
parse2.SetDefaultOperator(QueryParser.Operator.OR);
bQuery.Add(query2, BooleanClause.Occur.SHOULD);
dic.Add("content", key);
txtContent = key;
QueryParser parse3 = new QueryParser("type", PanGuAnalyzer);
Query query3 = parse3.Parse(title);
parse3.SetDefaultOperator(QueryParser.Operator.OR);
bQuery.Add(query3, BooleanClause.Occur.SHOULD);
/模糊查询
Query query4 = new WildcardQuery(new Term("title", key + "*"));
bQuery.Add(query4, BooleanClause.Occur.SHOULD);
Query query5 = new WildcardQuery(new Term("content", key + "*"));
bQuery.Add(query5, BooleanClause.Occur.SHOULD);
}
if (bQuery != null && bQuery.GetClauses().Length > 0)
{
//搜索数据
modelResult = GetSearchResult(bQuery, dic);
}
return View(modelResult);
}
#region 搜索查询
/// <summary>
/// 搜索引擎
/// </summary>
/// <param name="bQuery"></param>
private List<HotLine12345.Model.KL_CONTENT_INFO> GetSearchResult(BooleanQuery bQuery, Dictionary<string, string> dicKeywords)
{
List<HotLine12345.Model.KL_CONTENT_INFO> list = new List<HotLine12345.Model.KL_CONTENT_INFO>();
//FSDirectory directory = FSDirectory.Open(new DirectoryInfo(IndexDic), new NoLockFactory());
//IndexReader reader = IndexReader.Open(directory, true);
//IndexSearcher search = new IndexSearcher(reader);
try
{
IndexSearcher search = new IndexSearcher(IndexDic, true);
Stopwatch stopwatch = Stopwatch.StartNew();
//SortField构造函数第三个字段true为降序,false为升序
Sort sort = new Sort(new SortField("id", SortField.DOC, true));
//采用默认排序,按匹配度排序
TopDocs docs = search.Search(bQuery, (Lucene.Net.Search.Filter)null, PageSize * PageIndex);
stopwatch.Stop();
if (docs != null && docs.totalHits > 0)
{
lSearchTime = stopwatch.ElapsedMilliseconds;
txtPageFoot = GetPageFoot(PageIndex, PageSize, docs.totalHits, "sabrosus");
ViewData["txtPageFoot"] = txtPageFoot;
for (int i = 0; i < docs.totalHits; i++)
{
if (i >= (PageIndex - 1) * PageSize && i < PageIndex * PageSize)
{
Document doc = search.Doc(docs.scoreDocs[i].doc);
HotLine12345.Model.KL_CONTENT_INFO model = new HotLine12345.Model.KL_CONTENT_INFO();
model.KL_CONTENT_TITLE = doc.Get("title").ToString();
model.KL_CONTENT = doc.Get("content").ToString();
model.KL_CONTENT_ID = Convert.ToInt32(doc.Get("id").ToString());
model.KL_FILE = doc.Get("fileid").ToString();
model.KL_SORT_ID = doc.Get("type").ToString();
list.Add(SetHighlighter(dicKeywords, model));
}
}
}
}
catch (Exception ex)
{
}
return list;
}
/// <summary>
/// 处理关键字为索引格式
/// </summary>
/// <param name="keywords"></param>
/// <returns></returns>
private string GetKeyWordsSplitBySpace(string keywords)
{
PanGuTokenizer ktTokenizer = new PanGuTokenizer();
StringBuilder result = new StringBuilder();
ICollection<WordInfo> words = ktTokenizer.SegmentToWordInfos(keywords);
foreach (WordInfo word in words)
{
if (word == null)
{
continue;
}
result.AppendFormat("{0}^{1}.0 ", word.Word, (int)Math.Pow(3, word.Rank));
}
return result.ToString().Trim();
}
/// <summary>
/// 分词器
/// </summary>
/// <param name="keywords"></param>
/// <returns></returns>
private List<string> GetKeyWords_List(string keywords)
{
PanGuTokenizer ktTokenizer = new PanGuTokenizer();
ICollection<WordInfo> words = ktTokenizer.SegmentToWordInfos(keywords);
List<string> list_word = words.Select(q => q.Word).ToList();
return list_word;
}
/// <summary>
/// 设置关键字高亮
/// </summary>
/// <param name="dicKeywords">关键字列表</param>
/// <param name="model">返回的数据模型</param>
/// <returns></returns>
private HotLine12345.Model.KL_CONTENT_INFO SetHighlighter(Dictionary<string, string> dicKeywords, HotLine12345.Model.KL_CONTENT_INFO model)
{
SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color=\"red\">", "</font>");
Highlighter highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new Segment());
highlighter.FragmentSize = 50;
string strTitle = string.Empty;
string strContent = string.Empty;
dicKeywords.TryGetValue("title", out strTitle);
dicKeywords.TryGetValue("content", out strContent);
if (!string.IsNullOrEmpty(strTitle))
{
string str_content = highlighter.GetBestFragment(strTitle, model.KL_CONTENT_TITLE);
if (!string.IsNullOrEmpty(str_content))
{
model.KL_CONTENT_TITLE = str_content;
}
else
{
model.KL_CONTENT_TITLE = strHtml_format(model.KL_CONTENT_TITLE, strTitle);
}
}
if (!string.IsNullOrEmpty(strContent))
{
model.KL_FILE = strHtml_format(model.KL_CONTENT, strTitle);
string str_content = highlighter.GetBestFragment(strContent, model.KL_CONTENT);
if (!string.IsNullOrEmpty(str_content))
{
model.KL_CONTENT = str_content;
}
else
{
model.KL_CONTENT = SubString(model.KL_CONTENT, 45);
}
}
return model;
}
private string strHtml_format(string str, string strTitle)
{
List<string> list_str = GetKeyWords_List(strTitle);
string formatStr = str.Replace("\n", "<br/>").Replace("\r", "<br/>").Replace("\r\n", "<br/>");
foreach (var item in list_str)
{
formatStr = formatStr.Replace(item, "<font color='red'>" + item + "</font>");
}
return formatStr;
}
/// <summary>
/// 字符串截取
/// </summary>
/// <param name="str"></param>
/// <param name="subCount"></param>
/// <returns></returns>
private string SubString(string str, int subCount)
{
string NewStr = "";
if (str.Length > subCount)
{
NewStr = str.Substring(0, subCount) + "...";
}
else
{
NewStr = str;
}
return NewStr;
}
/// <summary>
/// 是否覆盖索引
/// </summary>
private bool Cover
{
get
{
if (Request.Form["cover"] != null)
{
if (Request.Form["cover"] == "1")
{
return true;
}
else
{
return false;
}
}
else return true;
}
}
/// <summary>
/// 分页页脚
/// </summary>
/// <param name="currentPageIndex">当前页</param>
/// <param name="pageSize">记录条数</param>
/// <param name="total">记录总数</param>
/// <param name="cssName">css样式名称</param>
/// <returns></returns>
private string GetPageFoot(int currentPageIndex, int pageSize, int total, string cssName)
{
currentPageIndex = currentPageIndex <= 0 ? 1 : currentPageIndex;
pageSize = pageSize <= 0 ? 10 : pageSize;
string options = string.Empty;
int pageCount = 0;//总页数
int pageVisibleCount = 10; // 显示数量
if (total % pageSize == 0)
{
pageCount = total / pageSize;
}
else
{
pageCount = total / pageSize + 1;
}
if (pageCount <= 1)
{
return "";
}
//如果是整除的话,退后一页
StringBuilder sb = new StringBuilder();
sb.AppendFormat("<div class=\"page_left\">一页显示<select id=\"pageSize\" name=\"pageSize\" onchange =\"SC.Page.ChangeSize();\">{0}</select> 条 总共{1}条</div>", SetOption(pageSize), total);
sb.AppendFormat("<div class=\"page_right\">跳转到第<input type=\"text\" id=\"pageIndex\" name=\"pageIndex\" value=\"{0}\" />页<a href=\"javascript:void(0);\" class=\"easyui-linkbutton\" plain=\"true\" iconCls=\"icon-redo\" οnclick=\"SC.Page.GotoPage();\">Go</a>共<span id=\"pageCount\">" + pageCount + "</span> 页</div><input type=\"hidden\" id=\"isSearch\" name=\"isSearch\" value=\"1\" />", currentPageIndex);
sb.Append("<div class='" + cssName + "'>");// sbrosus分页样式,需要自己添加哇
if (currentPageIndex == 1 || total < 1)
{
sb.Append("<span ><a href='javascript:void(0)'>首页</a></span>");
sb.Append("<span ><a href='javascript:void(0)'>上一页</a></span>");
}
else
{
sb.Append("<span><a οnclick=\"SC.Page.GetPage(1)\">首页</a></span>");
sb.Append("<span><a οnclick=\"SC.Page.GetPage(" + (currentPageIndex - 1).ToString() + ")\">上一页</a></span>");
}
int i = 1;
int k = pageVisibleCount > pageCount ? pageCount : pageVisibleCount;
if (currentPageIndex > pageVisibleCount)
{
i = currentPageIndex / pageVisibleCount * pageVisibleCount;
k = (i + pageVisibleCount) > pageCount ? pageCount : (i + pageVisibleCount);
}
for (; i <= k; i++)//k*10防止k为负数
{
if (i == currentPageIndex)
{
sb.AppendFormat("<span class='current' ><a href='javascript:void(0)'>{0}</a></span> ", i);
}
else
{
sb.AppendFormat("<span><a οnclick=\"SC.Page.GetPage(" + i + ")\" >{0}</a></span> ", i);
}
}
if (currentPageIndex == pageCount || total < 1)
{
sb.Append("<span ><a href='javascript:void(0)'>下一页</a></span>");
sb.Append("<span ><a href='javascript:void(0)'>尾页</a></span>");
}
else
{
sb.Append("<span><a οnclick=\"SC.Page.GetPage(" + (currentPageIndex + 1).ToString() + ")\">下一页</a></span>");
sb.Append("<span><a οnclick=\"SC.Page.GetPage(" + pageCount + ")\">尾页</a></span></div>");
}
return sb.ToString();
}
/// <summary>
/// 根据pagesize获取select标签
/// </summary>
/// <param name="pageSize"></param>
/// <returns></returns>
private string SetOption(int pageSize)
{
StringBuilder sb_options = new StringBuilder();
sb_options.AppendFormat("<option selected=\"selected\">{0}</option>", pageSize.ToString());
for (int i =1; i <7; i++)
{
int creatIndex = (i * 50);
if (pageSize != creatIndex)
sb_options.AppendFormat("<option>{0}</option>", (creatIndex).ToString());
}
return sb_options.ToString();
}
#endregion