Lucene.NET使用入门(二)【简单的搜索网站示例】

来源:互联网 发布:天龙八部九阴神爪 知 编辑:程序博客网 时间:2024/05/17 07:54

项目结构:

这里写图片描述


这里写图片描述

LuceneSearch.Data层

SampleData.cs

namespace LuceneSearch.Model {    public class SampleData {        public int Id { get; set; }        public string Name { get; set; }        public string Description { get; set; }    }}

SelectedList.cs

namespace LuceneSearch.Model {  public class SelectedList {    public string Value { get; set; }    public string Text { get; set; }  }}

SampleDataRepository.cs

using System.Collections.Generic;using System.Linq;using LuceneSearch.Model;namespace LuceneSearch.Repository{    public static class SampleDataRepository    {        public static SampleData Get(int id)        {            return GetAll().SingleOrDefault(x => x.Id.Equals(id));        }        public static List<SampleData> GetAll()        {            return new              List<SampleData> {                           new SampleData {Id = 1, Name = "Belgrad", Description = "City in Serbia"},                           new SampleData {Id = 2, Name = "Moscow", Description = "City in Russia"},                           new SampleData {Id = 3, Name = "Chicago", Description = "City in USA"},                           new SampleData {Id = 4, Name = "Mumbai", Description = "City in India"},                           new SampleData {Id = 5, Name = "Hong-Kong", Description = "City in Hong-Kong"},                         };        }    }}

LuceneSearch.Library层

