MVC+MQ+WinServices+Lucene.Net Demo

前言:

我之前没有接触过Lucene.Net相关的知识,最近在园子里看到很多大神在分享这块的内容,深受启发。秉着“实践出真知”的精神,再结合公司项目的实际情况,有了写一个Demo的想法,算是对自己能力的考验吧。

功能描述:

1. 前台网站把新增的索引项对象(标题、内容)序列化后,发送给MQ

2. MQ接收到消息后先持久化,再推送给消息的消费者

3. 消息的消费者(WinServices)接收到消息后,反序列化成索引项对象,调用SearchEngine类库的创建索引方法

4. 前台网站调用SearchEngine类库的查询方法,并传入用户输入的关键字,把查询后匹配的结果显示在View上

注:

1. 为了模拟多个用户同时新增索引项对象,互联网本身就是一个多线程的环境。这里使用了ActiveMQ的队列模式(另外还有主题模式,主要用于消息广播的场景),因为其内部维护了一个先进先出的队列,可以保证每次只能有一个消息被接收,所有其它待接收的都需要排队等待。

2. 这里引入了分布式项目的思想,前台网站只复制新增索引项和查询,MQ负责消息的接收和推送,WinServices负责生成索引文件。

3. 因为还只是Demo,所以很多功能还不完善,离真正企业级应用还有很大的差距,目的只是想练练手,熟悉下相关的知识点。

流程图:

架构图:

层次图:

项目结构:

LuceneTest.Entity:定义索引项和查询结果类的类库

LuceneTest.MQ:封装消息队列(ActiveMQ)发送和接收功能的类库

LuceneTest.Web:用于管理索引项和查询的MVC工程

LuceneTest.WinService.Test:用于WinService测试的WinForm工程

LuceneTest.SearchEngine:封装Lucene.Net的创建索引和根据关键字查询的类库

