本文演示如何在ASP.NET MVC应用程序和ElasticSearch搜索引擎中使用jQuery自动完成功能进行全文搜索。CRUD操作也适用于ElasticSearch(ElasticSearchCrud)。
代码: https://github.com/damienbod/WebSearchWithElasticsearch (我fork的地址 https://github.com/wtujvk/WebSearchWithElasticsearch)
教程:
- ElasticsearchCRUD 介绍
- 使用自动完成、jQuery和JTALE的简单文档搜索MVC应用程序
- 具有嵌套文档的MVC搜索的CRUD
- 利用实体框架从MS SQL Server获取数据传输到Elasticsearch
- 带有子文档的MVC的搜索
- 基于实体框架和搜索的MVC应用
- 实时重建Elasticsearch的索引
- 基于搜索和Web API导出CSV
- 父、子、孙子记录和路由的检索
- Elasticsearch的类型映射到ElasticsearchCRUD
- 使用搜索语句的搜索同义词分析器
- 使用德国分析器搜索
- 基于谷歌的MVC地图搜索
- 查询和过滤的搜索功能
- Elasticsearch批量插入
- Elasticsearch聚合搜索
- 多个Index和Type的搜索
- 搜索高亮
- 索引权重
举例:
在ElasticSearch中搜索文档
应用程序使用ElasticSearchCrud访问ElasticSearch。API可以使用任何DTO或实体类,并自动映射到使用类类型的ElasticSearch索引和类型。默认索引是用复数形式表示的类的类型,所有字符都转换为小写字符。默认类型是小写字符的类型名。如果ElasticSearch需要不同的映射,则可以很容易地更改这一点。例如,在ElasticSearch中保存为子文档的类需要其索引的映射,即使用存储父文档的索引。
A Skill class is used in this example. This class is saved in the search engine with the index ‘skills’ and the type ‘skill’.
public class Skill { [Required] [Range(1, long.MaxValue)] public long Id { get; set; } [Required] public string Name { get; set; } [Required] public string Description { get; set; } public DateTimeOffset Created { get; set; } public DateTimeOffset Updated { get; set; } }
ElasticSearchCrud搜索方法用于使用queryString进行全文搜索。该方法从SearchController获取术语,并在引擎中执行查询字符串搜索。此搜索不区分大小写。
几乎可以使用context.search方法进行任何搜索,而不仅仅是查询字符串搜索。不支持突出显示的结果,不支持多个索引或多个类型搜索。您所需要做的就是为搜索构建一个JSON查询,并从点击返回一组类型。查询是使用搜索类生成的。查询属性定义可以使用通配符的查询字符串搜索。
public IEnumerable<Skill> QueryString(string term) { var results = _context.Search<Skill>(BuildQueryStringSearch(term)); return results.PayloadResult.Hits.HitsResult.Select(t => t.Source); } private ElasticsearchCRUD.Model.SearchModel.Search BuildQueryStringSearch(string term) { var names = ""; if (term != null) { names = term.Replace("+", " OR *"); } var search = new ElasticsearchCRUD.Model.SearchModel.Search { Query = new Query(new QueryStringQuery(names + "*")) }; return search; }
The search method is used in the MVC SearchController. Json is returned because the action method is used by the jQuery Autocomplete control.
public JsonResult Search(string term) { return Json(_searchProvider.QueryString(term), "Skills", JsonRequestBehavior.AllowGet); }
自动完成(jquery ui)源方法使用SearchController中的操作方法搜索。这会将对象数组保存到自动完成控件中。此控件在控件的每个项中都需要标签和值属性。选择方法用于从搜索中选择结果。然后将所选项目添加到页面上的其他HTML控件中,以更新或删除HTTP请求。
<fieldset class="form"> <legend>SEARCH for a document in the search engine</legend> <table width="500"> <tr> <th></th> </tr> <tr> <td> <label for="autocomplete">Search: </label> </td> </tr> <tr> <td> <input id="autocomplete" type="text" style="width:500px" /> </td> </tr> </table> </fieldset> @section scripts { <script type="text/javascript"> var items; $(document).ready(function() { $("input#autocomplete").autocomplete({ source: function(request, response) { $.ajax({ url: "search", dataType: "json", data: { term: request.term, }, success: function(data) { var itemArray = new Array(); for (i = 0; i < data.length; i++) { itemArray[i] = { label: data[i].Name, value: data[i].Name, data: data[i] } } console.log(itemArray); response(itemArray); }, error: function(data, type) { console.log(type); } }); }, select: function (event, ui) { $("#spanupdateId").text(ui.item.data.Id); $("#spanupdateCreated").text(new Date(parseInt(ui.item.data.Created.substr(6)))); $("#spanupdateUpdated").text(new Date(parseInt(ui.item.data.Updated.substr(6)))); $("#updateName").text(ui.item.data.Name); $("#updateDescription").text(ui.item.data.Description); $("#updateName").val(ui.item.data.Name); $("#updateDescription").val(ui.item.data.Description); $("#updateId").val(ui.item.data.Id); $("#updateCreated").val(ui.item.data.Created); $("#updateUpdated").val(ui.item.data.Updated); $("#spandeleteId").text(ui.item.data.Id); $("#deleteId").val(ui.item.data.Id); $("#deleteName").text(ui.item.data.Name); console.log(ui.item); } }); }); </script> }
然后可以按如下方式使用控件:

