Elasticsearch.Net使用(二)【MVC4 图书管理系统】

首先项目结构图:


Model层的相关代码如下:

Book.cs代码如下:

public class Book
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public Guid Id { get; set; }

        [MaxLength(500)]

        [Display(Name = "标题")]
        public string Title { get; set; }

        [MaxLength(5000)]
        [Display(Name = "前言")]
        public string Foreword { get; set; }

        [Display(Name = "总页数")]
        public int Pages { get; set; }

        [Display(Name = "作者")]
        public string Author { get; set; }
    }
public class AppContext:DbContext 
    {
        public AppContext()
        {
            
        }
        public DbSet<Book> Books { get; set; }
    }
ViewModels的相关:

 public class SearchViewModel
    {
        public string Query { get; set; }

        public IEnumerable<IHit<Book>> Results { get; set; }

        public IDictionary<string, Suggest[]> Suggestions { get; set; }

        public long Elapsed { get; set; }

    }
接下来就HomeController.cs和BooksController.cs的代码:

 public class HomeController : Controller
    {
        private SearchService _searchService;
        public HomeController()
        {
            _searchService = new SearchService();
        }
        public ActionResult Index()
        {

            return View();
        }

        public ActionResult Search(string query, int page = 0, int pageSize = 10)
        {

            var result = _searchService.Find(query, page, pageSize);
            var suggestion = _searchService.FindPhraseSuggestion(query, 0, 3);

            var viewModel = new SearchViewModel { Query = query, Results = result.Item1,Elapsed = result.Item2, Suggestions = suggestion };


            return View("Index", viewModel);
        }

    }
 public class BooksController : Controller
    {
        private AppContext db = new AppContext();

        public ActionResult Index()
        {
            return View(db.Books.ToList());
        }

        public ActionResult Details(Guid? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Book book = db.Books.Find(id);
            if (book == null)
            {
                return HttpNotFound();
            }
            return View(book);
        }

        public ActionResult Create()
        {
            return View();
        }

        
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include="Id,Title,Foreword,Pages,Author")] Book book)
        {
            if (ModelState.IsValid)
            {
                book.Id = Guid.NewGuid();
                db.Books.Add(book);
                db.SaveChanges();

                //添加书
                Elasticsearch.Elasticsearch.Client.Index<Book>(book);



                return RedirectToAction("Index");
            }

            return View(book);
        }

        public ActionResult Edit(Guid? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Book book = db.Books.Find(id);
            if (book == null)
            {
                return HttpNotFound();
            }
            return View(book);
        }

       
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include="Id,Title,Foreword,Pages,Author")] Book book)
        {
            if (ModelState.IsValid)
            {
                db.Entry(book).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(book);
        }

        public ActionResult Delete(Guid? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Book book = db.Books.Find(id);
            if (book == null)
            {
                return HttpNotFound();
            }
            return View(book);
        }

        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(Guid id)
        {
            Book book = db.Books.Find(id);
            db.Books.Remove(book);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        public JsonResult Reindex()
        {
            foreach (var book in db.Books)
            {
                //Indexing book
                Elasticsearch.Elasticsearch.Client.Index<Book>(book);
            }
            return Json("OK",JsonRequestBehavior.AllowGet);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
Elasticsearch辅助类:

首先是Elasticsearch.cs

public class Elasticsearch
    {
        private static ElasticClient _client;
        public static ElasticClient Client
        {
            get
            {
                if (_client == null)
                {
                    //连接配置
                    var setting = new ConnectionSettings(ElasticsearchConfiguration.Connection,ElasticsearchConfiguration.DefaultIndex);
                    _client = new ElasticClient(setting);
                }
                return _client;
            }

        }
    }
ElasticsearchConfiguration.cs类

 public static class ElasticsearchConfiguration
    {
        public static string Host { get { return "http://localhost"; } }

        public static long Port { get { return 9200; } }

        public static Uri Connection
        {
            get { return new Uri(string.Format("{0}:{1}", Host, Port)); }
        }

        public static string DefaultIndex
        {
            get { return "library"; }
        }
    }
SearchService.cs代码:

 public class SearchService
    {
        public double MinScore { get {return 0.0005; }}

        //高亮标记前缀
        public string PreHighlightTag
        {
            get { return @"<strong>"; }
        }

        //高亮标记后缀
        public string PostHighlightTag
        {
            get { return @"</strong>"; }
        }


        public Tuple< IEnumerable<IHit<Book>>,long> Find(string query, int page = 0, int pageSize = 10)
        {
            var result = Elasticsearch.Elasticsearch.Client.Search<Book>(s => s
                 .From(page * pageSize)
                 .Size(pageSize)
                 .MinScore(MinScore)
                 .Highlight(h => h
                     .PreTags(PreHighlightTag)
                     .PostTags(PostHighlightTag)
                     .OnFields(
                         f => f.OnField(b => b.Foreword),
                         f => f.OnField(b => b.Title)
                         ))
                 .Query(q => q.QueryString(qs => qs.Query(query).UseDisMax())));

            return new Tuple<IEnumerable<IHit<Book>>, long>(result.Hits,result.ElapsedMilliseconds); 
        }

        //查找短语建议
        public IDictionary<string, Suggest[]> FindPhraseSuggestion(string phrase, int page = 0, int pageSize = 5)
        {
            var result = Elasticsearch.Elasticsearch.Client.Search<Book>(s => s
                .From(page*pageSize)
                .Size(pageSize)
                .SuggestPhrase("did-you-mean", ps => ps
                    .Text(phrase)
                    .OnField(f => f.Foreword))
                .Query(q => q.MatchAll()));
            
            return result.Suggest;
        }


        public IEnumerable<IHit<Book>> FindAll()
        {
            var result = Elasticsearch.Elasticsearch.Client.Search<Book>(s => s.AllIndices());
            return result.Hits;
        }

    }
Views视图

Books文件夹下:

Index.cshtml:

@model IEnumerable<Library.Web.Models.Book>

@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("创建新书", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Title)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Foreword)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Pages)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Author)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Title)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Foreword)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Pages)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Author)
        </td>
        <td>
            @Html.ActionLink("编辑", "Edit", new { id=item.Id }) |
            @Html.ActionLink("详细", "Details", new { id=item.Id }) |
            @Html.ActionLink("删除", "Delete", new { id=item.Id })
        </td>
    </tr>
}

