安徽新华电脑专修学院_安徽电脑培训_安徽电脑培训学校_合肥电脑培训

當(dāng)前位置:首頁(yè) > 網(wǎng)站舊欄目 > 學(xué)習(xí)園地 > 設(shè)計(jì)軟件教程 > Lucene應(yīng)用的一點(diǎn)體會(huì)

Lucene應(yīng)用的一點(diǎn)體會(huì)
2010-01-13 23:07:22  作者:  來(lái)源:
Lucene應(yīng)用(我用的是Lucene2.1.0,有些觀點(diǎn)有可能也不太正確)

1.多線程索引,共享同一個(gè)IndexWriter對(duì)象

這種方式效率很慢,主要原因是因?yàn)椋?br />
java 代碼
 
  1. public void addDocument(Document doc, Analyzer analyzer) throws IOException {  
  2. SegmentInfo newSegmentInfo = buildSingleDocSegment(doc, analyzer);  
  3. synchronized (this) {  
  4. ramSegmentInfos.addElement(newSegmentInfo);//這句很占用效率  
  5. maybeFlushRamSegments();  
  6. }  
  7. }  
ramSegmentInfos 是一個(gè)SegmentInfos 對(duì)象,這個(gè)對(duì)象extends Vector,Vector的addElement是同步的。這個(gè)可能是導(dǎo)致效率慢的主要原因吧.

2 多線程索引,  先寫(xiě)到RAMDirectory,再一次性寫(xiě)到FSDirectory

功能:首先向RAMDirectory里寫(xiě),當(dāng)達(dá)到1000個(gè)Document後,再向FSDirectory里寫(xiě)。

當(dāng)多線程執(zhí)行時(shí),會(huì)大量報(bào)java.lang.NullPointerException

自己寫(xiě)的多線程索引的類(lèi)為(IndexWriterServer,該對(duì)象只在Server啟動(dòng)時(shí)初始化一次):
 

代碼
  1. public class IndexWriterServer{  
  2. private static IndexWriter indexWriter = null;  
  3.       
  4.     //private String indexDir ;//索引目錄;  
  5.       
  6.     private static  CJKAnalyzer analyzer = null;  
  7.       
  8.     private static RAMDirectory ramDir = new RAMDirectory();  
  9.       
  10.     private static IndexWriter ramWriter = null;  
  11.       
  12.     private static int diskFactor = 0;//內(nèi)存中現(xiàn)在有多少Document  
  13.       
  14.     private static long ramToDistTime = 0;//內(nèi)存向硬盤(pán)寫(xiě)需要多少時(shí)間  
  15.       
  16.     private int initValue = 1000;//內(nèi)存中達(dá)到多少Document,才向硬盤(pán)寫(xiě)  
  17.       
  18.     private static IndexItem []indexItems = null;  
  19.       
  20.     public IndexWriterServer(String indexDir){  
  21.         initIndexWriter(indexDir);  
  22.     }  
  23.     public void initIndexWriter(String indexDir){  
  24.         boolean create = false;//是否創(chuàng)建新的  
  25.           
  26.         analyzer = new CJKAnalyzer();  
  27.           
  28.         Directory directory = this.getDirectory(indexDir);  
  29.         //判斷是否為索引目錄  
  30.         if(!IndexReader.indexExists(indexDir)){  
  31.             create = true;  
  32.         }  
  33.           
  34.         indexWriter = getIndexWriter(directory,create);  
  35.           
  36.         try{  
  37.             ramWriter = new IndexWriter(ramDir, analyzer, true);  
  38.         }catch(Exception e){  
  39.             logger.info(e);  
  40.         }  
  41.           
  42.         indexItems = new IndexItem[initValue+2];  
  43.     }  
  44.   
  45. /** 
  46.      * 生成單個(gè)Item索引 
  47.      */  
  48.     public boolean generatorItemIndex(IndexItem item, Current __current) throws DatabaseError, RuntimeError{  
  49.         boolean isSuccess = true;//是否索引成功  
  50.           
  51.         try{  
  52.               
  53.             Document doc = getItemDocument(item);  
  54.               
  55.             ramWriter.addDocument(doc);//關(guān)鍵代碼,錯(cuò)誤就是從這里報(bào)出來(lái)的  
  56.               
  57.             indexItems[diskFactor] = item;//為數(shù)據(jù)挖掘使用  
  58.             diskFactor ++;  
  59.             if((diskFactor % initValue) == 0){  
  60.                 ramToDisk(ramDir,ramWriter,indexWriter);  
  61.                 //ramWriter = new IndexWriter(ramDir, analyzer, true);  
  62.                 diskFactor = 0;  
  63.                   
  64.                 //數(shù)據(jù)挖掘  
  65.                 isSuccess = MiningData();  
  66.   
  67.                   
  68.             }  
  69.               
  70.             doc = null;  
  71.               
  72.   
  73.             logger.info("generator index item link:" + item.itemLink  +" success");  
  74.         }catch(Exception e){  
  75.             logger.info(e);  
  76.             e.printStackTrace();  
  77.       
  78.             logger.info("generator index item link:" + item.itemLink  +" faiture");  
  79.             isSuccess = false;  
  80.         }finally{  
  81.             item = null;  
  82.         }  
  83.           
  84.         return isSuccess;  
  85.     }  
  86.   
  87. public  void ramToDisk(RAMDirectory ramDir, IndexWriter ramWriter,IndexWriter writer){  
  88.         try{  
  89.             ramWriter.close();//關(guān)鍵代碼,把fileMap賦值為null了  
  90.             ramWriter = new IndexWriter(ramDir, analyzer, true);//重新構(gòu)建一個(gè)ramWriter對(duì)象。因?yàn)樗膄ileMap為null了,但是好像并沒(méi)有太大作用  
  91.             Directory ramDirArray[] = new Directory[1];  
  92.             ramDirArray[0] = ramDir;  
  93.             mergeDirs(writer, ramDirArray);  
  94.         }catch(Exception e){  
  95.             logger.info(e);  
  96.         }  
  97.     }  
  98.     /** 
  99.      * 將內(nèi)存里的索引信息寫(xiě)到硬盤(pán)里 
  100.      * @param writer 
  101.      * @param ramDirArray 
  102.      */   
  103.     public  void mergeDirs(IndexWriter writer,Directory[] ramDirArray){  
  104.         try {  
  105.             writer.addIndexes(ramDirArray);  
  106.             //optimize();  
  107.         } catch (IOException e) {  
  108.             logger.info(e);  
  109.         }  
  110.     }  
  111.       
  112. }  

