I'm developing a web application (with JSF) for information retrieval and I'm using Lucene to read and index file .pdf. I read a previous question (LockObtainFailedException at new IndexWriter()) about LockObtainFailedException but I still can't solve my problem, so I'll explain it briefly.
I have a managedBean who indexes docs with this method :
@ManagedBean
@RequestScoped
public class managedBeanIB{
@EJB
private Indexer indexer;
private Part file;;
private long ISBN;
private String author;
private String title;
private String content; // getter and setter for each field
...
public String add() throws IOException{
indexer = new Indexer();
InputStream is = file.getInputStream();
PDDocument doc = PDDocument.load(is);
contenuto = new PDFTextStripper().getText(doc);
doc.close();
Book book = new Libro(ISBN,author,title,content);
indexer.index(book);
indexer.close();
return "home";
}
}//class
class Indexer is the following :
@Stateless
public class Indexer implements Serializable {
private static final String directory = "C:\\Users\\EngineFM\\Documents\\NetBeansProjects\\SIA\\SIA-ejb\\src\\resources\\index\\";
public static final String ENG = "english";
private IndexWriter iw;
public Indexer() {
try {
if (iw == null) {
iw = new IndexWriter(FSDirectory.open(new File(directory)),
new IndexWriterConfig(Version.LATEST, new EnglishAnalyzer()));
}
} catch (IOException ex) {
System.out.println("something wrong");
ex.printStackTrace();
}
}
public void index(Book item) throws IOException{
iw.deleteDocuments(new Term(Book.ID, String.valueOf(item.getISBN())));
Document doc = new Document();
doc.add(new LongField(Book.ID, item.getISBN(),Field.Store.YES));
doc.add(new StringField(Book.AUTHOR, item.getAuthor(),Field.Store.YES));
doc.add(new StringField(Book.TITLE, item.getTitle(),Field.Store.YES));
doc.add(new TextField(Libro.CONTENT, item.getContent(),Field.Store.YES));
iw.addDocument(doc);
iw.commit();
}
public void close() throws IOException {
iw.close();
}
When I start my application (home page), I noticed that Indexer is instantiated, along with my managed bean. Then I go on add page, I fill all the information needed and I click on "add document". In this case Indexer is instantiated again, but the previous lock is still open (I guess), so the doc is not stored and I have the following exception :
Grave: org.apache.lucene.store.LockObtainFailedException: Lock obtain timed out: NativeFSLock@C:\Users\EngineFM\Documents\NetBeansProjects\SIA\SIA-ejb\src\resources\index\write.lock at org.apache.lucene.store.Lock.obtain(Lock.java:89) at org.apache.lucene.index.IndexWriter.(IndexWriter.java:755) at pack.Indexer.(Indexer.java:62) at managedBean.managedBeanIB.add(managedBeanIB.java:107) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at javax.el.ELUtil.invokeMethod(ELUtil.java:332) at javax.el.BeanELResolver.invoke(BeanELResolver.java:537) at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:256) at com.sun.el.parser.AstValue.invoke(AstValue.java:283) at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304) at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105) at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87) at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) at javax.faces.component.UICommand.broadcast(UICommand.java:315) at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790) at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282) at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:344) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) at org.glassfish.tyrus.servlet.TyrusServletFilter.doFilter(TyrusServletFilter.java:295) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:316) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:415) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:282) at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167) at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:201) at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:175) at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235) at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201) at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133) at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112) at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77) at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:561) at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:565) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545) at java.lang.Thread.run(Thread.java:745)
How can I avoid this situation? I'm thinking of unlock() method (as suggested in https://lucene.apache.org/core/4_1_0/core/org/apache/lucene/index/IndexWriter.html#close() ) but I don't know where to place it. Any help is appreciated.
On the suggestion of femtoRgon I tryed to modify my code to avoid instantiation for each add() operation :
public String add() throws IOException{
InputStream is = file.getInputStream();
PDDocument doc = PDDocument.load(is);
contenuto = new PDFTextStripper().getText(doc);
doc.close();
Book book = new Libro(ISBN,author,title,content);
indexer.index(book);
indexer.close();
return "home";
}
Unfortunately the result is the same and seems to have some conflict on write.lock . I don't know how is possible. Maybe can be that for each request the bean is re-generated and I have two or more lock? Should I change the @RequestScoped annotation?
unlock()
. You should only have oneIndexWriter
instance open on an index at a time. That's why the lock exists.unlock()
should only be used in situations such as when the application fails to exit gracefully, and leaves the index locked, even though you are certain there are no processes currently accessing it. – femtoRgon@EJB
, so it will do that, if I'm not mistaken. So, why are you constructing and closing yourIndexer
as part of theadd()
method? – femtoRgonIndexWriter
, rather than closing after each operation. Opening new writers is expensive, so it's a good idea to reuse them anyway. – femtoRgon