</table>
Edit.cshtml:

@model Library.Web.Models.Book

@{
    ViewBag.Title = "Edit";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Edit</h2>


@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>Book</h4>
        <hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.Id)

        <div class="form-group">
            @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Title)
                @Html.ValidationMessageFor(model => model.Title)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Foreword, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextAreaFor(model => model.Foreword)
                @Html.ValidationMessageFor(model => model.Foreword)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Pages, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Pages)
                @Html.ValidationMessageFor(model => model.Pages)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Author, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Author)
                @Html.ValidationMessageFor(model => model.Author)
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("返回列表", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}
Details.cshtml:

@model Library.Web.Models.Book

@{
    ViewBag.Title = "Details";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Details</h2>

<div>
    <h4>Book</h4>
	<hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.Title)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Title)
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.Foreword)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Foreword)
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.Pages)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Pages)
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.Author)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Author)
        </dd>

    </dl>
</div>
<p>
    @Html.ActionLink("编辑", "Edit", new { id = Model.Id }) |
    @Html.ActionLink("返回列表", "Index")
</p>
Delete.cshtml:

@model Library.Web.Models.Book

@{
    ViewBag.Title = "Delete";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Delete</h2>

<h3>Are you sure you want to delete this?</h3>
<div>
    <h4>Book</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.Title)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Title)
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.Foreword)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Foreword)
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.Pages)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Pages)
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.Author)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Author)
        </dd>

    </dl>

    @using (Html.BeginForm()) {
        @Html.AntiForgeryToken()

        <div class="form-actions no-color">
            <input type="submit" value="Delete" class="btn btn-default" /> |
            @Html.ActionLink("返回列表", "Index")
        </div>
    }
</div>
Create.cshtml:

@model Library.Web.Models.Book

