我正在努力将Lucene与基于Spring-MVC的应用程序集成。目前我们已经开始工作了,但我们很少遇到cannot obtain lock
错误。之后我必须手动删除锁定文件然后才能正常工作。
如何设置在Java中锁定索引的超时?我没有Lucene的任何XML配置。我通过POM.xml在maven中添加了项目库,并实例化了所需的类。
代码:
public void saveIndexes(String text, String tagFileName, String filePath, long groupId, boolean type, int objectId) {
try {
// path is the indexing directory.
File testDir;
Path suggestionsPath;
Directory suggestionsDir;
Path phraseSuggestPath;
Directory phraseSuggestDir;
Directory directory = org.apache.lucene.store.FSDirectory.open(path);
IndexWriterConfig config = new IndexWriterConfig(new SimpleAnalyzer());
IndexWriter indexWriter = new IndexWriter(directory, config);
org.apache.lucene.document.Document doc = new org.apache.lucene.document.Document();
if (filePath != null) {
File file = new File(filePath); // current directory
doc.add(new TextField("path", file.getPath(), Field.Store.YES));
}
doc.add(new StringField("id", String.valueOf(objectId), Field.Store.YES));
// doc.add(new TextField("id",String.valueOf(objectId),Field.Store.YES));
if (text == null) {
if (filePath != null) {
FileInputStream is = new FileInputStream(filePath);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder stringBuffer = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuffer.append(line).append("\n");
}
stringBuffer.append("\n").append(tagFileName);
reader.close();
doc.add(new TextField("contents", stringBuffer.toString(), Field.Store.YES));
}
} else {
FieldType fieldType = new FieldType(TextField.TYPE_STORED);
fieldType.setTokenized(false);
doc.add(new Field("contents", text+"\n"+tagFileName, fieldType));
}
indexWriter.addDocument(doc);
indexWriter.commit();
indexWriter.flush();
indexWriter.close();
directory.close();
StandardAnalyzer analyzer = new StandardAnalyzer();
AnalyzingInfixSuggester wordSuggester = new AnalyzingInfixSuggester(suggestionsDir, analyzer);
ArrayList<String> words = new ArrayList<>();
if (text != null) {
text = html2text(text);
Pattern pt = Pattern.compile("[^\\w\\s]");
Matcher match = pt.matcher(text);
while (match.find()) {
String s = match.group();
text = text.replaceAll("\\" + s, "");
}
if (text.contains(" ")) {
Collections.addAll(words, text.split(" "));
} else {
words.add(text);
}
SuggestionIterator suggestionIterator = new SuggestionIterator(words.iterator());
wordSuggester.build(suggestionIterator);
wordSuggester.close();
suggestionsDir.close();
}
AnalyzingInfixSuggester phraseSuggester = new AnalyzingInfixSuggester(phraseSuggestDir, analyzer);
if (text != null) {
text = html2text(text);
ArrayList<String> phrases = new ArrayList<>();
phrases.add(text);
SuggestionIterator suggestionIterator = new SuggestionIterator(phrases.iterator());
phraseSuggester.build(suggestionIterator);
phraseSuggester.close();
phraseSuggestDir.close();
}
} catch (Exception ignored) {
}
}
谢谢。
答案 0 :(得分:5)
我引用了IndexWriter Documentation,
中的两件事打开IndexWriter会为正在使用的目录创建一个锁定文件。 尝试在同一目录上打开另一个IndexWriter将导致 一个LockObtainFailedException。
和
注意:IndexWriter实例完全是线程安全的,这意味着 多个线程可以同时调用它的任何方法。如果你的 应用程序需要外部同步,你不应该 在IndexWriter实例上同步,因为这可能会导致死锁; 使用你自己的(非Lucene)对象。
因此,如果已经打开了IndexWriter并且未在其他位置关闭,则无法再次打开它。在您的情况下,当两个用户处于相同的代码块时,恰好有一些不幸的时间。
您可以通过两种方式解决此问题,
1. 指定关键部分:将编写器打开,使用和关闭操作的代码部分标记为关键部分,并在该关键部分应用Java同步。使用一些应用程序Singleton bean进行同步。因此,当另一个用户点击该块时,他将等到第一个用户完成并释放锁定。
2. 单个Writer实例:在您的应用程序中开发一种机制,在应用程序的生命周期内只打开和关闭一次编写器,并在服务代码中传递该单个实例,以便可以调用编写器方法尽可能多的用户,因为编写器实例由Lucene人员制作线程安全的。 我想,这可以通过Singleton Spring bean并在您的服务中注入该bean来实现。
第二种方法的缺点是 - 单个全局索引目录的多服务器部署,以及是否有其他应用程序试图在该全局索引上打开编写器。这个问题可以通过将索引编写器实例创建代码包装在某种全局服务中来解决,该服务将相同的实例返回到尝试使用它的任何应用程序。
这不是您尝试通过删除锁定文件或引入超时来解决的简单问题。您必须根据IndexWriter文档建模您的设计,而不是其他方式。
拥有单个编写器实例也会引入一些性能改进。
此外,在创建编写器后立即进行空提交练习。这帮助我解决了过去的一些问题。