关键代码片段:

 1         /// <summary>
 2         /// 创建索引
 3         /// </summary>
 4         /// <param name="model"></param>
 5         public void CreateIndex(IndexSet model)
 6         {
 7             //打开 索引文档保存位置
 8             var directory = FSDirectory.Open(new DirectoryInfo(this._indexPath), new NativeFSLockFactory());
 9             //IndexReader:对索引库进行读取的类
10             var isExist = IndexReader.IndexExists(directory);
11
12             if (isExist)
13             {
14                 //如果索引目录被锁定(比如索引过程中程序异常退出或另一进程在操作索引库),则解锁
15                 if (IndexWriter.IsLocked(directory))
16                     //手动解锁
17                     IndexWriter.Unlock(directory);
18             }
19
20             //创建向索引库写操作对象,IndexWriter(索引目录,指定使用盘古分词进行切词,最大写入长度限制)
21             //补充:使用IndexWriter打开directory时会自动对索引库文件上锁
22             var writer = new IndexWriter(directory, new PanGuAnalyzer(), !isExist, IndexWriter.MaxFieldLength.UNLIMITED);
23             //新建文档对象,一条记录对应索引库中的一个文档
24             var document = new Document();
25
26             //向文档中添加字段
27             //所有字段的值都将以字符串类型保存,因为索引库只存储字符串类型数据
28
29             //Field.Store:是否存储原文:
30             //Field.Store.YES:存储原值(如显示原内容必须为YES),可以用document.Get取出原值
31             //Field.Store.NO:不存储原值
32             //Field.Store.COMPRESS:压缩存储
33
34             //Field.Index:是否创建索引:
35             //Field.Index.NOT_ANALYZED:不创建索引
36             //Field.Index.ANALYZED:创建索引(利于检索)
37
38             //WITH_POSITIONS_OFFSETS:指示不仅保存分割后的词,还保存词之间的距离
39             document.Add(new Field("title", model.Title, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
40             document.Add(new Field("content", model.Content, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
41
42             //文档写入索引库
43             writer.AddDocument(document);
44
45             //会自动解锁
46             writer.Close();
47             //不要忘了Close,否则索引结果搜不到
48             directory.Close();
49         }
        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="keyWord"></param>
        /// <returns></returns>
        public List<SearchResult> Search(string keyWord)
        {
            var searchResultList = new List<SearchResult>();

            //打开 索引文档保存位置
            var directory = FSDirectory.Open(new DirectoryInfo(this._indexPath), new NoLockFactory());
            //IndexReader:对索引库进行读取的类
            var reader = IndexReader.Open(directory, true);

            //关键词分词
            var words = this.SplitWords(keyWord);
            //搜索条件
            var query = new PhraseQuery();

            foreach (var item in words)
            {
                query.Add(new Term("content", item));
            }

            //指定关键词相隔最大距离
            query.SetSlop(100);

            //TopScoreDocCollector:存放查询结果的容器
            var collector = TopScoreDocCollector.create(1000, true);

            //IndexReader:对索引库进行查询的类
            var searcher = new IndexSearcher(reader);
            //根据query查询条件进行查询,查询结果放入collector容器
            searcher.Search(query, null, collector);

            //TopDocs:指定0到GetTotalHits(),即所有查询结果中的文档,如果TopDocs(20,10)则意味着获取第20-30之间文档内容,达到分页的效果
            var docs = collector.TopDocs(0, collector.GetTotalHits()).scoreDocs;

            foreach (var item in docs)
            {
                var searchResult = new SearchResult();

                //得到查询结果文档的id(Lucene内部分配的id)
                var docId = item.doc;
                //根据文档id来获得文档对象Document
                var doc = searcher.Doc(docId);

                searchResult.Id = docId;
                searchResult.Title = doc.Get("title");
                //高亮显示
                searchResult.Content = this.HightLight(keyWord, doc.Get("content"));

                searchResultList.Add(searchResult);
            }

            return searchResultList;
        }

查询页面View

@{
    ViewBag.Title = "Search";
}

<h2>Search List</h2>

@using (Html.BeginForm("Search", "IndexMgr"))
{
    <div>
        关键字:
    </div>
    <div>
        @Html.TextBox("keyWord")
    </div>   

    <input type="submit" value="保存" />
}

@{
    var list = this.ViewBag.SearchResultList;

    if (list != null)
    {
        foreach (var item in list)
        {
    @Html.Raw("标题:" + item.Title)
    <br />
    @Html.Raw("内容:" + item.Content)
    <hr />
        }
    }
}

注意事项:

1. 如果使用盘古分词算法,以下文件的“复制到输出目录”需要选择“如果较新则复制”

2. 本Demo的索引文件保存在WinServices的可执行目录(bin\Debug\IndexData)下面,所以前台网站要查询,需要配置索引文件的路径。

运行效果图: 

1. 新增索引项

2. 查询

参考文献:

http://www.cnblogs.com/jiekzou/p/4364780.html

http://www.cnblogs.com/piziyimao/archive/2013/01/31/2887072.html

时间: 2024-10-11 06:41:16

MVC+MQ+WinServices+Lucene.Net Demo的相关文章

ASP.NET MVC+JQueryEasyUI1.4+ADO.NET Demo

1.JQueryEasyUI使用 JQuery EasyUI中文官网:http://www.jeasyui.net/ JQuery EasyUI中文官网下载地址:http://www.jeasyui.net/download/ jQuery EasyUI 1.4 版 API 中文版: 链接:http://pan.baidu.com/s/1c1pAutE%20 密码:0mk8 JQuery EasyUI 1.4.4 百度云盘:链接:http://pan.baidu.com/s/1bnRpH3T 密

spring MVC入门示例(hello world demo)

1. Spring MVC介绍 Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框 架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的. Spring Web MVC也是服务到工作者模式的实现,但进行可优化.前端控制器是DispatcherServlet:应用控制器其实拆为处理器映射器(Handler M

lucene 索引 demo

核心util /** * Alipay.com Inc. * Copyright (c) 2004-2015 All Rights Reserved/ */ package com.lucene.demo; import com.demo.convertor.BookConvertor; import com.demo.domain.BookDO; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.ap

EasyUI+MVC+EF简单用户管理Demo(问题及解决)

原文:http://www.cnblogs.com/xishuai/p/3635192.html 写在前面 iframe-src EntityFramework版本 connectionStrings View.Action.页面跳转 EasyUI中DataGrid绑定 新增.修改和删除数据 效果图.完整示例Demo下载 后记 关于EasyUI了解差不多,就想结合MVC.EF做一个简单的用户管理Demo,其实没多少东西,但这是小菜我第一次做.主要是熟悉下其中的流程,当然也遇到一些问题,走了很多的

lucene 搜索demo

package com.ljq.utils; import java.io.File; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.Inde

JavaWeb_(MVC)管理员后台商品查询demo

MVC分层实现管理员后台商品查询 MVC层即model view controller Model(模型):模型代表着核心的业务逻辑和数据(不要理解成Model只是实体类) View(视图):视图应该关注与如何展示数据,而不应该包含任何业务逻辑(业务逻辑应写在Model中) Controller(控制器):控制器控制着程序的逻辑,并充当着视图和模型之间的协调角色.控制器从视图层接收用户输入的信息,然后使用模型来执行特定的操作,并把最终的结果回传给视图 model层:存放业务逻辑处理,不直接和数据

Spring MVC +MyBatis +MySQL 登录查询Demo 解决了mybatis异常【转】

1.整体结构 2.准备工作 数据库: --Mysql 5.6 创建数据库 wolf 1 CREATE DATABASE wolf; 创建用户表 user 1 2 3 4 5 6 create table user( id int  AUTO_INCREMENT  primary key, name varchar(25) not null, pwd varchar(20) not null, create_time date ) 向表中插入测试数据 1 2 3 4 insert into use

lucene学习记录(一)--lucene demo的学习

敬伟大的实践出真知! 以前研究过全文检索,不过当时重点放在了使用上,而且当时重点放在了基于lucene之上的工具zoie,没有时间好好研究一下真正的实现内容.故现在闲暇时间好好看看官网,研究一下lucene这个全文检索的根.由于水平有限,很多地方比较浅显而且可能会有错误,请看官海涵,敬请指正! 本篇文章直接跳过lucene的各种介绍,援引等等,直接从lucene自带的demo开始记录. 我使用的lucene版本是4.10.2.下载地址:下载,因为我使用的Windows环境,故直接下载了zip包,

使用Lucene实现多个文档关键词检索demo(一)

在进行demo前先到http://www.ibm.com/developerworks/cn/java/j-lo-lucene1/了解关于lucene的一些基本概念,忽略其中的代码实例,因为年代久远,而我的这篇文档正是补充其中代码部分. 了解了基本概念后,接下来就可以开始完成demo了. 首先在http://www.apache.org/dyn/closer.cgi/lucene/java/4.10.0下载lucene包,这里我使用的是最新的4.10版,由于最新版与网上其他lucene使用dem