论坛首页 Java版 企业应用

IndexWriter类addDocument效率问题

浏览 1005 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2007-06-05 关键字: IndexWriter类addDocument效率问题
IndexWriter类的方法:
public void addDocument(Document doc, Analyzer analyzer) throws IOException {
SegmentInfo newSegmentInfo = buildSingleDocSegment(doc, analyzer);
synchronized (this) {
ramSegmentInfos.addElement(newSegmentInfo);
maybeFlushRamSegments();
}
}

执行效率很慢,当我是把ramSegmentInfos.addElement(newSegmentInfo);这句注释後就很快(效率相差很大)。当是把maybeFlushRamSegments();这句注释掉,效率依然很慢。
所以 总的来说应该是ramSegmentInfos.addElement(newSegmentInfo);这句很占用效率,不知道怎么解释。该怎么解决呢?非常感谢。
   
最后更新时间:2007-06-05
应该说你的业务中核心是
ramSegmentInfos.addElement(newSegmentInfo);

而flushRam只是把内存清一下。。。。

你说你的核心逻辑效率差。。。。
又没给出你的数据,
也没给出你的理想值,
更没有测试用例。。。。
   
0 请登录后投票
最后更新时间:2007-06-05
功能:首先向RAMDirectory里写,当达到1000个Document後,再向FSDirectory里写。

当多线程执行时,会大量报java.lang.NullPointerException,有没有好的解决办法?

自己写的多线程索引的类为(IndexWriterServer,该对象只在Server启动时初始化一次):
public class IndexWriterServer{
private static IndexWriter indexWriter = null;
	
	//private String indexDir ;//索引目录;
	
	private static  CJKAnalyzer analyzer = null;
	
	private static RAMDirectory ramDir = new RAMDirectory();
	
	private static IndexWriter ramWriter = null;
	
	private static int diskFactor = 0;//内存中现在有多少Document
	
	private static long ramToDistTime = 0;//内存向硬盘写需要多少时间
	
	private int initValue = 1000;//内存中达到多少Document,才向硬盘写
	
	private static IndexItem []indexItems = null;
	
	public IndexWriterServer(String indexDir){
		initIndexWriter(indexDir);
	}
	public void initIndexWriter(String indexDir){
		boolean create = false;//是否创建新的
		
		analyzer = new CJKAnalyzer();
		
		Directory directory = this.getDirectory(indexDir);
		//判断是否为索引目录
		if(!IndexReader.indexExists(indexDir)){
			create = true;
		}
		
		indexWriter = getIndexWriter(directory,create);
		
		try{
			ramWriter = new IndexWriter(ramDir, analyzer, true);
		}catch(Exception e){
			logger.info(e);
		}
		
		indexItems = new IndexItem[initValue+2];
	}

/**
	 * 生成单个Item索引
	 */
	public boolean generatorItemIndex(IndexItem item, Current __current) throws DatabaseError, RuntimeError{
		boolean isSuccess = true;//是否索引成功
		
		try{
			
			Document doc = getItemDocument(item);
			
			ramWriter.addDocument(doc);//关键代码,错误就是从这里报出来的
			
			indexItems[diskFactor] = item;//为数据挖掘使用
			diskFactor ++;
			if((diskFactor % initValue) == 0){
				ramToDisk(ramDir,ramWriter,indexWriter);
				//ramWriter = new IndexWriter(ramDir, analyzer, true);
				diskFactor = 0;
				
				//数据挖掘
				isSuccess = MiningData();

				
			}
			
			doc = null;
			

			logger.info("generator index item link:" + item.itemLink  +" success");
		}catch(Exception e){
			logger.info(e);
			e.printStackTrace();
	
			logger.info("generator index item link:" + item.itemLink  +" faiture");
			isSuccess = false;
		}finally{
			item = null;
		}
		
		return isSuccess;
	}

public  void ramToDisk(RAMDirectory ramDir, IndexWriter ramWriter,IndexWriter writer){
		try{
			ramWriter.close();//关键代码,把fileMap赋值为null了
			ramWriter = new IndexWriter(ramDir, analyzer, true);//重新构建一个ramWriter对象。因为它的fileMap为null了,但是好像并没有太大作用
			Directory ramDirArray[] = new Directory[1];
			ramDirArray[0] = ramDir;
			mergeDirs(writer, ramDirArray);
		}catch(Exception e){
			logger.info(e);
		}
	}
	/**
	 * 将内存里的索引信息写到硬盘里
	 * @param writer
	 * @param ramDirArray
	 */	
	public  void mergeDirs(IndexWriter writer,Directory[] ramDirArray){
		try {
			writer.addIndexes(ramDirArray);
			//optimize();
		} catch (IOException e) {
			logger.info(e);
		}
	}
	
}


主要原因大概是因为:在调用ramWriter.close();时,Lucene2.1里RAMDirectory 的close()方法
 public final void close() {
    fileMap = null;
  }

把fileMap 给置null了,当多线程执行ramWriter.addDocument(doc);时,最终执行RAMDirectory 的方法:
public IndexOutput createOutput(String name) {
    RAMFile file = new RAMFile(this);
    synchronized (this) {
    RAMFile existing = (RAMFile)fileMap.get(name);//fileMap为null,所以报:NullPointerException,
      if (existing!=null) {
        sizeInBytes -= existing.sizeInBytes;
        existing.directory = null;
      }
      fileMap.put(name, file);
    }
    return new RAMOutputStream(file);
  }



提示:在网上搜索了一下,好像这个是lucene的一个bug(http://www.opensubscriber.com/message/java-user@lucene.apache.org/6227647.html),但是好像并没有给出解决方案。
   
0 请登录后投票
最后更新时间:2007-06-05
建议用监控线程来维护merge indeces、IndexWriter的instances,工作线程仅仅提供劳动力,一个thread维护一个IndexWriter的instance,应该可以避免类似的问题。

SegmentInfo继承自Vector,这意味着SegmentInfo的大部分操作是同步的,多线程操作SegmentInfo基本没有多少性能提升,没做过这个实验,提供这个思路给楼主参考一下。
   
0 请登录后投票
最后更新时间:2007-06-07
谢谢指点
   
0 请登录后投票
论坛首页 Java版 企业应用

跳转论坛:
JavaEye推荐