ElasticSearch创建、更新和删除
为了方便搜索和提供一些数据,使用ElasticSearchCrud添加了创建、更新和删除实现。提供程序使用elasticsearchcrud中的上下文,并在对elasticsearch的单个批量请求中执行所有挂起的更改。多个索引,类型可以在单个上下文中执行,批量请求。httpclient类在上下文中心下使用。当在ElasticSearch中添加或更改大量数据时,这很好地工作。
private const string ConnectionString = "http://localhost:9200/"; private readonly IElasticsearchMappingResolver _elasticsearchMappingResolver = new ElasticsearchMappingResolver(); public void AddUpdateEntity(Skill skill) { using (var context = new ElasticsearchContext(ConnectionString, _elasticsearchMappingResolver)) { context.AddUpdateDocument(skill, skill.Id); context.SaveChanges(); } } public void UpdateSkill(long updateId, string updateName, string updateDescription) { using (var context = new ElasticsearchContext(ConnectionString, _elasticsearchMappingResolver)) { var skill = context.GetDocument<Skill>(updateId); skill.Updated = DateTime.UtcNow; skill.Name = updateName; skill.Description = updateDescription; context.AddUpdateDocument(skill, skill.Id); context.SaveChanges(); } } public void DeleteSkill(long deleteId) { using (var context = new ElasticsearchContext(ConnectionString, _elasticsearchMappingResolver)) { context.DeleteDocument<Skill>(deleteId); context.SaveChanges(); } }
然后可以在SearchController中使用。已对HTTP Post Index操作方法中的创建技能文档进行了验证。这将调用ElasticSearchCrud的AddUpdateDocument方法。如果搜索引擎中已存在具有相同ID的文档,则将覆盖该文档。通常,实体来自主数据库,并保存ElasticSearch以进行最佳搜索。主数据库管理实体的ID,因此这对于这个用例来说不是问题。
readonly ISearchProvider _searchProvider = new ElasticSearchProvider(); [HttpGet] public ActionResult Index() { return View(); } [HttpPost] public ActionResult Index(Skill model) { if (ModelState.IsValid) { model.Created = DateTime.UtcNow; model.Updated = DateTime.UtcNow; _searchProvider.AddUpdateDocument(model); return Redirect("Search/Index"); } return View("Index", model); } [HttpPost] public ActionResult Update(long updateId, string updateName, string updateDescription) { _searchProvider.UpdateSkill(updateId, updateName, updateDescription); return Redirect("Index"); } [HttpPost] public ActionResult Delete(long deleteId) { _searchProvider.DeleteSkill(deleteId); return Redirect("Index"); }
然后可以在视图中使用控制器。视图有三种不同的形式:创建、删除和更新。当从自动完成控件中选择搜索结果时,将更新删除和更新表单。
<form name="input" action="update" method="post"> <fieldset class="form"> <legend>UPDATE an existing document in the search engine</legend> <table width="500"> <tr> <th></th> <th></th> </tr> <tr> <td> <span>Id:</span> </td> <td> <span id="spanupdateId">-</span> <input id="updateId" name="updateId" type="hidden" /> </td> </tr> <tr> <td> <span>Name:</span> </td> <td> <input id="updateName" name="updateName" type="text" /> </td> </tr> <tr> <td> <span>Description:</span> </td> <td> <input id="updateDescription" name="updateDescription" type="text" /> </td> </tr> <tr> <td> <span>Created:</span> </td> <td> <span id="spanupdateCreated">-</span> <input id="updateCreated" name="updateCreated" type="hidden" /> </td> </tr> <tr> <td> <span>Updated:</span> </td> <td> <span id="spanupdateUpdated">-</span> <input id="updateUpdated" name="updateUpdated" type="hidden" /> </td> </tr> <tr> <td> <br /> <input type="submit" value="Update Skill" style="width: 200px" /> </td> <td></td> </tr> </table> </fieldset> </form> <form name="input" action="delete" method="post"> <fieldset class="form"> <legend>DELETE an existing document in the search engine</legend> <table width="500"> <tr> <th></th> <th></th> </tr> <tr> <td> <span id="deleteName">-</span> </td> <td> <span id="spandeleteId">-</span> <input id="deleteId" name="deleteId" type="hidden" /> </td> </tr> <tr> <td> <br /> <input type="submit" value="Delete Skill" style="width: 200px" /> </td> <td></td> </tr> </table> </fieldset> </form> @using (Html.BeginForm("Index", "Search")) { @Html.ValidationSummary(true) <fieldset class="form"> <legend>CREATE a new document in the search engine</legend> <table width="500"> <tr> <th></th> <th></th> </tr> <tr> <td> @Html.Label("Id:") </td> <td> @Html.EditorFor(model => model.Id) @Html.ValidationMessageFor(model => model.Id) </td> </tr> <tr> <td> @Html.Label("Name:") </td> <td> @Html.EditorFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name) </td> </tr> <tr> <td> @Html.Label("Description:") </td> <td> @Html.EditorFor(model => model.Description) @Html.ValidationMessageFor(model => model.Description) </td> </tr> <tr> <td> <br /> <input type="submit" value="Add Skill" style="width:200px" /> </td> <td></td> </tr> </table> </fieldset> }
然后可以在浏览器中使用该应用程序,如下所示:

结论
如您所见,使用带有ElasticSearch的ASP.NET MVC进行全文搜索非常容易。这可以很容易地更改为在AngularJS中使用WebAPI。由于这些扩展性好,性能也很好,所以您可以将其用于几乎任何应用程序。
链接
https://www.nuget.org/packages/ElasticsearchCRUD/
http://www.elasticsearch.org/blog/introducing-elasticsearch-net-nest-1-0-0-beta1/
https://github.com/CenturyLinkCloud/ElasticLINQ
https://github.com/elasticsearch/elasticsearch-net
http://nest.azurewebsites.net/
http://jqueryui.com/autocomplete/
http://joelabrahamsson.com/extending-aspnet-mvc-music-store-with-elasticsearch/
http://joelabrahamsson.com/elasticsearch-101/

浙公网安备 33010602011771号