• 瞎折腾之 Lucene.Net + MVC 搜索功能(上)


    前言

    首先,关于Lucene.Net 的文章已经很多了。我这次决定写出来只是为了练练手,虽然在别人看来没什么用,但是自己确实是手动实践了一把。我个人觉得还是有意义的。爱折腾、敢于实践、才能有所收获,才能发现问题。不要怕自己写的东西有问题,有问题才更好呢,可以让更多的人看见,提意见的当然是好,鄙视的……我也接受,给自己 动力去思考。

    想让自己时刻保持着这种程序员-->代码心态、人都是带有惰性的,一旦玩起来 呵呵...

    效果显示

    进入主题

    相信大家对于LuceneNet 并不陌生了,园子里面的文章很多。

    参考文章:

    http://www.cnblogs.com/birdshover/category/152283.html

    http://www.cnblogs.com/psforever/archive/2011/10/06/2200019.html

    界面是一个在线工具自己手动构的,可以随意的设计自己想要的界面。但是引用的css居然不是Bootstrap的css,这点得注意。

    css样式引用地址:http://www.bootcss.com/p/layoutit/css/bootstrap-combined.min.css

                http://www.bootcss.com/p/layoutit/css/layoutit.css

    在线工具地址:http://www.bootcss.com/p/layoutit/

    数据库大概8w条记录,每次最多取出1W条查询结果。正常人也不会看完这么多的。

     核心代码

    方法

            /// <summary>
            /// 获得搜索列表
            /// </summary>
            /// <param name="keyword">关键字</param>
            /// <param name="pageSize"></param>
            /// <param name="currentPage">当前页码</param>
            /// <param name="count"></param>
            /// <param name="pageCount"></param>
            /// <param name="isLike">是否开启模糊查询</param>
            /// <returns></returns>
            public static List<StoreInfo> GetSearchList(string keyword, int pageSize, int currentPage, out int count, out int pageCount, bool isLike = false)
            {
                string keywords = keyword; //获取用户输入关键字,以备设置高亮显示
                string strIndexPath = INDEX_STORE_PATH;
                List<StoreInfo> storeList = new List<StoreInfo>();
                StoreInfo modelstore;
                pageCount = 0;
                count = 0;
    
                IndexSearcher search = null;
                try
                {
                    search = new IndexSearcher(FSDirectory.Open(new System.IO.DirectoryInfo(strIndexPath)), true);
                }
                catch (Exception)
                {
                    return null;
                }
    
                keyword = GetKeyWordsSplitBySpace(keyword, new PanGuTokenizer());
    
                QueryParser titleQueryParser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, "body", new PanGuAnalyzer(true));
                Query titleQuery = titleQueryParser.Parse(keyword);
    
                Query PrefixQuery_title = null;
                Query PrefixQuery_body = null;
                Query FuzzyQuery_Title = null;
                Query FuzzyQuery_body = null;
                Query WildcardQuery_title = null;
                Query WildcardQuery_body = null;
    
                if (isLike)
                {
                    //以什么开头,输入“ja”就可以搜到包含java和javascript两项结果了
                    PrefixQuery_title = new PrefixQuery(new Term("title", keywords));
                    PrefixQuery_body = new PrefixQuery(new Term("body", keywords));
                    //直接模糊匹配,假设你想搜索跟‘wuzza’相似的词语,你可能得到‘fuzzy’和‘wuzzy’。
                    FuzzyQuery_Title = new FuzzyQuery(new Term("title", keywords));
                    FuzzyQuery_body = new FuzzyQuery(new Term("body", keywords));
                    //通配符搜索
                    WildcardQuery_title = new WildcardQuery(new Term("title", keywords));
                    WildcardQuery_body = new WildcardQuery(new Term("body", keywords));
                }
    
                //MultiFieldQueryParser
                BooleanQuery bq = new BooleanQuery();
    
                bq.Add(titleQuery, BooleanClause.Occur.SHOULD);//表示条件关系为“or”,BooleanClause.Occur.MUST表示“and”,BooleanClause.Occur.MUST_NOT表示“not”
       
                if (isLike)
                {
                    bq.Add(PrefixQuery_title, BooleanClause.Occur.SHOULD);
                    bq.Add(PrefixQuery_body, BooleanClause.Occur.SHOULD);
                    bq.Add(FuzzyQuery_Title, BooleanClause.Occur.SHOULD);
                    bq.Add(FuzzyQuery_body, BooleanClause.Occur.SHOULD);
                    bq.Add(WildcardQuery_title, BooleanClause.Occur.SHOULD);
                    bq.Add(WildcardQuery_body, BooleanClause.Occur.SHOULD);
                }
    
                //创建一个结果收集器(收集结果最大数为1000页)
                TopScoreDocCollector collector = TopScoreDocCollector.create(pageSize * 1000, true);
                search.Search(bq, null, collector);
                TopDocs topDoc = collector.TopDocs(0, collector.GetTotalHits());
    
                //搜索结果总数超出指定收集器大小,则摈弃
                if (topDoc.totalHits > pageSize * 1000)
                    count = pageSize * 1000;
                else
                    count = topDoc.totalHits;
    
                int i = (currentPage - 1) * pageSize;
    
                #region
                Lucene.Net.Documents.Document docs;
                PanGu.HighLight.Highlighter highlighter;
                PanGu.HighLight.SimpleHTMLFormatter simpleHTMLFormatter;
    
                while (i < count && storeList.Count < pageSize)
                {
                    modelstore = new StoreInfo();
    
                    docs = search.Doc(topDoc.scoreDocs[i].doc);
                    try
                    {
                        string strTitle = docs.Get("title");
                        string strContent = docs.Get("body");
                        modelstore.Store_ID = Convert.ToInt32(docs.Get("id"));
    
                        //高亮显示设置
                        simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<span style="color:red;">", "</span>");
                        highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new PanGu.Segment());
                        highlighter.FragmentSize = 200;
    
                        //string GetBestFragment(keywords,content)方法会按照SimpleHTMLFormatter构造的格式对content中关键字进行高亮显示
                        //但如果content中不包含keywords则会返回空值,故需要按照如下进行判断
                        modelstore.Description = highlighter.GetBestFragment(keywords, strContent);
                        if (string.IsNullOrEmpty(modelstore.Description))
                        {
                            modelstore.Description = strContent;
                        }
                        modelstore.Store_Name = highlighter.GetBestFragment(keywords, strTitle);
                        if (string.IsNullOrEmpty(modelstore.Store_Name))
                        {
                            modelstore.Store_Name = strTitle;
                        }
                    }
                    catch (Exception e)
                    {
                        continue;
                    }
                    finally
                    {
                        storeList.Add(modelstore);
                        i++;
                    }
                }
                #endregion
    
                search.Close();
                pageCount = Convert.ToInt32(Math.Ceiling((double)collector.GetTotalHits() / pageSize));
    
                return storeList;
            }
    View Code

    控制器

            public ActionResult Index(string id = "", string kw = "", string isLike = "0", int pageIndex = 1)
            {
                string strKeyWorld = HttpDecode(id.Length == 0 ? kw : id);
                int pageSize = 10;
                int intCount = 0;
                int intPageCount = 0;
                bool _boolisLike = isLike == "1" ? true : false;
                List<StoreInfo> StoreInfoList = null;
                Stopwatch watch = new Stopwatch();
                watch.Start();//调用方法开始计时
    
                if (strKeyWorld.Length > 0)
                {
                    StoreInfoList = LuceneNetUtils.GetSearchList(strKeyWorld, pageSize, pageIndex, out intCount, out intPageCount, _boolisLike);
                }
                watch.Stop();//调用方法计时结束
                double time = watch.Elapsed.TotalSeconds;//总共花费的时间
    
                ViewBag.time = time;
                ViewBag.kw = strKeyWorld;
                ViewBag.count = intCount;
                ViewBag.pageIndex = pageIndex;
                ViewBag.pageSize = pageSize;
                ViewBag.intPageCount = intPageCount;
                ViewBag._boolisLike = _boolisLike;
    
                return View(StoreInfoList);
            }
    View Code

    View视图

    注意:ShowPageBarMvc是个页码条,在页面当中用的时候一定要引用所在命名空间,或者添加webConfig

    @using System.Web.Optimization;
    @using LX.EFOPT.Web.Main.CommonUtils;
    @using PagedList;
    @using PagedList.Mvc;
    @model List<LX.EFOPT.Web.Main.Models.StoreInfo>
    @{
        Layout = "/Views/Shared/_LayoutLucene.cshtml";
    }
    
    <script src="~/Js/jquery.ds.js"></script>
    <div class="container-fluid">
        <div class="row-fluid">
            <div class="span12">
                <form class="form-search" action="/LuceneNet/index/" onsubmit="return _search.checkInput();">
                    <input class="input-medium search-query" id="inputKw" name="kw" value="@ViewBag.kw" type="text" />
                    <button id="btn_search" type="submit" class="btn">查找</button>&nbsp;
                    <input type="checkbox" @(ViewBag._boolisLike ? "checked=checked":"")  name="isLike" id="isLike" value="1" /><label for="isLike">是否开启模糊查询</label>
                    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                    <button id="btn_createIndex1" type="button" class="btn">创建索引-方式1</button>
                    <button id="btn_createIndex2" type="button" class="btn">创建索引-方式2</button>
                </form>
                <div id="ajaxData" style="80%">
                    @{
                        if (Model != null)
                        {
                             <div style="margin-top:20px;"><p>获得约 @ViewBag.count 条结果,用时 @ViewBag.time 秒</p></div>
                            foreach (var item in Model)
                            {
                              <div style="margin-top:20px;">
                                <h4>@item.Store_ID @Html.Raw(item.Store_Name)</h4>
                                <p>@Html.Raw(item.Description)</p>
                                <p><a class="btn" href="javascript:;">查看更多 »</a></p>
                              </div>
                            } 
                         
                          int pageIndex = ViewBag.pageIndex;
                          int pageSize = ViewBag.pageSize;
                          int intCount = ViewBag.count;
                          string kw = ViewBag.kw;
                          string isLike = ViewBag._boolisLike ? "1":"0";
                        @Html.ShowPageBarMvc("/LuceneNet/Index", pageIndex, pageSize, intCount, "kw=" + kw + "&isLike=" + isLike)
                        }
                        else
                        {
                            <div style="margin-top:20px;"><h4>没有找到你想要的数据</h4><p>可以更改关键字试试</p></div>
                        }
                    }
                </div>
            </div>
        </div>
    </div>
    @Scripts.Render("/LuceneNet/js/Search.js")
    View Code

    Js创建索引

    /// <reference path="../../Js/jquery-1.7.1.min.js" />
    /// <reference path="../../Js/jquery.ds.js" />
    
    function LuceneNet() {
        this.$_inputKw = $("#inputKw");
        this.$_btn_search = $("#btn_search");
        this.$_btn_createIndex1 = $("#btn_createIndex1");
        this.$_btn_createIndex2 = $("#btn_createIndex2");
    }
    
    LuceneNet.prototype.init = function () {
        var _self = this;
    
        _self.$_btn_createIndex1.on("click", function () {
            _self.createIndex(1);
        });
        _self.$_btn_createIndex2.on("click", function () {
            _self.createIndex(2);
        });
    };
    
    
    
    LuceneNet.prototype.checkInput = function () {
        _self = this;
        
        if (!_self.$_inputKw.val().length) {
            return false;
        }
    }
    
    LuceneNet.prototype.createIndex = function (_type) {
        _self = this;
        $.ds.tips.open("loading", "请稍后..");
        $.ajax({
            url: "/LuceneNet/CreateIndex",
            type: "get",
            dataType: "json",
            data: { type: _type },
            contentType: "application/x-www-form-urlencoded; charset=utf-8",
            success: function (data) {
                $.ds.tips.close();
            }
        });
    }
    
    
    LuceneNet.prototype.Search = function () {
    
        _self = this;
    
        $.ajax({
            url: "/",
            type: "get",
            dataType: "json",
            contentType: "application/x-www-form-urlencoded; charset=utf-8",
            data: { kw: decodeURI(_self.$_inputKw.val()) },
            success: function (data) {
    
            }
        });
    };
    
    var _search = new LuceneNet();
    _search.init();
    View Code

    下一篇将继续折腾添加索引和删除索引,和数据库保持同步。

    源代码只是我在公司测试的一个项目,比较杂,没有办法全部提供下载。但是我会把代码上传到git或者是网盘

    谢谢。

    原文地址:http://www.cnblogs.com/lxsweat/p/4386420.html

  • 相关阅读:
    VS2005下安装boost
    NOIP2017宝藏 [搜索/状压dp]
    SCOI2008奖励关 [状压dp]
    莫队算法解析
    SCOI2005 互不侵犯 [状压dp]
    Codeforces ----- Kefa and Dishes [状压dp]
    TSP问题之状压dp法
    NOI2001炮兵阵地 [状压dp]
    状压dp入门
    「网络流24题」餐巾计划问题
  • 原文地址:https://www.cnblogs.com/lxsweat/p/4386420.html
Copyright © 2020-2023  润新知