نحوه اضافه کردن Auto-Complete به جستجوی لوسین در ASP.NET MVC و Web forms
نویسنده: وحید نصیری
تاریخ: ۱۳۹۱/۰۸/۰۶ ۹:۵۸
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
using System.Collections.Generic;
using System.IO;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Store;
using LuceneSearch.Core.Model;
using LuceneSearch.Core.Utils;
namespace LuceneSearch.Core
{
public static class CreateIndex
{
static readonly Lucene.Net.Util.Version _version = Lucene.Net.Util.Version.LUCENE_30;
public static Document MapPostToDocument(Post post)
{
var postDocument = new Document();
postDocument.Add(new Field("Id", post.Id.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
var titleField = new Field("Title", post.Title, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS);
titleField.Boost = 3;
postDocument.Add(titleField);
postDocument.Add(new Field("Body", post.Body.RemoveHtmlTags(), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
return postDocument;
}
public static void CreateFullTextIndex(IEnumerable<Post> dataList, string path)
{
var directory = FSDirectory.Open(new DirectoryInfo(path));
var analyzer = new StandardAnalyzer(_version);
using (var writer = new IndexWriter(directory, analyzer, create: true, mfl: IndexWriter.MaxFieldLength.UNLIMITED))
{
foreach (var post in dataList)
{
writer.AddDocument(MapPostToDocument(post));
}
writer.Optimize();
writer.Commit();
writer.Close();
directory.Close();
}
}
}
}
namespace LuceneSearch.Core.Model
{
public class SearchResult
{
public int Id { set; get; }
public string Title { set; get; }
}
}
using System.Collections.Generic;
using System.IO;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using LuceneSearch.Core.Model;
using LuceneSearch.Core.Utils;
namespace LuceneSearch.Core
{
public static class AutoComplete
{
private static IndexSearcher _searcher;
/// <summary>
/// Get terms starting with the given prefix
/// </summary>
/// <param name="prefix"></param>
/// <param name="maxItems"></param>
/// <returns></returns>
public static IList<SearchResult> GetTermsScored(string indexPath, string prefix, int maxItems = 10)
{
if (_searcher == null)
_searcher = new IndexSearcher(FSDirectory.Open(new DirectoryInfo(indexPath)), true);
var resultsList = new List<SearchResult>();
if (string.IsNullOrWhiteSpace(prefix))
return resultsList;
prefix = prefix.ApplyCorrectYeKe();
var results = _searcher.Search(new PrefixQuery(new Term("Title", prefix)), null, maxItems);
if (results.TotalHits == 0)
{
results = _searcher.Search(new PrefixQuery(new Term("Body", prefix)), null, maxItems);
}
foreach (var doc in results.ScoreDocs)
{
resultsList.Add(new SearchResult
{
Title = _searcher.Doc(doc.Doc).Get("Title"),
Id = int.Parse(_searcher.Doc(doc.Doc).Get("Id"))
});
}
return resultsList;
}
}
}
using System.Text;
using System.Web.Mvc;
using LuceneSearch.Core;
using System.Web;
namespace LuceneSearch.Controllers
{
public class HomeController : Controller
{
static string _indexPath = HttpRuntime.AppDomainAppPath + @"App_Data\idx";
public ActionResult Index(int? id)
{
if (id.HasValue)
{
//todo: do something
}
return View(); //Show the page
}
public virtual ActionResult ScoredTerms(string q)
{
if (string.IsNullOrWhiteSpace(q))
return Content(string.Empty);
var result = new StringBuilder();
var items = AutoComplete.GetTermsScored(_indexPath, q);
foreach (var item in items)
{
var postUrl = this.Url.Action(actionName: "Index", controllerName: "Home", routeValues: new { id = item.Id }, protocol: "http");
result.AppendLine(item.Title + "|" + postUrl);
}
return Content(result.ToString());
}
}
}
@{
ViewBag.Title = "جستجو";
var scoredTermsUrl = Url.Action(actionName: "ScoredTerms", controllerName: "Home");
var bulletImage = Url.Content("~/Content/Images/bullet_shape.png");
}
<h2>
جستجو</h2>
<div align="center">
@Html.TextBox("term", "", htmlAttributes: new { dir = "ltr" })
<br />
جهت آزمایش lu را وارد نمائید
</div>
@section scripts
{
<script type="text/javascript">
EnableSearchAutocomplete('@scoredTermsUrl', '@bulletImage');
</script>
}
function EnableSearchAutocomplete(url, img) {
var formatItem = function (row) {
if (!row) return "";
return "<img src='" + img + "' /> " + row[0];
}
$(document).ready(function () {
$("#term").autocomplete(url, {
dir: 'rtl', minChars: 2, delay: 5,
mustMatch: false, max: 20, autoFill: false,
matchContains: false, scroll: false, width: 300,
formatItem: formatItem
}).result(function (evt, row, formatted) {
if (!row) return;
window.location = row[1];
});
});
}
result.AppendLine(item.Title + "|" + postUrl); return Content(result.ToString());
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="LuceneSearch.WebForms.Default" %>
<!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">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>جستجو</title>
<link href="Content/Site.css" rel="stylesheet" type="text/css" />
<script src="Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
<script src="Scripts/jquery.autocomplete.js" type="text/javascript"></script>
<script src="Scripts/custom.js" type="text/javascript"></script>
</head>
<body dir="rtl">
<h2>
جستجو</h2>
<form id="form1" runat="server">
<div align="center">
<asp:TextBox runat="server" dir="ltr" ID="term"></asp:TextBox>
<br />
جهت آزمایش lu را وارد نمائید
</div>
</form>
<script type="text/javascript">
EnableSearchAutocomplete('Search.ashx', 'Content/Images/bullet_shape.png');
</script>
</body>
</html>
using System.Text;
using System.Web;
using LuceneSearch.Core;
namespace LuceneSearch.WebForms
{
public class Search : IHttpHandler
{
static string _indexPath = HttpRuntime.AppDomainAppPath + @"App_Data\idx";
public void ProcessRequest(HttpContext context)
{
string q = context.Request.QueryString["q"];
if (string.IsNullOrWhiteSpace(q))
{
context.Response.Write(string.Empty);
context.Response.End();
}
var result = new StringBuilder();
var items = AutoComplete.GetTermsScored(_indexPath, q);
foreach (var item in items)
{
var postUrl = "Default.aspx?id=" + item.Id;
result.AppendLine(item.Title + "|" + postUrl);
}
context.Response.ContentType = "text/plain";
context.Response.Write(result.ToString());
context.Response.End();
}
public bool IsReusable
{ get { return false; } }
}
}
result.AppendLine(item.Title + "|" + postUrl); context.Response.Write(result.ToString());
indexWriter.DeleteDocuments(new Term("Id", id.ToString())) var query = new BooleanQuery();
query.Add(new BooleanClause(new TermQuery(new Term("id", id.ToString(CultureInfo.InvariantCulture))), Occur.SHOULD));
// query.Add(...
// query.Add(...
// ...
writer.DeleteDocuments(query); left: offset.left - options.width + 125
.ac_loading
{
background: white url('Images/indicator.gif') left center no-repeat;
}
window.location = row[1];
$.ajax({
//...
data: $.extend({
q: lastWord(term),
limit: options.max
}, extraParams),
//...
}); $(document).ready(function () {
$("#term").autocomplete(url, {
// .....
extraParams: { id: 12, xyz: "test" }
}).result(function (evt, row, formatted) {
// .....
});
}); EnableSearchAutocomplete('<%=ResolveClientUrl( "~/Handlers/find.ashx")%>', '<%=ResolveClientUrl("Images/bullet_shape.png")%>'); <script type="text/javascript" src='<%: ResolveClientUrl("~/path....") %>'></script>