A. 用Lucene 做搜索引擎的时候预处理出错java.io.IOException: 另一个程序已锁定文件的一部分,进程无法访问.
把锁文件删除就可以了
B. Lucene需要索引的文本文件太大,怎么解决
就报错来看,还没有用到Lucene就出错了,意思是只到第一行就虚拟机内存溢出了,可以考虑把源文件进行切割,如把10M的文本切成5个1M的,建议你试一下
给一个可以切分文件的程序,可把它作为预处理的一部分
public static void splitToSmallFiles(File file, String outputpath) throws IOException {
int filePointer = 0;
int MAX_SIZE = 10240000;
BufferedWriter writer = null;
BufferedReader reader = new BufferedReader(new FileReader(file));
StringBuffer buffer = new StringBuffer();
String line = reader.readLine();
while (line != null) {
buffer.append(line).append("\\r\
");
if (buffer.toString().getBytes().length >= MAX_SIZE)
{
writer = new BufferedWriter(new FileWriter(outputpath + "output" + filePointer + ".txt"));
writer.write(buffer.toString());
writer.close();
filePointer++;
buffer = new StringBuffer();
}
line = reader.readLine();
}
writer = new BufferedWriter(new FileWriter(outputpath + "output" + filePointer + ".txt"));
writer.write(buffer.toString());
writer.close();
}
C. 搜索引擎Lucene(4):索引的创建过程
创建索引的过程如下:
索引结构如下:
IndexWriter结构:
IndexWriter通过指定存放的目录(Directory)以及文档分析器(Analyzer)来构建,direcotry代表索引存储在哪里;analyzer表示如何来分析文档的内容;similarity用来规格化文档,给文档算分;IndexWriter类里还有一些SegmentInfos对象用于存储索引片段信息,以及发生故障回滚等。
添加文档使用addDocument()方法,删除文档使用deleteDocuments(Term)或者deleteDocuments(Query)方法,而且一篇文档可以使用updateDocument()方法来更新(仅仅是先执行delete在执行add操作而已)。当完成了添加、删除、更新文档,应该需要调用close方法。
这些修改会缓存在内存中(buffered in memory),并且定期地(periodically)刷新到(flush)Directory中(在上述方法的调用期间)。一次flush操作会在如下时候触发(triggered):当从上一次flush操作后有足够多缓存的delete操作(参见setMaxBufferedDeleteTerms(int)),或者足够多已添加的文档(参见setMaxBufferedDocs(int)),无论哪个更快些(whichever is sooner)。对被添加的文档来说,一次flush会在如下任何一种情况下触发,文档的RAM缓存使用率(setRAMBufferSizeMB)或者已添加的文档数目,缺省的RAM最高使用率是16M,为得到索引的最高效率,你需要使用更大的RAM缓存大小。需要注意的是,flush处理仅仅是将IndexWriter中内部缓存的状态(internal buffered state)移动进索引里去,但是这些改变不会让IndexReader见到,直到commit()和close()中的任何一个方法被调用时。一次flush可能触发一个或更多的片断合并(segmentmerges),这时会启动一个后台的线程来处理,所以不会中断addDocument的调用,请参考MergeScheler。
一个IndexReader或者IndexSearcher只会看到索引在它打开的当时的状态。任何在索引被打开之后提交到索引中的commit信息,在它被重新打开之前都不会见到。
DocumentsWriter结构:
DocumentsWriter 是由IndexWriter 调用来负责处理多个文档的类,它通过与Directory 类及Analyzer 类、Scorer 类等将文档内容提取出来,并分解成一组term列表再生成一个单一的segment 所需要的数据文件,如term频率、term 位置、term 向量等索引文件,以便SegmentMerger 将它合并到统一的segment 中去。
该类可接收多个添加的文档,并且直接写成一个单独的segment 文件。这比为每一个文档创建一个segment(使用DocumentWriter)以及对那些segments 执行合作处理更有效率。
每一个添加的文档都被传递给DocConsumer类,它处理该文档并且与索引链表中(indexing chain)其它的consumers相互发生作用(interacts with)。确定的consumers,就像StoredFieldWriter和TermVectorsTermsWriter,提取一个文档的摘要(digest),并且马上把字节写入“文档存储”文件(比如它们不为每一个文档消耗(consume)内存RAM,除了当它们正在处理文档的时候)。
其它的consumers,比如FreqProxTermsWriter和NormsWriter,会缓存字节在内存中,只有当一个新的segment制造出的时候才会flush到磁盘中。
一旦使用完我们分配的RAM缓存,或者已添加的文档数目足够多的时候(这时候是根据添加的文档数目而不是RAM的使用率来确定是否flush),我们将创建一个真实的segment,并将它写入Directory中去。
索引创建的调用过程:
一个Directory对象是一系列统一的文件列表(a flat list of files)。文件可以在它们被创建的时候一次写入,一旦文件被创建,它再次打开后只能用于读取(read)或者删除(delete)操作。并且同时在读取和写入的时候允许随机访问。
FSDirectory类直接实现Directory抽象类为一个包含文件的目录。目录锁的实现使用缺省的SimpleFSLockFactory,但是可以通过两种方式修改,即给getLockFactory()传入一个LockFactory实例,或者通过调用setLockFactory()方法明确制定LockFactory类。
目录将被缓存(cache)起来,对一个指定的符合规定的路径(canonical path)来说,同样的FSDirectory实例通常通过getDirectory()方法返回。这使得同步机制(synchronization)能对目录起作用。
RAMDirectory类是一个驻留内存的(memory-resident)Directory抽象类的实现。目录锁的实现使用缺省的SingleInstanceLockFactory,但是可以通过setLockFactory()方法修改。
IndexInput类是一个为了从一个目录(Directory)中读取文件的抽象基类,是一个随机访问(random-access)的输入流(input stream),用于所有Lucene读取Index的操作。BufferedIndexInput是一个实现了带缓冲的IndexInput的基础实现。
IndexOutput类是一个为了写入文件到一个目录(Directory)中的抽象基类,是一个随机访问(random-access)的输出流(output stream),用于所有Lucene写入Index的操作。BufferedIndexOutput是一个实现了带缓冲的IndexOutput的基础实现。RAMOuputStream是一个内存驻留(memory-resident)的IndexOutput的实现类。
域索引选项通过倒排索引来控制文本是否可被搜索。
当lucene建立起倒排索引后,默认情况下它会保存所有必要的信息以实施Vector Space Model。该Model需要计算文档中出现的Term数,以及它们出现的文职(这是必要的,比如通过词组搜索时用到)。但有时候这些域只是在布尔搜索时用到,他们并不为相关评分做贡献,一个常见的例子是,域只是被用作过滤,如权限过滤和日期过滤。在这种情况下,可以通过调用Field.setOmitTermFreqAndPositions(true)方法让lucene跳过对改选项的出现频率和出现位置的索引。该方法可以节省一些索引在磁盘上的储存空间,还可以加速搜索和过滤过程,但会悄悄阻止需要位置信息的搜索,如阻止PhraseQuery和SpanQuery类的运行。
域存储选项是用来确定是否需要存储域的真实值,以便后续搜索时能回复这个值。
lucene支持想一个域中写入多个不同的值。
这种处理方式是完全可以接受并鼓励使用的,因为这是逻辑上具有多个域值的域的自然表示方式。在lucene内部,只要文档中出现同名的多域值,倒排索引和项向量都会在逻辑上将这些语汇单元附加进去,具体顺序由添加该域的顺序决定。
文档和域的加权操作可以在索引期间完成。而搜索期间的加权操作会更加动态化,因为每次搜索都可以根据不同的加权因子独立选择加权或不加权,但这个策略也可能多消耗一些CPU效率。搜索期间的动态加权可以更灵活控制。
默认情况下,所有文档的加权因子都是1.0,通过改变文档的加权因子,就可以影响文档在索引中的重要程度。调整加权操作的API为:setBoost(float);
同文档加权一样,可以对进行加权操作。文档加权时,lucene内部会采用同一加权因子来对该文档中的域进行加权。域加权API:Field.setBoost(fliat)。
Analyzer类构建用于分析文本的TokenStream对象,因此(thus)它表示(represent)用于从文本中分解(extract)出组成索引的terms的一个规则器(policy)。典型的(typical)实现首先创建一个Tokenizer,它将那些从Reader对象中读取字符流(stream of characters)打碎为(break into)原始的Tokens(raw Tokens)。然后一个或更多的TokenFilters可以应用在这个Tokenizer的输出上。警告:你必须在你的子类(subclass)中覆写(override)定义在这个类中的其中一个方法,否则的话Analyzer将会进入一个无限循环(infinite loop)中。
StandardAnalyzer:
StandardAnalyzer类是使用一个English的stop words列表来进行tokenize分解出文本中word,使用StandardTokenizer类分解词,再加上StandardFilter以及LowerCaseFilter以及StopFilter这些过滤器进行处理的这样一个Analyzer类的实现。
D. 为什么我的Lucene的索引被锁定
被IIS锁定时什么情况呢?
不具有读写权限? 还是有一个?.lock文件 。 如果创建索引的时候异常中断,可以尝试删除lock文件或者重新生成。并赋予该文件夹正确的权限信息。
E. 在Lucene中删除索引,使用writer.optimize();//优化操作使删除生效,可是这一句老是有错,求大神指教。
IndexReader提供了两种方法:
reader.DeleteDocument(int
docNum)
reader.DeleteDocuments(Term term)
前者是根据文档的编号来删除该文档,docNum是该文档进回入索引时Lucene的编号,答是按照顺序编的;后者是删除满足某一个条件的多个文档。
在执行了DeleteDocument或者DeleteDocuments方法后,系统会生成一个*.del的文件,该文件中记录了删除的文档,但并未从物理上删除这些文档。此时,这些文档是受保护的,当使用Document
doc = reader.Document(i)来访问这些受保护的文档时,Lucene会报“Attempt to access a deleted
document”异常。如果一次需要删除多个文档时,可以用两种方法来解决:
1. 删除一个文档后,用IndexWriter的Optimize方法来优化索引,这样我们就可以继续删除另一个文档。
2.
先扫描整个索引文件,记录下需要删除的文档在索引中的编号。
F. 用lucene建立索引时,当第二次创建时,还在同一个目录下,那么之前的索引会被删除吗
你用Lucene建立索引的时候IndexWriter writer = new IndexWriter(indexdir,new StandardAnalyzer(), true);
第三个参数当为TRUE时是会删除同一个目录下的索引的,这是在回初次创建答索引时使用
以后每次增量索引直接设置为FALSE即可,这样直接将后面新建立的索引添加到索引文件中,不会覆盖原来建立的索引。
当删除索引时我们可以找到对应的索引ID,然后删除索引,将删除掉索引文件中的该条记录,同时在同目录下生成一个删除索引的记录问价,为-DEL文件,便于后面恢复删除的索引。
以上解答希望你能理解,建个简单的索引试试就可以知道的