Lucene IndexWriter.commit()在Ubuntu中无法完成的问题排查
解决Ubuntu下Lucene IndexWriter.commit()卡住的问题
我之前也碰到过类似的跨平台Lucene问题,结合你的代码和Windows/Ubuntu的系统差异,这几个方向应该能帮你定位并解决问题:
一、文件权限与目录存在性问题
Ubuntu的文件权限管控比Windows严格得多,这是最常见的触发原因:
- 你的索引目录
index_dir = "res/index/" +lang+ "." +dType+ ".index",在Ubuntu下如果res/index/父目录不存在,Lucene不会自动创建目录,直接导致写入失败;就算目录存在,当前运行程序的用户也可能没有写入权限。 - 排查方法:在终端执行
ls -ld res/index/查看目录权限,执行touch res/index/test.file测试是否能正常写入文件。 - 解决方法:
- 提前创建索引目录的父路径,在初始化IndexWriter前添加代码:
Path indexDirPath = Paths.get(index_dir); if (!Files.exists(indexDirPath.getParent())) { Files.createDirectories(indexDirPath.getParent()); } - 给目录添加写入权限:
sudo chmod -R 775 res/index/,或者把目录所有者改为当前用户:sudo chown -R $USER res/index/
- 提前创建索引目录的父路径,在初始化IndexWriter前添加代码:
二、资源释放逻辑有缺陷
你的Index.run()方法里,writer.commit()之后直接调用writer.close(),但如果commit过程抛出异常,close()就不会执行,导致IndexWriter一直占用文件句柄,最终卡住:
- 看你代码里的这段逻辑:
如果commit失败,writer没有被关闭,会导致资源泄漏,进而引发后续操作卡住。try { System.out.println("start index"); indexDocs(data, field); this.writer.commit(); this.writer.close(); System.out.println("done"); } catch (IOException e) { e.printStackTrace(); } - 优化方案:用Java的try-with-resources自动管理资源(Lucene的IndexWriter实现了AutoCloseable),修改你的Index类逻辑:
这样不管是否发生异常,IndexWriter都会自动关闭,避免资源泄漏导致的卡住。// 调整initWriter方法,返回IndexWriter实例 public IndexWriter initWriter(String index_path, Analyzer analyzer) throws IOException { IndexWriterConfig config = new IndexWriterConfig(analyzer); return new IndexWriter(FSDirectory.open(Paths.get(index_path)), config); } // 修改run方法,用try-with-resources自动管理writer public void run(String path, String field, String extension, String separator) { List<File> files = this.handler.getInputFiles(path, extension); List<?> data = this.handler.readDocs(files, separator); try (IndexWriter writer = initWriter(index_dir, new StandardAnalyzer())) { System.out.println("start index"); indexDocs(data, field, writer); // 把writer传入indexDocs方法 writer.commit(); System.out.println("done"); } catch (IOException e) { e.printStackTrace(); } } // 调整indexDocs方法,接收writer参数 public void indexDocs(List<?> datas, String field, IndexWriter writer) throws IOException { FieldType fieldType = new FieldType(); FieldType fieldType2 = new FieldType(); fieldType.setStored(true); fieldType.setTokenized(true); fieldType.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS); fieldType2.setStored(true); fieldType2.setTokenized(false); fieldType2.setIndexOptions(IndexOptions.DOCS); for(int i = 0 ; i < datas.size() ; i++) { Map<String,String> temp = (Map<String,String>) datas.get(i); Document doc = new Document(); for(String key : temp.keySet()) { if(key.equals(field)) continue; doc.add(new Field(key, temp.get(key), fieldType2)); } doc.add(new Field(field, temp.get(field), fieldType)); writer.addDocument(doc); } }
三、磁盘或内存资源不足
Ubuntu服务器如果磁盘空间不足,或者内存不够,Lucene在flush/commit时会因为无法写入磁盘而卡住:
- 排查方法:
- 执行
df -h查看磁盘剩余空间,确保索引所在磁盘有足够空间。 - 执行
free -h查看内存使用情况,如果内存不足,Lucene会频繁触发磁盘交换,导致commit极慢甚至无响应。
- 执行
- 解决方法:
- 清理磁盘空间,或者扩容磁盘。
- 调整Lucene的内存缓冲区大小,减少磁盘写入频率:
IndexWriterConfig config = new IndexWriterConfig(analyzer); config.setRAMBufferSizeMB(64.0); // 根据服务器内存调整,比如设置为64MB或128MB
四、路径分隔符与跨平台兼容问题
虽然你用了Paths.get(index_path)来处理路径,但还是要注意:
- 确保
input_path(比如train变量)在Ubuntu下是正确的相对路径,或者直接用绝对路径测试,避免相对路径解析错误。 - 检查路径中是否包含Ubuntu不支持的特殊字符(比如Windows下的中文路径在Ubuntu下编码不一致)。
最后,建议你在Ubuntu运行时,在commit()前后添加更详细的日志,比如打印当前索引目录的绝对路径,或者捕获IOException的完整堆栈信息,这样能更快定位具体问题。
内容的提问来源于stack exchange,提问作者sjpark
相关产品推荐
相关产品推荐

