工作的需要,需要对于lucene.net索引即时的更新,毕竟lucene.net的索引重建的话比较慢,数据量大的时候建下要几天,所以就写个了缓冲类来解决即时的更新的问题,其实还是比较简单的。

大体上的原理就是创建的时候创建两组Directory 一组在内存中,一组在硬盘上,搜索的时候可以进行合并去搜索,后续的操作都直接暂放到内存中,定时的去同步到硬盘上,删除或者更新的时候内存中有一缓存Query,用来排除被更新或者删除的内容,当搜索的时候,自动忽略掉这部分的内容去集中,就解决了大多数的问题了。

OK.看代码的实现。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using S = System.Timers;
using IO = System.IO;

using Lucene.Net.Documents;
using Lucene.Net.Store;
using Lucene.Net.Search;
using Lucene.Net.Index;
using Lucene.Net.Analysis;
using System.Collections;
using Lucene.Net.Analysis.MMSeg;

namespace SearchSample
{
    public class BufferDirectory
    {

        private static readonly Analyzer _analysis;

        private static readonly string _path;

        private static RAMDirectory _ramIndex;

        private static readonly IndexWriter _ramWrite;

        private static BufferDirectory _directory;
        private static object _lock = new object();

        private static BooleanQuery _query = new BooleanQuery();
        private static object _querylock = new object();

        static BufferDirectory()
        {
            _path = IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Index");
            _ramIndex = new RAMDirectory();
            _ramWrite = new IndexWriter(_ramIndex, DefaultAnalyzer.Analyzer, true, IndexWriter.MaxFieldLength.LIMITED);
            _analysis = DefaultAnalyzer.Analyzer;

            var tmpFs = FSDirectory.Open(_path);
            if (Lucene.Net.Index.IndexReader.IndexExists(tmpFs))
            {
                using (IndexWriter tmp = new IndexWriter(tmpFs, _analysis, false, IndexWriter.MaxFieldLength.LIMITED))
                {

                }
            }
            else
            {
                using (IndexWriter tmp = new IndexWriter(tmpFs, _analysis, true, IndexWriter.MaxFieldLength.LIMITED))
                {

                }
            }
        }

        ~BufferDirectory()
        {
            _ramIndex.Dispose();
            _ramWrite.Dispose();
            _query = null;
        }

        public static BufferDirectory InitConfig()
        {
            if (_directory == null)
            {
                lock (_lock)
                {
                    if (_directory == null)
                    {
                        _directory = new BufferDirectory();
                    }
                }
            }
            return _directory;
        }

        public static BufferDirectory Instance()
        {
            return _directory;
        }

        /// <summary>
        /// 重启缓存区
        /// </summary>
        public static void Reset()
        {
            lock (_lock)
            {
                _directory = null;

                InitConfig();
            }
            lock (_querylock)
            {
                _query = null;
                _query = new BooleanQuery();
            }
            return;
        }

        /// <summary>
        /// 初始化的时候注册,注册为全局生效
        /// </summary>
        /// <param name="before"></param>
        public static void BeforeConfig(BeforeSetDocument before)
        {
            if (_directory == null)
            {
                throw new NullReferenceException("BufferDirectory为空");
            }
            _directory.BeforeSetDocumentHandler += before;
            return;

        }

        /// <summary>
        /// 初始化的时候注册,注册为全局生效
        /// </summary>
        /// <param name="after"></param>
        public static void AfterConfig(AfterSetDocument after)
        {
            if (_directory == null)
            {
                throw new NullReferenceException("BufferDirectory为空");
            }
            _directory.AfterSetDocumentHandler += after;
            return;
        }

        /// <summary>
        /// 更新删除Query
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public static void IgnoreQuery(Query query, Occur occur)
        {
            lock (_querylock)
            {
                _query.Add(query, occur);
            }
            return;
        }

        public static Query IgnoreQuery()
        {
            return _query;
        }

        public delegate void BeforeSetDocument(Document document);

        public event BeforeSetDocument BeforeSetDocumentHandler;

        public delegate void AfterSetDocument(Document document);

        public event AfterSetDocument AfterSetDocumentHandler;

        private BufferDirectory()
        {

        }

        //public void SetIndexWriter(Action<IndexWriter> action)
        //{
        //    action(_index2);
        //    return;
        //}

        public void CreateDocument(Document documnet)
        {
            try
            {
                if (BeforeSetDocumentHandler != null)
                    BeforeSetDocumentHandler(documnet);
                _ramWrite.AddDocument(documnet);
                if (AfterSetDocumentHandler != null)
                    AfterSetDocumentHandler(documnet);
            }
            catch
            {

            }
            finally
            {
                _ramWrite.Commit();
            }
            return;
        }

        public static void UpdateOrSaved()
        {
            _ramWrite.Optimize();
            using (IndexWriter update = new IndexWriter(FSDirectory.Open(_path), _analysis, false, IndexWriter.MaxFieldLength.LIMITED))
            {
                try
                {
                    update.AddIndexes(IndexReader.Open(_ramIndex, true));
                    update.DeleteDocuments(_query);
                    update.Commit();
                    update.Optimize();
                }
                catch
                {

                }
                finally
                {
                    _ramIndex.Dispose();
                    _ramIndex = null;
                    _ramIndex = new RAMDirectory();
                    using (IndexWriter tmp = new IndexWriter(_ramIndex, _analysis, true, IndexWriter.MaxFieldLength.LIMITED))
                    {

                    }
                }
            }
            return;
        }

        public static IndexReader Reader()
        {
            return new MultiReader(IndexReader.Open(FSDirectory.Open(_path), false), IndexReader.Open(_ramIndex, false));
        }
    }
}

  

