分享

基于lucene的案例开发14:实时索引管理类IndexManager

gefieder 2015-4-14 16:51:13 发表于 连载型 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 0 18092
本帖最后由 nettman 于 2015-4-16 22:39 编辑
问题导读:
1、如何利用lucene来实现索引的管理?
2、如何实现索引的单例模式?
3、内存重读线程的配置参数如何配置?




接上篇:基于lucene的案例开发13:实现实时索引基本原理

在前一篇博客中,对实时索引的实现原理做了一些简单的介绍,这里就介绍下,如何利用Lucene来实现索引的管理(Lucene中已经实现了大部分的功能,我们只需要对其再次封装即可)。

逐个击破

      在Lucene4.3.1中,实现实时索引时,需要将IndexWrite的相关操作委托给TrackingIndexWriter来处理,具体代码实现如下:

ps:关于如何创建索引这里就不再介绍了,可以参照之前的博客或者该博客后面的完整代码。

  1. this.trackingIndexWriter = new TrackingIndexWriter(this.indexWriter);  
复制代码
同时初始化索引管理对象,代码如下:
  1. this.nrtManager = new NRTManager(this.trackingIndexWriter, new SearcherFactory());   
复制代码
     到这里还需要开启两个守护线程:内存索引重读线程和内存数据commit线程。内存索引重读线程执行的频率也就是实时索引的时差,由于内存中的数据不会太多,所以这个延时一般也就是在十几毫秒左右;内存数据commit线程是将内存中的数据写到磁盘上,不至于数据丢失,如果研究过Lucene源码的童鞋也许会发现,即使你不执行commit操作,到内存中的数据达到一定的程度,也会将一部分数据写到磁盘上,只不过重启服务这部分数据就丢失了同时还会造成一系列的问题, 这个地址下就是commit线程死掉之后造成的一系列问题,感兴趣的童鞋可以了解下。      内存重读线程我们只需要配置下参数启动即可,代码如下:

  1.     this.nrtManagerReopenThread = new NRTManagerReopenThread(this.nrtManager, indexReopenMaxStaleSec, indexReopenMinStaleSec);  
  2.     this.nrtManagerReopenThread.setName("NRTManager Reopen Thread");  
  3.     this.nrtManagerReopenThread.setPriority(Math.min(Thread.currentThread().getPriority()+2, Thread.MAX_PRIORITY));  
  4.     this.nrtManagerReopenThread.setDaemon(true);  
  5.     this.nrtManagerReopenThread.start();  
复制代码
     内存数据commit线程需要自己写代码实现,然后启动该线程即可,代码如下:
  1.     private class IndexCommitThread extends Thread{  
  2.         private boolean flag;  
  3.         public IndexCommitThread(String name){  
  4.             super(name);  
  5.         }  
  6.          
  7.         @SuppressWarnings("deprecation")  
  8.         public void run(){  
  9.             flag = true;  
  10.             while(flag) {  
  11.                 try {  
  12.                     indexWriter.commit();  
  13.                     if (bprint) {  
  14.                         System.out.println(new Date().toLocaleString() + "\t" + IndexManagerName + "\tcommit");  
  15.                     }  
  16.                     TimeUnit.SECONDS.sleep(indexCommitSeconds);  
  17.                 } catch (IOException e) {  
  18.                     e.printStackTrace();  
  19.                 } catch (InterruptedException e1) {  
  20.                     e1.printStackTrace();  
  21.                 }  
  22.             }  
  23.         }  
  24.     }  
复制代码
  1.     this.indexCommitThread = new IndexCommitThread(IndexManagerName + "Index Commit Thread");  
  2.     this.indexCommitThread.setDaemon(true);  
  3.     this.indexCommitThread.start();  
复制代码
     那又如何像普通的索引那样使用IndexSearcher呢?当然NrtManager类也提供了相关的方法,可以获取最新可用的IndexSearcher,代码如下:
  1.     public IndexSearcher getIndexSearcher(){  
  2.         try {  
  3.             return this.nrtManager.acquire();  
  4.         } catch (IOException e) {  
  5.             e.printStackTrace();  
  6.             return null;  
  7.         }  
  8.     }  
复制代码
     当然在使用之后别忘记释放,代码如下:
  1.     public void release(IndexSearcher searcher){  
  2.         try {  
  3.             nrtManager.release(searcher);  
  4.         } catch (IOException e) {  
  5.             // TODO Auto-generated catch block   
  6.             e.printStackTrace();  
  7.         }  
  8.     }  