主要原因大概是因?yàn)椋涸谡{(diào)用ramWriter.close();時(shí),Lucene2.1里RAMDirectory 的close()方法
 

代碼
  1. public final void close() {  
  2.    fileMap = null;  
  3.  }  

把fileMap 給置null了,當(dāng)多線程執(zhí)行ramWriter.addDocument(doc);時(shí),最終執(zhí)行RAMDirectory 的方法:
代碼
  1. public IndexOutput createOutput(String name) {  
  2.     RAMFile file = new RAMFile(this);  
  3.     synchronized (this) {  
  4.     RAMFile existing = (RAMFile)fileMap.get(name);//fileMap為null,所以報(bào):NullPointerException,  
  5.       if (existing!=null) {  
  6.         sizeInBytes -= existing.sizeInBytes;  
  7.         existing.directory = null;  
  8.       }  
  9.       fileMap.put(name, file);  
  10.     }  
  11.     return new RAMOutputStream(file);  
  12.   }  

提示:在網(wǎng)上搜索了一下,好像這個(gè)是lucene的一個(gè)bug(http://www.opensubscriber.com/message/java-user@lucene.apache.org/6227647.html),但是好像并沒(méi)有給出解決方案。


 

3.多線程索引,每個(gè)線程一個(gè)IndexWriter對(duì)象,每個(gè)IndexWriter 綁定一個(gè)FSDirectory對(duì)象。每個(gè)FSDirectory綁定一個(gè)本地的磁盤(pán)目錄(唯一的)。單獨(dú)開(kāi)辟一個(gè)線程出來(lái)監(jiān)控這些索引線程(監(jiān)控線程),也就是說(shuō)負(fù)責(zé)索引的線程索引完了以后,給這個(gè)監(jiān)控線程的queue里發(fā)送一個(gè)對(duì)象:queue.add(directory);,這個(gè)監(jiān)控現(xiàn)成的queue對(duì)象是個(gè)全局的。當(dāng)這個(gè)queue的size() > 20 時(shí),監(jiān)控線程 把這20個(gè)索引目錄合并(merge):indexWriter.addIndexes(dirs);//合并索引,合并到真正的索引目錄里。,合并完了以后,然后刪除掉這些已經(jīng)合并了的目錄。

但是這樣也有幾個(gè)bug:

a. 合并線程的速度 小于 索引線程的速度。導(dǎo)致 目錄越來(lái)越多

b.經(jīng)常會(huì)報(bào)一個(gè)類(lèi)似這樣的錯(cuò)誤:
 

2007-06-08 10:49:18 INFO [Thread-2] (IndexWriter.java:1070) - java.io.FileNotFoundException: /home/spider/luceneserver/merge/item_d28686afe01f365c5669e1f19a2492c8/_1.cfs (No such file or directory)
 


 

4.單線程索引,調(diào)幾個(gè)參數(shù)後,效率也非常快(索引一條信息大概在6-30 ms之間)。感覺(jué)一般的需求單線程就夠用了。這些參數(shù)如下:

   private int mergeFactor = 100;//磁盤(pán)里達(dá)到多少後會(huì)自動(dòng)合并
    private int maxMergeDocs = 1000;//內(nèi)存中達(dá)到多少會(huì)向磁盤(pán)寫(xiě)入
    private int minMergeDocs = 1000;//lucene2.0已經(jīng)取消了
    private int maxFieldLength = 2000;//索引的最大文章長(zhǎng)度
    private int maxBufferedDocs = 10000;//這個(gè)參數(shù)不能要,要不然不會(huì)自動(dòng)合并了


得出的結(jié)論是:Lucene的多線程索引會(huì)有些問(wèn)題,如果沒(méi)有特殊需求,單線程的效率幾乎就能滿足需求.


 

如果單線程的速度滿足不了你的需求,你可以多開(kāi)幾個(gè)應(yīng)用。每個(gè)應(yīng)用都綁定一個(gè)FSDirectory,然后通過(guò)search時(shí)通過(guò)RMI去這些索引目錄進(jìn)行搜索。

RMI Server端,關(guān)鍵性代碼:


 

 

java 代碼
  1. private void initRMI(){  
  2.         //第一安全配置  
  3.         if (System.getSecurityManager() == null) {  
  4.             System.setSecurityManager( new RMISecurityManager() );  
  5.         }  
  6.         //注冊(cè)  
  7.         startRMIRegistry(serverUrl);  
  8.           
  9.         SearcherWork searcherWork = new SearcherWork("//" + serverUrl + "/" + bindName, directory);  
  10.           
  11.         searcherWork.run();  
  12.           
  13.     }  
  14.   
  15. public class SearcherWork  {  
  16. //   Logger  
  17.     private static Logger logger = Logger.getLogger(SearcherWork.class);  
  18.     private String serverUrl =null;  
  19.     private Directory directory =null;  
  20.   
  21.     public SearcherWork(){  
  22.           
  23.     }  
  24.       
  25.     public SearcherWork(String serverUrl, Directory directory){  
  26.         this.serverUrl = serverUrl;  
  27.         this.directory = directory;  
  28.     }  
  29.       
  30.     public void run(){  
  31.         try{  
  32.              Searchable searcher = new IndexSearcher(directory);  
  33.              SearchService service = new SearchService(searcher);  
  34.              Naming.rebind(serverUrl, service);  
  35.              logger.info("RMI Server bind " + serverUrl + " success");  
  36.               
  37.         }catch(Exception e){  
  38.             logger.info(e);  
  39.             System.out.println(e);  
  40.         }  
  41.     }  
  42.       
  43.   
  44. }  
  45.   
  46. public class SearchService extends RemoteSearchable implements Searchable {  
  47.       
  48.     public SearchService (Searchable local) throws RemoteException {  
  49.         super(local);  
  50.     }  
  51. }  

客戶(hù)端關(guān)鍵性代碼:

 

java 代碼
 
  1. RemoteLuceneConnector rlc= new RemoteLuceneConnector();  
  2. RemoteSearchable[] rs= rlc.getRemoteSearchers();  
  3. MultiSearcher multi = new MultiSearcher(rs);  
  4. Hits hits = multi.search(new TermQuery(new Term("content","中國(guó)")));  

 


安徽新華電腦學(xué)校專(zhuān)業(yè)職業(yè)規(guī)劃師為你提供更多幫助【在線咨詢(xún)
主站蜘蛛池模板: 全自动视觉点胶机|在线式点胶机|精密点胶阀设备厂家-杭州迈伺特科技有限公司 | 西安外墙防水补漏-堵漏-防腐-保温工程公司-陕西宏图祥瑞实业有限公司 | 美国SI中国区总代-北京开源国创科技有限公司 | 无锡市一格机械设备有限公司【官网】 | 硬脂酸钡_硬脂酸镁_硬脂酸镉_硬脂酸铝_硬脂酸锌-石家庄中石恒达矿产品有限公司 | 江寒必恋术在线阅读_江寒必恋术免费下载 - 江寒必恋术电子书 | 手板模型-温州手板模-快速成型厂家-温州星科模具加工厂 | 江西铭鑫冶金设备有限公司-破碎机,铜米机,选矿摇床,电池回收设备 | 卧螺离心机-固液分离机-台州春鼎机械制造有限公司 | 深圳市碧源达科技有限公司| 铝型材定制_东莞铝型材_散热器铝型材_工业铝合金型材挤压加工生产厂家价格-中亚铝业 | 深圳市中控智能科技有限公司 | 苏州拆除公司_太仓拆除公司_常熟拆除公司_昆山拆除公司--苏州伊诺尔拆除工程有限公司 | 辽宁大卯新能源供热设备制造有限公司官方网站,大卯新能源,大卯新能源供热设备 | 透明捆扎带_束带机打包带_束带机纸带_热封纸带机_上海得亿束带机包装材料有限公司 | 呕吐毒素快速检测仪-黄曲霉毒素测定仪-玉米赤霉烯酮快速检测卡-南京微测生物科技有限公司 | 义乌供需网-义乌外发加工来料加工,义乌采购信息供求对接平台(yiwugongxu.com) | 一体式电磁流量计_分体式电磁流量计_卫生级电磁流量计_卫生型电磁流量计_电池供电电磁流量计_卡箍式电磁流量计_废水电磁流量计_德克森仪表(淮安)有限公司官网 | 输送机电动滚筒_山东电动滚筒_输送机滚筒_皮带输送机-山东中输输送机械有限公司 | 前海卡的物联智能技术(深圳)有限公司 | 河南三特炉业科技有限公司| 铸造厂-铸铝-铸铜-铝合金铸造-重力铸造-翻砂铸造-[剑锋机械配件]专业东莞|深圳铸造厂 | 形创(CREAFORM)3D扫描仪|三维检测|三维数字化处理|3D设备租赁|3D打印|——北京中显恒业仪器仪表有限公司 | 耐磨涂料_陶瓷涂料_高温涂料_高硬度耐磨涂料-北京耐默科技 | 兰州钢结构,甘肃铝镁锰板工程,青海岩棉复合板厂家,宁夏岩棉彩钢板公司,西宁彩钢夹芯板-兰州腾达彩钢 | 秦皇岛图成玻璃_横切机,琴键落板,堆垛机械手,玻璃钢化设备,掰边机,铺纸机,水平堆垛机+超大板堆垛机,纵掰纵分,下片机,冷端优化切割 | 膨胀节_波纹膨胀节_非金属膨胀节_波纹管补偿器_膨胀节厂家-江苏苏创管业科技有限公司 | 济南手板_山东快速成型-山东嘉瑞杰机械科技有限公司 | 深圳市大业激光成型技术有限公司| 数控立式车铣复合加工中心_数控立车_卧式加工中心_阀门专机-华电数控 | 智能档案柜,回转柜,密集架,密集柜厂家-北京及尚智能家具 | 久久91精品久久91综合_国产亚洲自拍一区_国产精品第1页_亚洲高清视频一区_91成人午夜在线精品_亚洲国产精品网站在线播放_亚洲国产成人久久综合区_国产精品亚洲专区在线观看_免费视频精品一区二区三区 | 楼宇门厂家-氟碳漆门-不锈钢大门-单元门-锌合金大门-永康市龙卫门业 | 英格索兰空压机_英格索兰空压机配件_英格索兰空压机维修—商天机械 | 硬度计,里氏硬度计,布氏硬度计,高强螺栓检测仪,平板导热仪,专业无损检测仪器商-北京时代新天测控技术有限公司-北京时代新天测控技术有限公司 | 苏州氮气弹簧厂家_江浙沪氮气弹簧价格_江苏氮气弹簧规格_BelleFlex碟形弹簧_昆山三虑五金机械有限公司 | 上海浩斌信息科技有限公司RFID读写器,IC卡读卡器,手持机,数据采集终端,电力仓库管理软件开发,固定资产软件,纱管标签,试剂管理,RFID试剂柜,档案管理,档案柜,智能货架 | 山东汇河环保科技集团有限公司,水囊水袋,水罐,油囊,预压水袋,吊重水袋_山东汇河环保科技集团有限公司,水囊水袋,水罐,油囊,预压水袋,吊重水袋 | 全地形消防摩托车_背负式细水雾_全氟己酮灭火装置「斯库尔消防」 | 天猫代运营_淘宝代运营_正规电商代运营公司_武汉火蝠电商 | 联动机-钻井转盘-滑动游车-河南思达瑞石油机械制造有限公司 |