@{
    ViewBag.Title = "Create";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>创建</h2>


@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>Book</h4>
        <hr />
        @Html.ValidationSummary(true)

        <div class="form-group">
            @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Title)
                @Html.ValidationMessageFor(model => model.Title)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Foreword, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextAreaFor(model => model.Foreword)
                @Html.ValidationMessageFor(model => model.Foreword)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Pages, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Pages)
                @Html.ValidationMessageFor(model => model.Pages)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Author, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Author)
                @Html.ValidationMessageFor(model => model.Author)
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="创建" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("回到列表", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}
Home->Index.cshtml

@model Library.Web.ViewModels.SearchViewModel
@{
    ViewBag.Title = "Elasticsearch";
}

<div class="jumbotron">
    <h1>Elasticsearch入门</h1>
    <p class="lead">安装和配置群集</p>
    <ol>
        <li>
            <a href="http://www.oracle.com/technetwork/java/
javase/downloads/index.html">安装Java</a>
        </li>
        <li>
            <a href="http://www.elasticsearch.org/
download/">安装Elasticsearch</a>
        </li>
        <li>运行Elasticsearch</li>
        <li><a href="/Books/Create">增加一些书籍</a></li>
    </ol>
</div>


@if (Model == null)
{
    return;
}
<div style="margin-top: 30px;">
    @if (Model.Suggestions.Any(x => x.Key == "did-you-mean"))
    {
        <span>你的意思是: </span>
        foreach (var suggestions in Model.Suggestions["did-you-mean"])
        {
            var count = 0;
            foreach (var suggestion in suggestions.Options)
            {
                <a href="/Home/Search?query=@suggestion.Text"><strong>@suggestion.Text </strong> </a>
                count++;
            }
            if (count == 0)
            {
                <span class="alert-danger">没有建议!</span>
            }

        }
    }
</div>

<h3><strong>Results for:</strong> @Model.Query</h3>

@if (Model != null)
{
    <table class="table table-condensed">
        <thead>
            <tr><th>文档的分数(排名相关度)</th><th>Title</th><th>Content</th><th>Author</th></tr>
        </thead>

        <tbody>
            @foreach (var result in Model.Results)
            {
                <tr>
                    <td>@result.Score</td>
                    <td>
                        <a href="/Books/Details/@result.Id">
                            @if (result.Highlights != null && result.Highlights.Any(x => x.Key == "title"))
                            {
                                var hl = result.Highlights.FirstOrDefault(x => x.Key == "title");
                                foreach (var h in hl.Value.Highlights)
                                {
                                    WriteLiteral(h);
                                }
                            }
                            else
                            {
                                WriteLiteral(result.Source.Title);
                            }
                        </a>
                    </td>

                    <td>
                        @if (result.Highlights != null && result.Highlights.Any(x => x.Key == "foreword"))
                        {
                            var hl = result.Highlights.FirstOrDefault(x => x.Key == "foreword");
                            foreach (var h in hl.Value.Highlights)
                            {
                                WriteLiteral(h + "...");
                            }
                        }

                    </td>

                    <td>@result.Source.Author</td>
                </tr>

            }
            @if (!Model.Results.Any())
            {
                <tr>
                    <td colspan="4" class="alert alert-danger" style="text-align:center;">没有结果发现:(</td>
                </tr>
            }
        </tbody>

    </table>
    <h4><span class="label label-default">@Model.Results.Count()</span>搜索结果用了 @Model.Elapsed 毫秒</h4>
}
_Layout.cshtml

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")

</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                @Html.ActionLink("Elasticsearch MVC示例", "Index", "Home", null, new { @class = "navbar-brand" })
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("Books", "Index", "Books")</li>
                </ul>


                @using (Html.BeginForm("Search", "Home", FormMethod.Get,new {@class = "navbar-form navbar-left"}))
                {
                    <div class="form-group">
                        <input class="form-control" type="text" placeholder="搜索" name="query" />
                    </div>
                    <button type="submit" class="btn btn-default">提交</button>
                }



            </div>

        </div>
    </div>
    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - Elasticsearch, Nest, ASP.NET 应用</p>
        </footer>
    </div>

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>
</html>
结果如图:


列表页


创建页:


搜索结果页:














  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值