复制代码

另类单例模式

      在之前的博客中,我也多次提到,加载索引是一个相当消耗资源的事情,所以我们不可能每一次索引操作都加载一次索引,所以我们就必须使用单例模式来实现IndexManager类。这里的单例模式又和我们常见的单例模式有所区别,普通的单例模式该类只有一个对象,这里的单例模式是该类有多个对象,下面就简单的介绍下此处另类的单例模式。
      通过前一篇博客最后,你也许会注意到,系统中关于索引的配置信息是存在HashSet对象中,这也就是说这里IndexManager类会实例化多少次取决于HashSet对象,也就是你配置文件让他实例化多少次就会实例化多少次。既然这样,怎么还能叫单例模式呢?这里的单例是索引的单例,也就是说一个索引只有一个IndexManager对象,不会存在两个IndexManager对象去操作同一个索引的情况。具体代码实现如下:
  1.     /**
  2.      * Initialization on Demand Holder式初始化IndexManager
  3.      */  
  4.     private static class LazyLoadIndexManager {  
  5.         private static final HashMap<String, IndexManager> indexManager = new HashMap<String, IndexManager>();  
  6.          
  7.         static {  
  8.             for (ConfigBean configBean : IndexConfig.getConfigBean()) {  
  9.                 indexManager.put(configBean.getIndexName(), new IndexManager(configBean));  
  10.             }  
  11.         }  
  12.     }  
  13.       
  14.     /**   
  15.      *@Description: IndexManager私有构造方法
  16.      *@Author: lulei   
  17.      *@Version: 1.1.0   
  18.      */  
  19.     private IndexManager(ConfigBean configBean){  
  20.         //...  
  21.     }  
  22.     public static IndexManager getIndexManager(String indexName){  
  23.         return LazyLoadIndexManager.indexManager.get(indexName);  
  24.     }  
复制代码
     这样我们就可以通过索引名获取到该索引的IndexManager对象。

