|
锁定老贴子 主题:lucene造成磁盘空间不足的问题
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
|---|---|
| 作者 | 正文 |
|
最后更新时间:2007-08-01 关键字: lucene
我用lucene做了一个Search Engine
程序运行也很正常,但如果连续运行几个月,有时会出现磁盘空间不足的情况 检查发现,index目录占用了数10G空间。 我的lucene程序里有delete超时的index的 后来我写了一个删除程序,用来delete无用的index public boolean shrink(String path, String time) {
int deletedNum = 0;
boolean isSucceed = true;
File tempFile = queryCanbeDeletedTermToTempFile(path, time);
IndexReader ir = null;
try {
ir = IndexReader.open(path);
}
catch (IOException ex) {
LogOut.writeErr("Create index reader failed! Path = " + path);
ex.printStackTrace();
return false;
}
try {
long deleteTimes=0;
do {
termValue = br.readLine();
if (termValue == null) {
break;
}
termValue = termValue.trim();
if (termValue.length() > 0) {
deleteTimes++;
Term term = new Term("KEY_PARSETIME", termValue);
int num = ir.deleteDocuments(term);
deletedNum += num;
}
}
while (termValue != null);
isSucceed = true;
}
catch (Exception ex2) {
ex2.printStackTrace();
isSucceed = false;
}
finally {
if (ir != null) {
try {
ir.close();
}
catch (IOException ex3) {
}
}
if (br != null) {
try {
br.close();
}
catch (IOException ex4) {
}
}
if(tempFile!=null){
tempFile.delete();
}
}
boolean isOptimized=false;
IndexWriter iw = null;
try {
iw = new IndexWriter(path, new StandardAnalyzer(), false);
iw.optimize();
isOptimized=true;
}
catch (IOException ex5) {
ex5.printStackTrace();
isOptimized=false;
}finally{
if(iw!=null){
try {
iw.close();
}
catch (IOException ex6) {
}
}
}
return isSucceed&&isOptimized;
}
这个删除无用index也工作正常,但却无法将index目录的大小缩减 仔细检查目录,发现里面有很多文件,几十个。有些都有几十兆大。而用时间排序,发现有些甚至是一个月前的。我手动把修改时间是昨天前的文件删除后,运行lucene,一切正常。似乎这些文件都是无效的旧文件。 这个该怎么办?怎么才能将无效文件删除呢? 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
最后更新时间:2007-08-01
我觉这个问题应该是建索引的问题。
所以你应该把你建索引的代码贴出来,或者说说你建索引的具体思路。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-08-01
建立索引如下
private void indexStoredDocuments() {
ArrayList documents = new ArrayList();
IndexWriter iw = null;
synchronized (this) {
try {
iw = createIndexWriter();
while (!documentList.isEmpty()) {
IndexDocumentNode node = removeLastStoredButNotIndexedDocument();
documents.add(node);
Document doc = parseDocument(node);
iw.addDocument(doc);
}
iw.optimize();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (iw != null) {
try {
iw.close();
}
catch (Exception ex1) {
}
iw = null;
}
}
}
}
private IndexWriter createIndexWriter() throws Exception {
IndexWriter iw = null;
try {
iw = new IndexWriter(initParamNode.getIndexFilePath(), analyzer,
!IndexReader.indexExists(initParamNode.
getIndexFilePath()));
iw.setInfoStream(initParamNode.getInfoStream());
iw.setMaxBufferedDocs(initParamNode.getMaxBufferedDocs());
iw.setMaxFieldLength(initParamNode.getMaxFieldLength());
iw.setMaxMergeDocs(initParamNode.getMaxMergeDocs());
iw.setMergeFactor(initParamNode.getMergeFactor());
}
catch (Exception ex) {
if (iw != null) {
try {
iw.close();
}
catch (IOException ex1) {
}
iw = null;
}
throw ex;
}
return iw;
}
我用Thread来建立index的. 从外面将需要建立index的文字放到一个LinkedList里,然后这个Thread在循环时check这个List,如果发现它不是空的,就会调用indexStoredDocuments()方法 这个方法通过removeLastStoredButNotIndexedDocument()来从list里取得内容,然后通过parseDocument(node)方法把它变成lucene的document。这两个方法没贴出来,我觉得不是这里的问题,因为document正常的。 通过iw.addDocument(doc)写入index 当list里的东西全部被写入完毕后,通过optimze来优化索引 可这个东西运行不是很稳定,有的时候很正常,运行几个月都okay,有时1个月就出现问题了。会在index的目录里出现很多文件。这些文件似乎是应该被optimize掉的。 我不知道哪里出的问题。lucene有没有管理这些文件的功能呢 |
|
| 返回顶楼 | |
|
最后更新时间:2007-08-02
fool_leave 写道 建立索引如下
private void indexStoredDocuments() {
ArrayList documents = new ArrayList();
IndexWriter iw = null;
synchronized (this) {
try {
iw = createIndexWriter();
while (!documentList.isEmpty()) {
IndexDocumentNode node = removeLastStoredButNotIndexedDocument();
documents.add(node);
Document doc = parseDocument(node);
iw.addDocument(doc);
}
iw.optimize();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (iw != null) {
try {
iw.close();
}
catch (Exception ex1) {
}
iw = null;
}
}
}
}
private IndexWriter createIndexWriter() throws Exception {
IndexWriter iw = null;
try {
iw = new IndexWriter(initParamNode.getIndexFilePath(), analyzer,
!IndexReader.indexExists(initParamNode.
getIndexFilePath()));
iw.setInfoStream(initParamNode.getInfoStream());
iw.setMaxBufferedDocs(initParamNode.getMaxBufferedDocs());
iw.setMaxFieldLength(initParamNode.getMaxFieldLength());
iw.setMaxMergeDocs(initParamNode.getMaxMergeDocs());
iw.setMergeFactor(initParamNode.getMergeFactor());
}
catch (Exception ex) {
if (iw != null) {
try {
iw.close();
}
catch (IOException ex1) {
}
iw = null;
}
throw ex;
}
return iw;
}
我用Thread来建立index的. 从外面将需要建立index的文字放到一个LinkedList里,然后这个Thread在循环时check这个List,如果发现它不是空的,就会调用indexStoredDocuments()方法 这个方法通过removeLastStoredButNotIndexedDocument()来从list里取得内容,然后通过parseDocument(node)方法把它变成lucene的document。这两个方法没贴出来,我觉得不是这里的问题,因为document正常的。 通过iw.addDocument(doc)写入index 当list里的东西全部被写入完毕后,通过optimze来优化索引 可这个东西运行不是很稳定,有的时候很正常,运行几个月都okay,有时1个月就出现问题了。会在index的目录里出现很多文件。这些文件似乎是应该被optimize掉的。 我不知道哪里出的问题。lucene有没有管理这些文件的功能呢 要删除无效的索引文件,IndexWriter.optimize()就可以了,在调用前最好把索引目录的所有IndexReader,IndexSeacher都关闭,否则无法删除无效的文件。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-08-02
一个索引只能有一个indexreader, 在optimize的时候可以有多个indexsearcher在工作。
你得确保 1。你的optimize确实调用了 2。optimize的时候, 得有双倍的磁盘空间 |
|
| 返回顶楼 | |
|
最后更新时间:2007-08-03
认真想了一下,你这个程序要连续运行几个月以上,而且又是多线程操作,所以经常会出现这样的情况:
在你修改索引的时候(即addDocument,deleteDocument,updateDocument,optimize),同时也在使用IndexSearcher读取了索引,提供搜索。 下面是Lucene API doc 的optimize()方法的一段注释: If readers/searchers are using the index, then free space required is up to 2X the size of the starting index. This is because in addition to the 1X used by optimize, the original 1X of the starting index is still consuming space in the Directory as the readers are holding the segments files open. Even on Unix, where it will appear as if the files are gone ("ls" won't list them), they still consume storage due to "delete on last close" semantics. 从中可以分析出,如果在optimize索引的时候,也同时使用Searcher。索引空间的使用情况如下: 1. 原始索引 2. 由IndexWriter使用的索引,用于optimize 3. 由IndexSearcher使用的索引,用于搜索。 当你optimize完索引后,应该只剩下optimize后的新索引和由IndexSearcher使用的临时索引。 根据你的描述: fool_leave 写道 仔细检查目录,发现里面有很多文件,几十个。有些都有几十兆大。而用时间排序,发现有些甚至是一个月前的。我手动把修改时间是昨天前的文件删除后,运行lucene,一切正常。似乎这些文件都是无效的旧文件。 你发现的很多文件应该是IndexSearcher正在使用的临时索引,而不是索引的段文件,但这些文件应该是在IndexSearcher关闭时或下次optimize时就删除掉的。 那是什么原因使得这些文件不能删除呢? 下面是小弟的几个猜测: 1. 没有正确使用IndexSearcher,即打开了没有关闭。 2. 打开了多个IndexSearcher,一直没有关闭。导致临时文件增多。 3. 没有权限删除这些临时文件(不知道在linux下会不会出现这种情况),不过这个可能性比较小 4. Lucene不稳定,出现重大Bug了。(不过这个可能性也较小) 说得好乱 :? 以上只是个人的猜测,未经实践证实, 仅供参考。 :D |
|
| 返回顶楼 | |
|
最后更新时间:2007-08-03
谢谢您的恢复
我的index是这样写的
public SearchResult query(SearchNode node) throws Exception {
ArrayList resultList = null;
int totleNum = 0;
Searcher searcher = null;
SearchResult sr = new SearchResult();
try {
Analyzer analyzer = getAnalyzer();
Query oriQuery = getOriQuery(node, analyzer);
Query query = getFilterQuery(oriQuery, node, analyzer);
searcher = new IndexSearcher(initParamNode.getIndexFilePath());
Hits hits = searcher.search(query, getSort(node));
totleNum = hits.length();
resultList = new ArrayList();
int startpos=0;
int endpos=hits.length();
if(!node.isDetailSearch()){
startpos=Math.max(node.getFromPosition(),0);
endpos=Math.min(startpos+node.getMaxLength(),hits.length());
}
for (int i = startpos, num = 0;
i < endpos; i++) {
Document doc = hits.doc(i);
sr.addSourceName(doc.get(node.KEY_SOURCENAME));
sr.addClassDef(doc.get(node.KEY_CLASSDEF));
if (i >= node.getFromPosition() && num < node.getMaxLength()) {
ResultNode rn = new ResultNode();
rn.setScore(hits.score(i));
rn.setSourceName(doc.get(node.KEY_SOURCENAME));
rn.setTitle(doc.get(node.KEY_TITLE));
rn.setUrl(doc.get(node.KEY_URL));
resultList.add(rn);
num++;
}
}
}
catch (Exception ex) {
ex.printStackTrace();
}
finally {
if(searcher!=null){
try {
searcher.close();
}
catch (Exception e) {}
searcher = null;
}
}
sr.setList(resultList);
sr.setSearchTime(end - begin);
sr.setFirstParsedResultPosition(node.getFromPosition());
sr.setTotleResultNum(totleNum);
return sr;
}
由于这是一个web app,所以在search这里没有加同步,怕同步造成用户访问速度慢 |
|
| 返回顶楼 | |
|
最后更新时间:2007-08-03
amigobot 写道 一个索引只能有一个indexreader, 在optimize的时候可以有多个indexsearcher在工作。
你得确保 1。你的optimize确实调用了 2。optimize的时候, 得有双倍的磁盘空间 是不是说我在索引创建好后就需要创建一个IndexReader,然后每次操作都通过这个IndexReader来做,而不是每次操作前创建一个,再关闭? optimize肯定调用了,而且双倍磁盘空间也有的 |
|
| 返回顶楼 | |
|
最后更新时间:2007-08-03
再三测试,再三测试
终于 发现规律了 各位再看看,分析一下原因 1:当search动作太频繁,或者访问的人很多,在optimize时会出现这个message java.io.IOException: Cannot delete E:\index\_nir.f2; Will re-try later. 不知道re-try later是他做还是我做呢 2:更有意思的规律 当我把search进程关闭,只做index写入动作时,似乎运行正常 每次优化后index一共有3个文件 _p00.cfs,deletable,segments 但当我关闭这个index写入进程,然后再重新启动它后,上次留下的一些文件就会保留下来,不被删除掉 如:我在14:20分关闭这个进程 结果index目录里有 _p00.cfs,deletable,segments,_idv.tis,_idv.prx等文件 我在14:25分开启这个进程,当optimize完成后,index目录里 _p00.cfs,deletable,segments文件全部更新了,修改时间是14:25,而其他的几个文件的修改时间还是14:20,而且会一直保持不变。如果中间停止的时间很长,这种现象越明显。 index程序在上面有代码 进程关闭时也可能Lucene正在做index或者optimize动作。但我的程序没办法等待它做完再exit。进程关闭后出现无法清除的残留文件最终导致硬盘不够用。 各位有这种情况吗? |
|
| 返回顶楼 | |
|
最后更新时间:2007-08-03
你看下使用的lucene对应版本的文件格式
10g单个索引? 如果是,那么建议你要想法子切开。 |
|
| 返回顶楼 | |






