关闭

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

标签: 搜索lucene网站
391人阅读 评论(1) 收藏 举报
分类:

项目结构:

这里写图片描述


这里写图片描述

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>

运行结果如图:

这里写图片描述

0
0
查看评论

Webpack入门之一:从一个简单例子入门

通过一个简单的例子,初步理解webpack原理以及使用方式。
  • chencl1986
  • chencl1986
  • 2017-06-13 22:17
  • 817

Lucene.Net多字段查询

//搜索条件                 PhraseQuery queryTitle = new PhraseQuery();            ...
  • hzy19860111
  • hzy19860111
  • 2013-10-17 00:04
  • 1090

asp.net中利用Lucene.net实现检索并对检索关键字高亮显示

Lucene.NET是一个全文搜索框架,而不是应用产品。关于其中用到的两个dll文件,可到http://d.download.csdn.net/down/2352061/taomanman免费下载。 直接贴代码了:http://www.w3.org/TR/xhtml1/DTD/xhtml1...
  • taomanman
  • taomanman
  • 2010-05-14 14:39
  • 5579

借助 Lucene.Net 构建站内搜索引擎(上)

借助 Lucene.Net 构建站内搜索引擎(上) 前言:最近翻开了之前老杨(杨中科)的Lucene.Net站内搜索项目的教学视频,于是作为老杨脑残粉的我又跟着复习了一遍,学习途中做了一些笔记也就成了接下来您看到的这篇博文,仅仅是我的个人笔记,大神请呵呵一笑而过。相信做过站内搜索的.Net程序...
  • mss359681091
  • mss359681091
  • 2016-07-31 13:13
  • 1185

vue + elementui 新手入门案例

vue + elementui 新手入门案例 vue vue-router axios vuex webpack elementui 接口在elementui-api中,采用spring boot 开发内置功能点: 登录 未登录判断拦截 不同用户显示不同菜单 api请求统一封装 vuex状态控制是否...
  • u010889990
  • u010889990
  • 2017-11-25 17:48
  • 219

lucene.net 高级应用之排序、设置权重、优化、分布式搜索

1. 基本应用 using System; using System.Collections.Generic; using System.Text; using Lucene.Net; using Lucene.Net.Analysis; using Lucene.Net.Analysis.S...
  • ysq5202121
  • ysq5202121
  • 2012-08-02 10:55
  • 884

Lucene.Net学习心得(转载)

http://kb.cnblogs.com/page/52642/ 一、Lucene点滴    (发音为['lusen]),我经常就读鹿神,是头活蹦乱跳的好鹿,研究它吧,保证感觉它很神!Lucene是一个非常优秀的开源的全文搜索引擎,我们可以在它的上面开发出各种全文搜索的应用来。...
  • itstt
  • itstt
  • 2013-09-11 15:29
  • 2420

JSTL简单入门学习实例

建立页面index.jsp<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib ...
  • csujiangyu
  • csujiangyu
  • 2015-08-13 22:02
  • 1552

AR初入门

最近,想做一个AR的项目,在网上翻阅了会博客,感觉讲的都挺深的,还有一些很专业的名词等造成了AR技术理解困难的问题,所以借此博客讲讲我对AR技术的理解。 借鉴博客地址:http://www.mamicode.com/info-detail-1524759.html AR 增强现实技术,它是一...
  • zhaiax672
  • zhaiax672
  • 2017-03-31 21:19
  • 517

Dubbo教程(三)----一个简单的Dubbo示例

一、创建Maven多模块项目 项目结构如下 模块介绍: dubbo-api            ----API接口 dubbo-consumer ----消费者 dubbo-provider    ...
  • u011781521
  • u011781521
  • 2017-07-29 19:04
  • 1205
    个人资料
    • 访问:1297991次
    • 积分:18625
    • 等级:
    • 排名:第591名
    • 原创:312篇
    • 转载:932篇
    • 译文:123篇
    • 评论:297条
    博客专栏
    文章分类
    打赏
    如果你觉得我的文章对您有用,请随意打赏。 微信 支付宝