庐山真面目

      说了这么多,下面就把IndexManager的源码附在最后,感兴趣的童鞋可以试试(里面还有一些其他的方法,相信不用介绍也都可以看的懂)
  1.      /**   
  2.      *@Description: 索引管理类   
  3.      */   
  4.     package com.lulei.lucene.index.manager;   
  5.       
  6.     import java.io.File;  
  7.     import java.io.IOException;  
  8.     import java.util.Date;  
  9.     import java.util.HashMap;  
  10.     import java.util.concurrent.TimeUnit;  
  11.       
  12.     import org.apache.lucene.analysis.Analyzer;  
  13.     import org.apache.lucene.index.IndexWriter;  
  14.     import org.apache.lucene.index.IndexWriterConfig;  
  15.     import org.apache.lucene.index.IndexWriterConfig.OpenMode;  
  16.     import org.apache.lucene.search.IndexSearcher;  
  17.     import org.apache.lucene.search.NRTManager;  
  18.     import org.apache.lucene.search.NRTManager.TrackingIndexWriter;  
  19.     import org.apache.lucene.search.NRTManagerReopenThread;  
  20.     import org.apache.lucene.search.SearcherFactory;  
  21.     import org.apache.lucene.store.Directory;  
  22.     import org.apache.lucene.store.NIOFSDirectory;  
  23.     import org.apache.lucene.util.Version;  
  24.       
  25.     import com.lulei.lucene.index.model.ConfigBean;  
  26.     import com.lulei.lucene.index.model.IndexConfig;  
  27.       
  28.     public class IndexManager {  
  29.       
  30.         private IndexWriter indexWriter;  
  31.         //更新索引文件的IndexWriter  
  32.         private TrackingIndexWriter trackingIndexWriter;  
  33.         //索引文件采用的分词器  
  34.         private Analyzer analyzer;  
  35.         //索引管理对象  
  36.         private NRTManager nrtManager;  
  37.         //索引重读线程  
  38.         private NRTManagerReopenThread nrtManagerReopenThread;  
  39.         //索引写入磁盘线程  
  40.         private IndexCommitThread indexCommitThread;  
  41.          
  42.         //索引地址  
  43.         private String indexPath;  
  44.         //索引重读最大、最小时间间隔  
  45.         private double indexReopenMaxStaleSec;  
  46.         private double indexReopenMinStaleSec;  
  47.         //索引commit时间  
  48.         private int indexCommitSeconds;  
  49.         //索引名  
  50.         private String IndexManagerName;  
  51.         //commit时是否输出相关信息  
  52.         private boolean bprint = true;  
  53.          
  54.         /**
  55.          * Initialization on Demand Holder式初始化IndexManager
  56.          */  
  57.         private static class LazyLoadIndexManager {  
  58.             private static final HashMap<String, IndexManager> indexManager = new HashMap<String, IndexManager>();  
  59.               
  60.             static {  
  61.                 for (ConfigBean configBean : IndexConfig.getConfigBean()) {  
  62.                     indexManager.put(configBean.getIndexName(), new IndexManager(configBean));  
  63.                 }  
  64.             }  
  65.         }  
  66.          
  67.         /**   
  68.          *@Description: IndexManager私有构造方法
  69.          *@Author: lulei   
  70.          *@Version: 1.1.0   
  71.          */  
  72.         private IndexManager(ConfigBean configBean){  
  73.             //设置相关属性  
  74.             analyzer = configBean.getAnalyzer();  
  75.             indexPath = configBean.getIndexPath();  
  76.             IndexManagerName = configBean.getIndexName();  
  77.             indexReopenMaxStaleSec = configBean.getIndexReopenMaxStaleSec();  
  78.             indexReopenMinStaleSec = configBean.getIndexReopenMinStaleSec();  
  79.             indexCommitSeconds = configBean.getIndexCommitSeconds();  
  80.             bprint = configBean.isBprint();  
  81.             String indexFile = indexPath + IndexManagerName + "/";  
  82.             //创建或打开索引  
  83.             IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_43, analyzer);  
  84.             indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);  
  85.             Directory directory = null;  
  86.             try {  
  87.                 directory = NIOFSDirectory.open(new File(indexFile));  
  88.                 if (IndexWriter.isLocked(directory)){  
  89.                     IndexWriter.unlock(directory);  
  90.                 }  
  91.                 this.indexWriter = new IndexWriter(directory, indexWriterConfig);  
  92.                 this.trackingIndexWriter = new TrackingIndexWriter(this.indexWriter);  
  93.                 this.nrtManager = new NRTManager(this.trackingIndexWriter, new SearcherFactory());  
  94.             } catch(IOException e){  
  95.                 e.printStackTrace();  
  96.             }  
  97.             //开启守护进程  
  98.             this.setThread();  
  99.         }  
  100.         /**
  101.          * @Author: lulei   
  102.          * @Description: 创建索引管理线程
  103.          */  
  104.         private void setThread(){  
  105.             this.nrtManagerReopenThread = new NRTManagerReopenThread(this.nrtManager, indexReopenMaxStaleSec, indexReopenMinStaleSec);  
  106.             this.nrtManagerReopenThread.setName("NRTManager Reopen Thread");  
  107.             this.nrtManagerReopenThread.setPriority(Math.min(Thread.currentThread().getPriority()+2, Thread.MAX_PRIORITY));  
  108.             this.nrtManagerReopenThread.setDaemon(true);  
  109.             this.nrtManagerReopenThread.start();  
  110.               
  111.             this.indexCommitThread = new IndexCommitThread(IndexManagerName + "Index Commit Thread");  
  112.             this.indexCommitThread.setDaemon(true);  
  113.             this.indexCommitThread.start();  
  114.         }  
  115.          
  116.         /**
  117.          * @return
  118.          * @Author:lulei   
  119.          * @Description: 重启索引commit线程
  120.          */  
  121.         public String setCommitThread() {  
  122.             try {  
  123.                 if (this.indexCommitThread.isAlive()){  
  124.                     return "is alive";  
  125.                 }  
  126.                 this.indexCommitThread = new IndexCommitThread(IndexManagerName + "Index Commit Thread");  
  127.                 this.indexCommitThread.setDaemon(true);  
  128.                 this.indexCommitThread.start();  
  129.             } catch (Exception e) {  
  130.                 e.printStackTrace();  
  131.                 return "failed";  
  132.             }  
  133.             return "reload";  
  134.         }  
  135.          
  136.         /**
  137.          *@Description: 索引commit线程  
  138.          *@Author: lulei   
  139.          *@Version: 1.1.0
  140.          */  
  141.         private class IndexCommitThread extends Thread{  
  142.             private boolean flag;  
  143.             public IndexCommitThread(String name){  
  144.                 super(name);  
  145.             }  
  146.               
  147.             @SuppressWarnings("deprecation")  
  148.             public void run(){  
  149.                 flag = true;  
  150.                 while(flag) {  
  151.                     try {  
  152.                         indexWriter.commit();  
  153.                         if (bprint) {  
  154.                             System.out.println(new Date().toLocaleString() + "\t" + IndexManagerName + "\tcommit");  
  155.                         }  
  156.                         TimeUnit.SECONDS.sleep(indexCommitSeconds);  
  157.                     } catch (IOException e) {  
  158.                         e.printStackTrace();  
  159.                     } catch (InterruptedException e1) {  
  160.                         e1.printStackTrace();  
  161.                     }  
  162.                 }  
  163.             }  
  164.         }  
  165.          
  166.          
  167.         /**
  168.          * @return IndexManager
  169.          * @Author: lulei   
  170.          * @Description: 获取索引管理类
  171.          */  
  172.         public static IndexManager getIndexManager(String indexName){  
  173.             return LazyLoadIndexManager.indexManager.get(indexName);  
  174.         }  
  175.          
  176.         /**
  177.          * @@Description:释放IndexSearcher资源
  178.          * @param searcher
  179.          */  
  180.         public void release(IndexSearcher searcher){  
  181.             try {  
  182.                 nrtManager.release(searcher);  
  183.             } catch (IOException e) {  
  184.                 // TODO Auto-generated catch block   
  185.                 e.printStackTrace();  
  186.             }  
  187.         }  
  188.          
  189.         /**
  190.          * @return IndexSearcher
  191.          * @Author: lulei   
  192.          * @Description: 返回IndexSearcher对象,使用完之后,调用release方法进行释放
  193.          */  
  194.         public IndexSearcher getIndexSearcher(){  
  195.             try {  
  196.                 return this.nrtManager.acquire();  
  197.             } catch (IOException e) {  
  198.                 e.printStackTrace();  
  199.                 return null;  
  200.             }  
  201.         }  
  202.          
  203.         public NRTManager getNRTManager(){  
  204.             return this.nrtManager;  
  205.         }  
  206.          
  207.         public IndexWriter getIndexWriter(){  
  208.             return this.indexWriter;  
  209.         }  
  210.          
  211.         public TrackingIndexWriter getTrackingIndexWriter(){  
  212.             return this.trackingIndexWriter;  
  213.         }  
  214.          
  215.         public Analyzer getAnalyzer(){  
  216.             return analyzer;  
  217.         }  
  218.          
  219.         /**
  220.          * @return
  221.          * @Author: lulei   
  222.          * @Description: 获取索引中的记录条数
  223.          */  
  224.         public int getIndexNum(){  
  225.             return indexWriter.numDocs();  
  226.         }  
  227.     }  
