瞎折腾之 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;
        }

控制器

        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视图

注意: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="width: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")

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();

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

谢谢。

时间: 2024-10-11 12:45:21

瞎折腾之 Lucene.Net + MVC 搜索功能的相关文章

【Lucene】Apache Lucene全文检索引擎架构之搜索功能

上一节主要总结了一下Lucene是如何构建索引的,这一节简单总结一下Lucene中的搜索功能.主要分为几个部分,对特定项的搜索:查询表达式QueryParser的使用:指定数字范围内搜索:指定字符串开头搜索以及多条件查询. 1. 对特定项的搜索 要使用Lucene的搜索功能,首先得有索引,也就是说Lucene首先得针对特定的文件生成特定的索引,然后我们才能搜索,这在第一节里描述的很清楚,那么构建索引的例子也是使用第一节中的例子,在这就不再赘述了,然后生成了索引后,如何来搜索呢?先看第一种搜索方式

Lucene 搜索功能

搜索过程 图解: 主要 API: IndexSearcher:    //所有搜索都通过 IndexSearcher 进行,他们将调用该类中重载的 search() 方法 Query:            //封装某种查询类型的具体子类,Query 实例将会被传递给 IndexSearcher 的 search() 方法 QueryParser:      //将用户输入的查询表达式处理成各种具体的 Query 对象 TopDocs:          //保存由 IndexSearcher.

ASP.NET MVC页面搜索功能实现(普通方法和使用Ajax)

使用以下方法可以对数据进行过滤再在页面中显示 假设当前数据库.控制器和视图都已创建 模型名为Movies 控制名为MoviesController 显示页面的视图名为Index 数据库上下文为MovieDBContext 一.     在显示页面添加搜索功能(普通) 1.         在显示页面的视图中(即Index.cshtml)加入一个搜索表单 @using (Html.BeginForm("Index", "Movies", FormMethod.Get)

刚接触Joomla,写一下瞎折腾的初感受~

我这几天一直在苦苦寻找一款可以长期投靠的CMS产品,要求的是 1)必须支持命名空间 2)必须OOP + MVC分层 3)丰富分文档和使用群体,至少是出名的,免得哪一天他们解散了 4)-- 一开始我把目光投向了drupal,看了一下中文网络对他的介绍,什么节点存储思路,创造了什么先河.看了之后都睡不着觉了,恨不得开灯起来下载测试下. 不过第二天下载来安装发现,很让自己失望(自己对Drupal的感受的文章 http://blog.csdn.net/default7/article/details/3

创建一个提供搜索功能的搜索类(可运行)

/* * 这段代码的主要功能是对于创建索引的后的文件, * 创建一个提供搜索功能的搜索类. * */ package ch2.lucenedemo.process; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.Date; import java.util.Iterator; import jav

【转载】使用Lucene.NET实现数据检索功能

1.索引的管理 //指定索引库文件存放文件位置 FSDirectory directory = FSDirectory.Open(new DirectoryInfo(this.IndexDataDir), new NativeFSLockFactory()); //判断索引文件目录是否存在 bool isExist = IndexReader.IndexExists(directory); if (isExist) { if (IndexWriter.IsLocked(directory)) {

利用solr实现商品的搜索功能

Solr 是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的全文搜索服务器.Solr提供了比Lucene更为丰富的查询语言,同时实现了可配置.可扩展,并对索引.搜索性能进行了优化. Solr是一个全文检索服务器,只需要进行配置就可以实现全文检索服务.有效降低频繁访问数据库对数据库造成的压力. 第一步:将solr部署在linux系统下. 第二步:solrJ是solr的客户端,使用它需要依赖solrJ的jar包. 第三步:将数据库的内容添加到solr的索引库,这样查询就在索

创建一个提供搜索功能来搜索类(可执行文件)

/* * 这段代码的主要功能是后创建文件的索引. * 创建一个提供搜索功能来搜索类. * */ package ch2.lucenedemo.process; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.Date; import java.util.Iterator; import java.u

【瞎折腾系列】Spring DataSource 【结论:没弄好】

本来想弄个多数据源,但是技术不高,嗯,宣布失败... 嗯,结论是失败了... 求高手给我讲讲这些东西啊,感激不尽啊~~~ 以下的折腾也是基于之前配置的Spring Mybatis框架. 想弄多数据源,首先想到的就是从datasource入手. spring-database.xml改成了两个datasource: <bean id="dataSourceA" class="com.alibaba.druid.pool.DruidDataSource">