<source id="4vppl"><ins id="4vppl"></ins></source>
<u id="4vppl"><sub id="4vppl"><label id="4vppl"></label></sub></u>
<object id="4vppl"></object>
  • <u id="4vppl"><li id="4vppl"><label id="4vppl"></label></li></u>

    <object id="4vppl"></object>
    <b id="4vppl"><sub id="4vppl"><tr id="4vppl"></tr></sub></b>

      <i id="4vppl"><thead id="4vppl"></thead></i>

      <thead id="4vppl"><li id="4vppl"><label id="4vppl"></label></li></thead>

      當前位置:首頁 > 網站舊欄目 > 學習園地 > 設計軟件教程 > Lucene應用的一點體會

      Lucene應用的一點體會
      2010-01-13 23:07:22  作者:  來源:
      Lucene應用(我用的是Lucene2.1.0,有些觀點有可能也不太正確)

      1.多線程索引,共享同一個IndexWriter對象

      這種方式效率很慢,主要原因是因為:

      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 是一個SegmentInfos 對象,這個對象extends Vector,Vector的addElement是同步的。這個可能是導致效率慢的主要原因吧.

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

      功能:首先向RAMDirectory里寫,當達到1000個Document後,再向FSDirectory里寫。

      當多線程執行時,會大量報java.lang.NullPointerException

      自己寫的多線程索引的類為(IndexWriterServer,該對象只在Server啟動時初始化一次):
       

      代碼
      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;//內存中現在有多少Document  
      13.       
      14.     private static long ramToDistTime = 0;//內存向硬盤寫需要多少時間  
      15.       
      16.     private int initValue = 1000;//內存中達到多少Document,才向硬盤寫  
      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;//是否創建新的  
      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.      * 生成單個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);//關鍵代碼,錯誤就是從這里報出來的  
      56.               
      57.             indexItems[diskFactor] = item;//為數據挖掘使用  
      58.             diskFactor ++;  
      59.             if((diskFactor % initValue) == 0){  
      60.                 ramToDisk(ramDir,ramWriter,indexWriter);  
      61.                 //ramWriter = new IndexWriter(ramDir, analyzer, true);  
      62.                 diskFactor = 0;  
      63.                   
      64.                 //數據挖掘  
      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();//關鍵代碼,把fileMap賦值為null了  
      90.             ramWriter = new IndexWriter(ramDir, analyzer, true);//重新構建一個ramWriter對象。因為它的fileMap為null了,但是好像并沒有太大作用  
      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.      * 將內存里的索引信息寫到硬盤里 
      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. }  

      主要原因大概是因為:在調用ramWriter.close();時,Lucene2.1里RAMDirectory 的close()方法
       

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

      把fileMap 給置null了,當多線程執行ramWriter.addDocument(doc);時,最終執行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,所以報: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.   }  

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


       

      3.多線程索引,每個線程一個IndexWriter對象,每個IndexWriter 綁定一個FSDirectory對象。每個FSDirectory綁定一個本地的磁盤目錄(唯一的)。單獨開辟一個線程出來監控這些索引線程(監控線程),也就是說負責索引的線程索引完了以后,給這個監控線程的queue里發送一個對象:queue.add(directory);,這個監控現成的queue對象是個全局的。當這個queue的size() > 20 時,監控線程 把這20個索引目錄合并(merge):indexWriter.addIndexes(dirs);//合并索引,合并到真正的索引目錄里。,合并完了以后,然后刪除掉這些已經合并了的目錄。

      但是這樣也有幾個bug:

      a. 合并線程的速度 小于 索引線程的速度。導致 目錄越來越多

      b.經常會報一個類似這樣的錯誤:
       

      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.單線程索引,調幾個參數後,效率也非?(索引一條信息大概在6-30 ms之間)。感覺一般的需求單線程就夠用了。這些參數如下:

         private int mergeFactor = 100;//磁盤里達到多少後會自動合并
          private int maxMergeDocs = 1000;//內存中達到多少會向磁盤寫入
          private int minMergeDocs = 1000;//lucene2.0已經取消了
          private int maxFieldLength = 2000;//索引的最大文章長度
          private int maxBufferedDocs = 10000;//這個參數不能要,要不然不會自動合并了


      得出的結論是:Lucene的多線程索引會有些問題,如果沒有特殊需求,單線程的效率幾乎就能滿足需求.


       

      如果單線程的速度滿足不了你的需求,你可以多開幾個應用。每個應用都綁定一個FSDirectory,然后通過search時通過RMI去這些索引目錄進行搜索。

      RMI Server端,關鍵性代碼:


       

       

      java 代碼
      1. private void initRMI(){  
      2.         //第一安全配置  
      3.         if (System.getSecurityManager() == null) {  
      4.             System.setSecurityManager( new RMISecurityManager() );  
      5.         }  
      6.         //注冊  
      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. }  

      客戶端關鍵性代碼:

       

      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","中國")));  

       


      安徽新華電腦學校專業職業規劃師為你提供更多幫助【在線咨詢
      国产午夜福三级在线播放_亚洲精品成a人片在线观看_亚洲自慰一区二区三区_久久棈精品久久久久久噜噜
      <source id="4vppl"><ins id="4vppl"></ins></source>
      <u id="4vppl"><sub id="4vppl"><label id="4vppl"></label></sub></u>
      <object id="4vppl"></object>
    1. <u id="4vppl"><li id="4vppl"><label id="4vppl"></label></li></u>

      <object id="4vppl"></object>
      <b id="4vppl"><sub id="4vppl"><tr id="4vppl"></tr></sub></b>

        <i id="4vppl"><thead id="4vppl"></thead></i>

        <thead id="4vppl"><li id="4vppl"><label id="4vppl"></label></li></thead>
        中文字幕在线视频观看 | 中文字幕国产第一页首页 | 五月婷婷亞洲綜合色色 | 亚洲有码在线播放 | 婷婷亚洲综合五月天小说 | 亚洲人成电影在线播 |