原文地址:https://damienbod.com/2014/10/01/full-text-search-with-asp-net-mvc-jquery-autocomplete-and-elasticsearch/

本文演示如何在ASP.NET MVC应用程序和ElasticSearch搜索引擎中使用jQuery自动完成功能进行全文搜索。CRUD操作也适用于ElasticSearch(ElasticSearchCrud)。

代码: https://github.com/damienbod/WebSearchWithElasticsearch  (我fork的地址 https://github.com/wtujvk/WebSearchWithElasticsearch

教程

  1.  ElasticsearchCRUD 介绍
  2. 使用自动完成、jQuery和JTALE的简单文档搜索MVC应用程序
  3. 具有嵌套文档的MVC搜索的CRUD
  4. 利用实体框架从MS SQL Server获取数据传输到Elasticsearch
  5. 带有子文档的MVC的搜索
  6. 基于实体框架和搜索的MVC应用
  7. 实时重建Elasticsearch的索引
  8. 基于搜索和Web API导出CSV
  9. 父、子、孙子记录和路由的检索
  10. Elasticsearch的类型映射到ElasticsearchCRUD
  11. 使用搜索语句的搜索同义词分析器
  12. 使用德国分析器搜索
  13. 基于谷歌的MVC地图搜索
  14. 查询和过滤的搜索功能
  15. Elasticsearch批量插入
  16. Elasticsearch聚合搜索
  17. 多个Index和Type的搜索
  18. 搜索高亮
  19. 索引权重

举例:

在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>
}

 

The control can then be used as follows:
 

然后可以按如下方式使用控件:

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

http://www.elasticsearch.org/

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/

 

posted on 2019-01-29 14:50  余昭(Ray)  阅读(163)  评论(0)    收藏  举报