`
ttitfly
  • 浏览: 623280 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Lucene应用的一点体会

阅读更多
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. }  
<script type="text/javascript">render_code();</script>

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

代码
  1. public final void close() {  
  2.    fileMap = null;  
  3.  }  
<script type="text/javascript">render_code();</script>
把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.   }  
<script type="text/javascript">render_code();</script>

提示:在网上搜索了一下,好像这个是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","中国")));  

 


分享到:
评论
5 楼 yfmine 2007-06-12  
引用

private int maxMergeDocs = 1000;//内存中达到多少会向磁盘写入

Determines the largest number of documents ever merged by addDocument().

引用

    private int minMergeDocs = 1000;//lucene2.0已经取消了
    private int maxBufferedDocs = 10000;//这个参数不能要,要不然不会自动合并了

minMergeDocs没有取消,就是改成setMaxBufferedDocs了。

引用

ramWriter = new IndexWriter(ramDir, analyzer, true);//重新构建一个ramWriter对象。因为它的fileMap为null了,但是好像并没有太大作用 

lz你的代码有问题,这个是参数……

在实际中,我会用多线程开多个IndexWriter分别索引到不同的目录,IndexWriter被设计成线程安全的,有同步机制,多线程使用同一个IndexWriter,应该没有多大提高,和lz说的3比较类似,但通常不会合并(索引目录是按数据库表分的)。索引的速度和I/O关系比较大,要么是写入磁盘比较慢,要么是从数据源读取慢,通过调整maxBufferedDocs,写入索引文件这一端应该不会成为瓶颈。但调整到10000很可能服务器没那么大的内存。一般都是1000左右
4 楼 ttitfly 2007-06-11  
只是我个人测试的结果,有些地方不对请指点,请问restart错在什么地方?
3 楼 restart 2007-06-11  
楼主,光看你的第一点“多线程索引,共享同一个IndexWriter对象”就严重错误了!
2 楼 rtdb 2007-06-11  
支持一下楼主,这种个人应用上的体会,是有价值的。
1 楼 sg552 2007-06-11  
楼主想说些什么?


LUCENE到底是好?还是不好?
还是在普及LUCENE知识???

相关推荐

    lucene的应用程序扩展

    **Lucene 应用程序扩展在 ASP.NET 中的实践与应用** Lucene 是一个高性能、全文本搜索库,由 Apache 软件基金会开发。它提供了强大的搜索功能,被广泛应用于各种应用程序,包括网站、数据库和文档管理。在 ASP.NET ...

    Lucene在web项目中的应用

    **Lucene在Web项目中的应用** Lucene是一个高性能、全文本搜索库,由Apache软件基金会开发,它提供了完整的搜索解决方案,包括索引构建、搜索功能以及分词处理。在Java Web项目中,Lucene能够帮助开发者实现高效、...

    Lucene应用中Pdf文档文本数据提取方法研究

    在探讨“Lucene应用中Pdf文档文本数据提取方法研究”的主题下,我们深入研究了如何在基于Lucene的全文检索系统中高效处理和提取Pdf文档中的文本数据。Lucene作为一款开源的全文检索引擎,虽然提供了强大的全文检索...

    lucene 3.4基本应用

    **Lucene 3.4 基本应用详解** Lucene 是一个开源的全文搜索引擎库,由Apache软件基金会开发并维护。它提供了高效、可扩展的搜索功能,被广泛应用于各种信息检索系统。本篇文章将深入探讨Lucene 3.4版本的基础应用,...

    lucene高级应用

    《Lucene高级应用详解》 在信息技术领域,搜索引擎技术是数据检索的重要手段,而Apache Lucene作为开源全文搜索引擎库,以其高效、灵活的特点被广泛应用于各类项目中。本篇文章将深入探讨Lucene的高级应用,结合...

    Java全文检索引擎Lucene的应用.pdf

    ### Java全文检索引擎Lucene的应用 #### 一、引言 随着信息技术的飞速发展,尤其是数据库技术和数据库管理系统(DBMS)的广泛应用,全球范围内的数据量急剧增长。特别是在科学研究领域,面对海量的数据,传统的手工...

    用 Lucene 加速 Web 搜索应用程序的开发

    "用 Lucene 加速 Web 搜索应用程序的开发" 这个标题指出,我们将探讨如何利用 Apache Lucene 这个全文搜索引擎库来提升 Web 应用程序的搜索性能。Lucene 是一个开源的Java库,专门用于文本搜索,它提供了高效的索引...

    基于Lucene的搜索引擎的研究与应用

    文章主要研究和应用了基于Lucene的搜索引擎,其特点是利用开源网络爬虫工具抓取互联网信息,并通过Lucene的API对特定信息进行索引和搜索。下面详细介绍相关知识点。 1. Lucene基础 Lucene是由Apache软件基金会提供...

    Lucene in Action 中文版

     《Lucene实战 第2版 》基于Apache的Lucene 3 0 从Lucene核心 Lucene应用 案例分析3个方面详细系统地介绍了Lucene 包括认识Lucene 建立索引 为应用程序添加搜索功能 高级搜索技术 扩展搜索 使用Tika提取文本 Lucene...

    经典的lucene实例代码及详细解析以及lucene结构流程介绍

    Lucene应用是指使用Lucene搜索引擎库构建搜索应用程序的过程。Lucene应用程序可以用于各种领域,包括文本搜索、图片搜索和视频搜索等。 在上面的代码中,我们使用了Lucene搜索引擎库构建了一个文本搜索应用程序。该...

    Lucene4.7-Web 例子

    《Lucene4.7在Web应用中的实践:结合SpringMVC与MyBatis3》 在信息化时代,搜索引擎已经成为我们日常获取信息的重要工具。Apache Lucene作为一款强大的全文搜索引擎库,为开发者提供了丰富的功能,帮助构建高效、可...

    linux 下配置和应用lucene

    "Linux 下配置和应用 Lucene" 在本文中,我们将详细介绍如何在 Red Hat Linux 9 下配置和应用 Lucene 2.9.1。这篇文章将对 Lucene 的安装、配置和应用进行详细的讲解,旨在为读者提供一个清晰、详细的指南。 环境...

    lucene实现过程中存在的问题

    Lucene是一款高性能、全功能的文本搜索引擎库,它被广泛应用于各种需要进行高效全文检索的应用场景中,例如网站搜索、文档管理等。由于其高度可定制化的特点,开发者可以根据具体需求对Lucene进行配置和优化。 ####...

    lucene的实际应用案例

    本案例"lucene的实际应用案例"主要关注如何利用Lucene来创建和管理索引,以便在大量文本数据中进行高效搜索。 在Lucene中,索引是搜索的核心。索引过程主要包括以下几个步骤: 1. **创建索引**: 首先,你需要读取...

    lucene API最基本应用

    **Lucene API 最基本应用** Lucene 是一个高性能、全文本搜索库,由 Apache 软件基金会开发。它提供了一个简单的 Java API,使得开发者能够方便地在应用程序中实现索引和搜索功能。在这个主题中,我们将深入探讨 ...

    lucene,lucene教程,lucene讲解

    lucene,lucene教程,lucene讲解。 为了对文档进行索引,Lucene 提供了五个基础的类 public class IndexWriter org.apache.lucene.index.IndexWriter public abstract class Directory org.apache.lucene.store....

    lucene_web项目应用实例

    《Lucene Web项目应用实例详解》 在信息技术领域,搜索引擎技术是不可或缺的一部分,Apache Lucene作为一款开源全文搜索引擎库,为开发者提供了强大的文本检索能力。本文将深入探讨一个名为“lucene_web”的项目,...

    基于Lucene的全文检索引擎研究与应用.pdf

    ### 基于Lucene的全文检索引擎研究与应用 #### 概述 随着信息技术的飞速发展,尤其是互联网的普及,企业和个人积累了大量的电子文档。如何高效地管理和检索这些文档成为了亟待解决的问题。全文检索技术作为一种...

    lucene3.0 lucene3.0

    lucene3.0 lucene3.0 lucene3.0 lucene3.0 lucene3.0

Global site tag (gtag.js) - Google Analytics