0
votes

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?

1
Don't use unlock(). You should only have one IndexWriter 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
@femtoRgon Yes I got, but I don't control the instantiation when the web application start. How can I do?Fabrizio
Right, you've annotated it with @EJB, so it will do that, if I'm not mistaken. So, why are you constructing and closing your Indexer as part of the add() method?femtoRgon
@femtoRgon I thought it was a good idea. The closure is necessary after each operation (I guess). What I should do?Fabrizio
You should reuse the same IndexWriter, rather than closing after each operation. Opening new writers is expensive, so it's a good idea to reuse them anyway.femtoRgon

1 Answers

0
votes

I found the solution for my problem. As I said before, it depends on Scope of managed bean. In the case of @RequestScoped, the managed bean is created for each request : in my case, this implies that also Indexer is generated for each request. I had the instantiation of IndexWriter in the Indexer constructor, so since the instance was generated at the beginning (when application start), when I tryed to compute a request it was generated again and there were conflict problems on write lock. I solved postponing the instantiation of IndexWriter in the method index(). Here my code :

 public void index(Book item) throws IOException{



        if (iw == null) {

                iw = new IndexWriter(FSDirectory.open(new File(directory)),
                        new IndexWriterConfig(Version.LATEST, new EnglishAnalyzer()));


            }


        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(Book.CONTENT, item.getContent(),Field.Store.YES));




       iw.addDocument(doc);
       iw.commit();

    }

Moreover I removed the instruction

indexer.close()

from add() method in the class managedBeanIB since it has to be called only when the application ends.