复制代码



相关内容:
基于lucene的案例开发1:lucene初始认知

基于lucene的案例开发2:索引数学模型

基于lucene的案例开发3:索引文件结构

基于lucene的案例开发4:创建索引

基于lucene的案例开发5:搜索索引

基于lucene的案例开发6:分词器介绍

基于lucene的案例开发7:Query查询

基于lucene的案例开发8:IndexSearcher中检索方法

基于lucene的案例开发9:案例初识

基于lucene的案例开发10:搜索后台基础,JsonUtil & XmlUtil类介绍

基于lucene的案例开发11:项目常用类ClassUtil & CharsetUtil介绍

基于lucene的案例开发12:数据库连接池

基于lucene的案例开发13:实现实时索引基本原理

基于lucene的案例开发14:实时索引管理类IndexManager

基于lucene的案例开发15:实时索引的检索

基于lucene的案例开发16:实时索引的修改

基于lucene的案例开发17:查询语句创建PackQuery

基于lucene的案例开发18:纵横小说更新列表页抓取

基于lucene的案例开发19:纵横小说简介页采集

基于lucene的案例开发20:纵横小说章节列表采集

基于lucene的案例开发21:纵横小说阅读页采集
资料来源: http://blog.csdn.net/xiaojimanman/article/details/44015983

欢迎加入about云群371358502、39327136,云计算爱好者群,亦可关注about云腾讯认证空间||关注本站微信

没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条