GoLucene.cs

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Web;using Lucene.Net.Analysis.Standard;using Lucene.Net.Documents;using Lucene.Net.Index;using Lucene.Net.QueryParsers;using Lucene.Net.Search;using Lucene.Net.Store;using LuceneSearch.Model;using Version = Lucene.Net.Util.Version;namespace LuceneSearch.Service{    public static class GoLucene    {        // 属性        public static string _luceneDir =Path.Combine(HttpContext.Current.Request.PhysicalApplicationPath, "lucene_index");        private static FSDirectory _directoryTemp;        private static FSDirectory _directory        {            get            {                if (_directoryTemp == null) _directoryTemp = FSDirectory.Open(new DirectoryInfo(_luceneDir));                if (IndexWriter.IsLocked(_directoryTemp)) IndexWriter.Unlock(_directoryTemp);                var lockFilePath = Path.Combine(_luceneDir, "write.lock");                if (File.Exists(lockFilePath)) File.Delete(lockFilePath);                return _directoryTemp;            }        }        // 搜索方法        public static IEnumerable<SampleData> GetAllIndexRecords()        {            // 验证搜索索引            if (!System.IO.Directory.EnumerateFiles(_luceneDir).Any()) return new List<SampleData>();            // 设置lucene搜索器            var searcher = new IndexSearcher(_directory, false);            var reader = IndexReader.Open(_directory, false);            var docs = new List<Document>();            var term = reader.TermDocs();            // v 2.9.4: use 'term.Doc()'            // v 3.0.3: use 'term.Doc'            while (term.Next()) docs.Add(searcher.Doc(term.Doc));            reader.Dispose();            searcher.Dispose();            return _mapLuceneToDataList(docs);        }        public static IEnumerable<SampleData> Search(string input, string fieldName = "")        {            if (string.IsNullOrEmpty(input)) return new List<SampleData>();            var terms = input.Trim().Replace("-", " ").Split(' ')                .Where(x => !string.IsNullOrEmpty(x)).Select(x => x.Trim() + "*");            input = string.Join(" ", terms);            return _search(input, fieldName);        }        public static IEnumerable<SampleData> SearchDefault(string input, string fieldName = "")        {            return string.IsNullOrEmpty(input) ? new List<SampleData>() : _search(input, fieldName);        }        // 主要搜索方法        private static IEnumerable<SampleData> _search(string searchQuery, string searchField = "")        {            // 验证            if (string.IsNullOrEmpty(searchQuery.Replace("*", "").Replace("?", ""))) return new List<SampleData>();            // 设置Lucene搜索器            using (var searcher = new IndexSearcher(_directory, false))            {                var hits_limit = 1000;                var analyzer = new StandardAnalyzer(Version.LUCENE_30);                // 搜索单字段                if (!string.IsNullOrEmpty(searchField))                {                    var parser = new QueryParser(Version.LUCENE_30, searchField, analyzer);                    var query = parseQuery(searchQuery, parser);                    var hits = searcher.Search(query, hits_limit).ScoreDocs;                    var results = _mapLuceneToDataList(hits, searcher);                    analyzer.Close();                    searcher.Dispose();                    return results;                }                // 搜索多个字段(按照RELEVANCE排序)                else                {                    var parser = new MultiFieldQueryParser                        (Version.LUCENE_30, new[] { "Id", "Name", "Description" }, analyzer);                    var query = parseQuery(searchQuery, parser);                    var hits = searcher.Search(query, null, hits_limit, Sort.INDEXORDER).ScoreDocs;                    var results = _mapLuceneToDataList(hits, searcher);                    analyzer.Close();                    searcher.Dispose();                    return results;                }            }        }        private static Query parseQuery(string searchQuery, QueryParser parser)        {            Query query;            try            {                query = parser.Parse(searchQuery.Trim());            }            catch (ParseException)            {                query = parser.Parse(QueryParser.Escape(searchQuery.Trim()));            }            return query;        }        // 将Lucene搜索索引映射到数据        private static IEnumerable<SampleData> _mapLuceneToDataList(IEnumerable<Document> hits)        {            return hits.Select(_mapLuceneDocumentToData).ToList();        }        private static IEnumerable<SampleData> _mapLuceneToDataList(IEnumerable<ScoreDoc> hits, IndexSearcher searcher)        {            // v 2.9.4: use 'hit.doc'            // v 3.0.3: use 'hit.Doc'            return hits.Select(hit => _mapLuceneDocumentToData(searcher.Doc(hit.Doc))).ToList();        }        private static SampleData _mapLuceneDocumentToData(Document doc)        {            return new SampleData            {                Id = Convert.ToInt32(doc.Get("Id")),                Name = doc.Get("Name"),                Description = doc.Get("Description")            };        }        // 添加/更新/清除  搜索索引数据        public static void AddUpdateLuceneIndex(SampleData sampleData)        {            AddUpdateLuceneIndex(new List<SampleData> { sampleData });        }        public static void AddUpdateLuceneIndex(IEnumerable<SampleData> sampleDatas)        {            // 初始lucene            var analyzer = new StandardAnalyzer(Version.LUCENE_30);            using (var writer = new IndexWriter(_directory, analyzer, IndexWriter.MaxFieldLength.UNLIMITED))            {                // add data to lucene search index (replaces older entries if any)                //将数据添加到lucene搜索索引(如果有的话替换旧条目)                foreach (var sampleData in sampleDatas) _addToLuceneIndex(sampleData, writer);                // 关闭                analyzer.Close();                writer.Dispose();            }        }        public static void ClearLuceneIndexRecord(int record_id)        {            // 初始lucene            var analyzer = new StandardAnalyzer(Version.LUCENE_30);            using (var writer = new IndexWriter(_directory, analyzer, IndexWriter.MaxFieldLength.UNLIMITED))            {                // 删除旧索引条目                var searchQuery = new TermQuery(new Term("Id", record_id.ToString()));                writer.DeleteDocuments(searchQuery);                // 关闭                analyzer.Close();                writer.Dispose();            }        }        public static bool ClearLuceneIndex()        {            try            {                var analyzer = new StandardAnalyzer(Version.LUCENE_30);                using (var writer = new IndexWriter(_directory, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED))                {                    // 删除旧索引条目                    writer.DeleteAll();                    // 关闭                    analyzer.Close();                    writer.Dispose();                }            }            catch (Exception)            {                return false;            }            return true;        }        public static void Optimize()        {            var analyzer = new StandardAnalyzer(Version.LUCENE_30);            using (var writer = new IndexWriter(_directory, analyzer, IndexWriter.MaxFieldLength.UNLIMITED))            {                analyzer.Close();                writer.Optimize();                writer.Dispose();            }        }        private static void _addToLuceneIndex(SampleData sampleData, IndexWriter writer)        {            // 删除旧索引条目            var searchQuery = new TermQuery(new Term("Id", sampleData.Id.ToString()));            writer.DeleteDocuments(searchQuery);            // 添加新的索引条目            var doc = new Document();            // 添加映射到db字段的lucene字段            doc.Add(new Field("Id", sampleData.Id.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));            doc.Add(new Field("Name", sampleData.Name, Field.Store.YES, Field.Index.ANALYZED));            doc.Add(new Field("Description", sampleData.Description, Field.Store.YES, Field.Index.ANALYZED));            // 添加条目到索引            writer.AddDocument(doc);        }    }}

LuceneSearch.Mvc层

HomeController.cs

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Web.Mvc;using LuceneSearch.Repository;using LuceneSearch.Service;using LuceneSearch.Model;using MvcLuceneSampleApp.ViewModels;namespace MvcLuceneSampleApp.Controllers{    public class HomeController : Controller    {        public ActionResult Index(string searchTerm, string searchField, bool? searchDefault, int? limit)        {            //创建默认的Lucene搜索索引目录            if (!Directory.Exists(GoLucene._luceneDir))            {                Directory.CreateDirectory(GoLucene._luceneDir);            }            //执行Lucene搜索            List<SampleData> _searchResults;            if (searchDefault == true)            {                _searchResults = (string.IsNullOrEmpty(searchField) ? GoLucene.SearchDefault(searchTerm) : GoLucene.SearchDefault(searchTerm, searchField)).ToList();            }            else            {                _searchResults = (string.IsNullOrEmpty(searchField)                                  ? GoLucene.Search(searchTerm)                                  : GoLucene.Search(searchTerm, searchField)).ToList();            }            if (string.IsNullOrEmpty(searchTerm) && !_searchResults.Any())            {                _searchResults = GoLucene.GetAllIndexRecords().ToList();            }            //设置和返回视图模型            var search_field_list = new                List<SelectedList> {                                         new SelectedList {Text = "(所有字段)", Value = ""},                                         new SelectedList {Text = "Id", Value = "Id"},                                         new SelectedList {Text = "Name", Value = "Name"},                                         new SelectedList {Text = "Description", Value = "Description"}                                     };            //限制显示数据库记录数            var limitDb = limit == null ? 3 : Convert.ToInt32(limit);            List<SampleData> allSampleData;            if (limitDb > 0)            {                allSampleData = SampleDataRepository.GetAll().ToList().Take(limitDb).ToList();                ViewBag.Limit = SampleDataRepository.GetAll().Count - limitDb;            }            else allSampleData = SampleDataRepository.GetAll();            return View(new IndexViewModel            {                AllSampleData = allSampleData,                SearchIndexData = _searchResults,                SampleData = new SampleData { Id = 9, Name = "埃尔帕索", Description = "德克萨斯城市" },                SearchFieldList = search_field_list,            });        }        public ActionResult Search(string searchTerm, string searchField, string searchDefault)        {            return RedirectToAction("Index", new { searchTerm, searchField, searchDefault });        }        public ActionResult CreateIndex()        {            GoLucene.AddUpdateLuceneIndex(SampleDataRepository.GetAll());            TempData["Result"] = "搜索索引已成功创建!";            return RedirectToAction("Index");        }        [HttpPost]        public ActionResult AddToIndex(SampleData sampleData)        {            GoLucene.AddUpdateLuceneIndex(sampleData);            TempData["Result"] = "记录被成功添加到搜索索引!";            return RedirectToAction("Index");        }        public ActionResult ClearIndex()        {            if (GoLucene.ClearLuceneIndex())                TempData["Result"] = "搜索索引已成功清除!";            else                TempData["ResultFail"] = "索引已锁定,无法清除,请稍后重试或手动清除!";            return RedirectToAction("Index");        }        public ActionResult ClearIndexRecord(int id)        {            GoLucene.ClearLuceneIndexRecord(id);            TempData["Result"] = "搜索索引记录已成功删除!";            return RedirectToAction("Index");        }        public ActionResult OptimizeIndex()        {            GoLucene.Optimize();            TempData["Result"] = "搜索索引成功优化!";            return RedirectToAction("Index");        }    }}

IndexViewModel.cs

using System.Collections.Generic;using LuceneSearch.Model;namespace MvcLuceneSampleApp.ViewModels{    public class IndexViewModel    {        public int Limit { get; set; }        public bool SearchDefault { get; set; }        public SampleData SampleData { get; set; }        public IEnumerable<SampleData> AllSampleData { get; set; }        public IEnumerable<SampleData> SearchIndexData { get; set; }        public IList<SelectedList> SearchFieldList { get; set; }        public string SearchTerm { get; set; }        public string SearchField { get; set; }    }}

Index.cshtml

@model MvcLuceneSampleApp.ViewModels.IndexViewModel<div class="content_left">    <span style="color: green;">@TempData["Result"]</span>    <span style="color: red;">@TempData["ResultFail"]</span></div><div class="clear"></div><div class="col_12">    <fieldset>        <legend>数据库记录 (@Html.ActionLink("从数据库创建搜索索引 [+]", "CreateIndex"))</legend>        <table class="grid">            <tr>                <th>@Html.LabelFor(m => Model.SampleData.Id)</th>                <th>@Html.LabelFor(m => Model.SampleData.Name)</th>                <th>@Html.LabelFor(m => Model.SampleData.Description)</th>            </tr>            @foreach (var record in Model.AllSampleData)            {                <tr>                    <td>@record.Id</td>                    <td>@record.Name</td>                    <td>@record.Description</td>                </tr>            }        </table>        @if (ViewBag.Limit > 0)        {            <div class="margin_top10"> <b>@ViewBag.Limit</b> 条更多记录... (<a href="\?limit=0">查看全部</a>)</div>        }    </fieldset></div><div class="col_12">    <fieldset>        <legend>搜索(自定义,适用于大多数基本场景)</legend>        <div class="content_left margin_top5">            <p>尝试这些搜索: <em>"1 3 5", "City", "Russia India", "bel mos ind"</em></p>        </div>        @using (Html.BeginForm("Search", "Home"))        {            <div class="content_left margin_top13 margin_left30">                @Html.CheckBoxFor(m => m.SearchDefault)                @Html.LabelFor(m => m.SearchDefault, "使用默认的Lucene查询")            </div>            <div class="content_left margin_right20">                @Html.TextBoxFor(m => m.SearchTerm, new { @class = "big", style = "width:650px;", autocomplete = "off" })            </div>            <div class="content_left margin_top15 margin_right30">                @Html.DropDownListFor(m => m.SearchField, Model.SearchFieldList.Select(x => new SelectListItem { Text = x.Text, Value = x.Value }),          new { style = "width:150px;" })            </div>            <div class="content_right margin_top8">                <input type="submit" value="搜索" />            </div>            <div class="clear"></div>  }    </fieldset></div><div class="col_8">    <fieldset>        <legend>            Search index            (@Html.ActionLink("优化", "OptimizeIndex"))            (@Html.ActionLink("清除 [X]", "ClearIndex"))        </legend>        @if (Model.SearchIndexData.Any())        {            <table class="grid">                <tr>                    <th>@Html.LabelFor(m => Model.SampleData.Id)</th>                    <th>@Html.LabelFor(m => Model.SampleData.Name)</th>                    <th>@Html.LabelFor(m => Model.SampleData.Description)</th>                    <th></th>                </tr>                @foreach (var record in Model.SearchIndexData)                {                    <tr>                        <td>@record.Id</td>                        <td>@record.Name</td>                        <td>@record.Description</td>                        <td>@Html.ActionLink("删除", "ClearIndexRecord", new { record.Id })</td>                    </tr>                }            </table>        }        else        {            <text><br />找不到搜索索引记录...<br /></text>        }    </fieldset></div><div class="col_4">    <fieldset class="add_record">        <legend>添加/更新 搜索索引记录</legend>        使用现有的ID进行更新        @using (Html.BeginForm("AddToIndex", "Home"))        {            <div class="form_horizontal">                <p>                    @Html.LabelFor(m => m.SampleData.Id)<br />                    @Html.TextBoxFor(m => m.SampleData.Id, new { style = "width:30px;" })                </p>                <p>                    @Html.LabelFor(m => m.SampleData.Name)<br />                    @Html.TextBoxFor(m => m.SampleData.Name, new { style = "width:100px;" })                </p>                <p>                    @Html.LabelFor(m => m.SampleData.Description)<br />                    @Html.TextBoxFor(m => m.SampleData.Description, new { style = "width:120px;" })                </p>            </div>            <div class="clear"></div>            <input type="submit" value="添加/更新 记录" />  }    </fieldset></div><script type="text/javascript">    $(document).ready(function () {        $('#SearchTerm').focus();        $('.grid tr:even').css("background", "silver");    });</script>

_Layout.cshtml

@{    Layout = null;}<!DOCTYPE html><html><head>  <title>Lucene.Net | MVC</title>    <link href="@Url.Content("~/Content/style.css")" rel="stylesheet" type="text/css" />  <link href="@Url.Content("~/Content/kickstart/kickstart.css")" rel="stylesheet" type="text/css" />  <link href="@Url.Content("~/Content/style.css")" rel="stylesheet" type="text/css" />  <link href="@Url.Content("~/Content/style.lib.css")" rel="stylesheet" type="text/css" />  <link href="@Url.Content("~/Content/style.local.css")" rel="stylesheet" type="text/css" />    <script src="http://code.jquery.com/jquery.min.js" type="text/javascript"></script>    <script type="text/javascript">window.jQuery || document.write('<script src="@Url.Content("~/Scripts/jquery-1.7.2.min.js")"><\/script>')</script>  <script src="@Url.Content("~/Scripts/kickstart.js")" type="text/javascript"></script>  <script src="@Url.Content("~/Scripts/prettify.js")" type="text/javascript"></script></head><body>    <div class="header clearfix">      <div class="top_menu"><a href="/">主页</a></div>        <h2>Lucene.Net for MVC => 创建更容易!</h2>        <h3>简单的Lucene.Net使用示例站点</h3>    </div>  <div class="content clearfix">        @RenderBody()    </div>    <div class="footer">© @DateTime.Now.Year    </div></body></html>

_Layout.cshtml

@{    Layout = null;}<!DOCTYPE html><html><head>    <title>Lucene.Net | MVC</title>    <link href="@Url.Content("~/Content/style.css")" rel="stylesheet" type="text/css" />    <link href="@Url.Content("~/Content/kickstart/kickstart.css")" rel="stylesheet" type="text/css" />    <link href="@Url.Content("~/Content/style.css")" rel="stylesheet" type="text/css" />    <link href="@Url.Content("~/Content/style.lib.css")" rel="stylesheet" type="text/css" />    <link href="@Url.Content("~/Content/style.local.css")" rel="stylesheet" type="text/css" />    <script src="http://code.jquery.com/jquery.min.js" type="text/javascript"></script>    <script type="text/javascript">window.jQuery || document.write('<script src="@Url.Content("~/Scripts/jquery-1.7.2.min.js")"><\/script>')</script>    <script src="@Url.Content("~/Scripts/kickstart.js")" type="text/javascript"></script>    <script src="@Url.Content("~/Scripts/prettify.js")" type="text/javascript"></script></head><body>    <div class="header clearfix">        <div class="top_menu"><a href="/">主页</a></div>        <h2>Lucene.Net for MVC => 创建更容易!</h2>        <h3>简单的Lucene.Net使用示例站点</h3>    </div>    <div class="content clearfix">        @RenderBody()    </div>    <div class="footer">        © @DateTime.Now.Year    </div></body></html>

运行结果如图:

这里写图片描述

原创粉丝点击