大体上也就这样逻辑,但是还有一个就是内存中的索引持久问题,毕竟如果不进行持久,在AppDomain重启会导致内存中的索引删除,而导致的索引不同步。

这样可以通过BeforeSetDocumentHandler 和AfterSetDocumentHandler事件来写入到持久的临时缓冲器,加载的时候自动优先加载这部分的临时缓存区,于是就算比较完整的实现lucene.net动态维护了。

当然这些是比较粗暴的方法,还有一些更好的维护策略,就以后再慢慢总结了。

lucene.net的一个动态更新类的更多相关文章

  1. vue+vuex+axios+echarts画一个动态更新的中国地图

    一. 生成项目及安装插件 # 安装vue-cli npm install vue-cli -g # 初始化项目 vue init webpack china-map # 切到目录下 cd china- ...

  2. JAVA代码热部署,在线不停服动态更新

    本地debug的时候,可以实时编译并更新代码,线上也可以不停服来动态更新类,即所说的java热部署.   JDK代理的两种方式: 1.premain方式是Java SE5开始就提供的代理方式,但其必须 ...

  3. C++学习之动态数组类的封装

    动态数组(Dynamic Array)是指动态分配的.可以根据需求动态增长占用内存的数组.为了实现一个动态数组类的封装,我们需要考虑几个问题:new/delete的使用.内存分配策略.类的四大函数(构 ...

  4. ajax动态更新下拉列表

    前面做了一个ajax的小demo,今天看一个动态更新下拉列表,或者也叫级联更新下拉列表,这个也是利用ajax的异步调用去后台实现数据请求.然后回到前台完毕下拉列表数据的更新,以增强web应用的交互性. ...

  5. Unity热更新之C#反射动态获取类属性及方法

    如果我们要为发布出去的游戏更新一些功能,但又不想让用户重新下载整个游戏包,只让他下载我们更新的资源包,用assetBundle打包资源的方式是可以的,但其中有个最大的例外,那就是脚本. 虽然asset ...

  6. Vue父组件向子组件传递一个动态的值,子组件如何保持实时更新实时更新?

    原文:https://blog.csdn.net/zhouweixue_vivi/article/details/78550738 2017年11月16日 14:22:50 zhouweixue_vi ...

  7. C#编写了一个基于Lucene.Net的搜索引擎查询通用工具类:SearchEngineUtil

    最近由于工作原因,一直忙于公司的各种项目(大部份都是基于spring cloud的微服务项目),故有一段时间没有与大家分享总结最近的技术研究成果的,其实最近我一直在不断的深入研究学习Spring.Sp ...

  8. java动态更新枚举类

    工作中遇到需要对枚举类的值进行动态更新 手动改不现实也不方便 现记录下来方便以后学习使用 1.在工程utils包中添加动态更新枚举类得工具类(根据自己得项目,放到指定位置调用就可以) 2.一开始陷入了 ...

  9. 模仿.NET框架ArrayList写一个自己的动态数组类MyArrayList,揭示foreach实现原理

    通过.NET反编译工具可以查看到ArrayList内部的代码,发现ArrayList并非由链表实现,而是由一个不断扩容的数组对象组成. 下面模仿ArrayList写一个自己的MyArrayList. ...

随机推荐

  1. weblogic jetty debug 远程

  2. struts2学习笔记之二:基本环境搭建

    学习struts2有一段时间了,作为一个运维人员学习的时间还是挺紧张的,写这篇文件为了方便以后复习时使用 环境: MyEclipse 10 tomcat6 jdk1.6   首先建立一个web项目,并 ...

  3. javaweb学习总结(七)——HttpServletResponse对象(一)

    Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的response对象.request和response对象即然代表请求和响应,那我们要 ...

  4. javaweb回顾第二篇tomcat和web程序部署

    前言这篇主要说下关于tomcat中一些属性和web程序的简单部署,可能在实际开发有更好的部署方式,但是这也是一个基础. 1:tomcat 关于tomcat估计只要接触java的人都听过这个名字,那我们 ...

  5. css之属性部分

    这篇写的是今天的学习到的属性,一共20个. 属性再多,但也要会使用,会在使用时可以记起它,才能起到它为我们所需要的作用. 样式属性 1.border CSS边框属性允许你指定一个元素边框的样式和颜色. ...

  6. python redis使用

    #!/usr/bin/python #coding=utf-8 import redis class CRedis: def __init__(self): self.host = 'localhos ...

  7. android: 接收和发送短信

    8.2    接收和发送短信 收发短信应该是每个手机最基本的功能之一了,即使是许多年前的老手机也都会具备这 项功能,而 Android 作为出色的智能手机操作系统,自然也少不了在这方面的支持.每个 A ...

  8. python matplotlib

    背景: 1)数据可视化 目前还处于python入门阶段,主要想通过numpy.matplotlib进行数据可视化. 安装: 操作系统:windows7 1)python2.7 安装numpy.matp ...

  9. C#代码像QQ的右下角消息框一样,无论现在用户的焦点在哪个窗口,消息框弹出后都不影响焦点的变化,那么有两种方法

    你QQ的右下角消息框一样,无论现在用户的焦点在哪个窗口,消息框弹出后都不影响焦点的变化,那么有两种方法: 要么重写需要弹出的窗体的事件: protected override CreateParams ...

  10. 用C#表达式树优雅的计算24点

    思路:一共4个数字,共需要3个运算符,可以构造一个二叉树,没有子节点的节点的为值,有叶子节点的为运算符 例如数字{1, 2, 3, 4},其中一种解的二叉树形式如下所示: 因此可以遍历所有二叉树可能的 ...