-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: Extend FullTextIndexEventListener to allow selective indxing
PostPosted: Thu Apr 14, 2011 7:40 am 
Newbie

Joined: Wed Apr 13, 2011 2:59 pm
Posts: 5
We're upgrading to H.Search 3.4 and it seems that we have hit an incompatibility issue with our old code.

In our domain model we have 'public' and 'private' photos. Public photos' metadata must be indexed and available as fulltext search results on the public web page, private photos don't. We have around 100.000 public photos and 500.000 private photos, so adding them all to the index is not a good option.

That's the code that worked perfectly for the situation stated above and that doesn't work anymore with Search 3.4.0.CR2 and H.Core 3.6.3.Final:

Our custom FullTextIndexEventListener that was checking if the updated entity was "public" or "private" and decided if must be added to the index or not:

Code:
public class SelectiveFullTextIndexEventListener extends FullTextIndexEventListener
{
   @Override
   public void onPostUpdate(PostUpdateEvent event) {
      
         Object entity = event.getEntity();
         if (entity instanceof Photo)
         {
            Photo photo = ((Photo)entity);
            
            if (Constants.VALUES_PRIVATE.equals(photo.getPrivacy()))
            {
               if ( used ) {
                  final Class<?> entityType = event.getEntity().getClass();
                      if ( searchFactoryImplementor.getDocumentBuildersIndexedEntities().containsKey( entityType )
                      || searchFactoryImplementor.getDocumentBuilderContainedEntity( entityType ) != null ) {
                         processWork( event.getEntity(), event.getId(), WorkType.DELETE, event, false );
                         if (logger.isDebugEnabled())
                            logger.debug("Deleted from index after making photo private");
                      }
                  }  //change from private-->public delete from index
            }else {
               if (logger.isDebugEnabled())
                  logger.debug("Added to full text index after updating photo to 'public'");
               super.onPostUpdate(event);
               
            }
         }
         
         
      }
}


hibernate.hbm.xml <event/> section:

Code:
        ...
        <property name="hibernate.search.autoregister_listeners">true</property>
        ...
        <event type="post-update">
            <listener class="CustomFullTextIndexEventListener"/>
        </event>
       <event type="post-insert">
            <listener class="CustomFullTextIndexEventListener"/>
        </event>
        <event type="post-delete">
            <listener class="CustomFullTextIndexEventListener"/>
        </event>
        <event type="post-collection-recreate">
            <listener class="CustomFullTextIndexEventListener"/>
        </event>
        <event type="post-collection-remove">
            <listener class="CustomFullTextIndexEventListener"/>
        </event>
        <event type="post-collection-update">
            <listener class="CustomFullTextIndexEventListener"/>
        </event>
        <event type="flush">
            <listener class="org.hibernate.event.def.DefaultFlushEventListener"/>
            <listener class="CustomFullTextIndexEventListener"/>
        </event>



The exception raised is:

Code:
2011-04-14 18:42:25,536 => INFO  Version:39 - Hibernate Search 3.4.0.CR2
2011-04-14 18:42:25,538 => ERROR FullTextIndexEventListener:122 - FullTextIndexEventListener default constructor is obsolete. Remove all explicitevent listener configuration. As of Hibernate Core 3.6 Hibernate Search will be automatically enabled if it is detected on the classpath.
2011-04-14 18:42:25,540 => ERROR HibernateManager:52 - Unable to instantiate specified event (post-update) listener class: SelectiveFullTextIndexEventListener
org.hibernate.MappingException: Unable to instantiate specified event (post-update) listener class: SelectiveFullTextIndexEventListener
   at org.hibernate.cfg.Configuration.setListeners(Configuration.java:2411)
   at org.hibernate.cfg.Configuration.parseEvent(Configuration.java:2380)
   at org.hibernate.cfg.Configuration.parseSessionFactory(Configuration.java:2302)
   at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:2263)
   at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:2216)
   at org.hibernate.cfg.Configuration.configure(Configuration.java:2131)



Any ideas on how to extend FullTextIndexEventListener in Search 3.4 and Core 3.6.3 to selectively add entities to the lucene index? or alternatively how to do the same without having to give up using listeners? doing it manually is tedious and error prone since we should add code to every DAO updating photos.

Many thanks for your help/ideas

Jordi


Top
 Profile  
 
 Post subject: Re: Extend FullTextIndexEventListener to allow selective indxing
PostPosted: Fri Apr 15, 2011 5:56 am 
Hibernate Team
Hibernate Team

Joined: Fri Oct 05, 2007 4:47 pm
Posts: 2536
Location: Third rock from the Sun
Hi,
we're having intentions to make the listener final, that's been in the comments for a long time now, as people have lots of issues when extending it; having it extensible was never an intention.

As you noticed, the constructor is now throwing an exception to make sure people notice that it's not intended to be registered by configuration.. so right I could as well make it final right now.

About your workaround: are you aware that when persisting a new entity it's going to trigger a different event which you're not skipping? And you're not avoiding the unnecessary work during delete operations? And I assume you're not Photo entity is not being embedded in collections from other entities via @IndexedEmbedded.

I think you could deal with it using another approach, which has the benefit of avoiding hacking into the error-prone FullTextIndexEventListener:
* look at org.hibernate.search.backend.impl.lucene.LuceneBackendQueueProcessorFactory
* extend it, overriding
Code:
getProcessor(List<LuceneWork> queue)

and making sure you invoke super.getProcessor but removing from the list all work which is relative to private Photo instances (you might need to index a private/public token to be able to read it from here).

* configure your new backend to replace the default one :

Code:
hibernate.search.worker.backend com.your.package.CustomSmartLuceneBackend


This won't prevent you to do some work about creating the LuceneWork, but at least the engine will be able to figure out the proper events. Also, it's expected that people replace the back end as that's a proper extension point.

_________________
Sanne
http://in.relation.to/


Top
 Profile  
 
 Post subject: Re: Extend FullTextIndexEventListener to allow selective indxing
PostPosted: Fri Apr 15, 2011 6:16 am 
Hibernate Team
Hibernate Team

Joined: Fri Oct 05, 2007 4:47 pm
Posts: 2536
Location: Third rock from the Sun
there's an open issue to properly support this: http://opensource.atlassian.com/project ... SEARCH-471
if you want you could contribute a patch

_________________
Sanne
http://in.relation.to/


Top
 Profile  
 
 Post subject: Re: Extend FullTextIndexEventListener to allow selective indxing
PostPosted: Tue Apr 19, 2011 4:25 am 
Newbie

Joined: Wed Apr 13, 2011 2:59 pm
Posts: 5
Hi Sanne

Many thanks for your help on this. It works perfectly and as you mention, without doing extra work adding/deleting entities from index unnecessarily. I post the code below, perhaps it might be of help to someone else.

I attach two versions of the overridden function you suggest, the first one works perfectly and the second one raises an exception.

Code that works:
Code:
public class SelectiveLuceneBackendQueueProcessorFactory extends LuceneBackendQueueProcessorFactory {

   @Override
   public Runnable getProcessor(List<LuceneWork> queue) {
      List<LuceneWork> list = new ArrayList<LuceneWork>();

      for (LuceneWork work: queue) {         
         if (Image.class.equals(work.getEntityClass())) {
//Only keep the LuceneWork if it is a "DELETE from index" OR an "ADD to index" of a PUBLIC image" 
            if (work.getDocument()==null || Constants.VALUES_PUBLIC.equals(work.getDocument().getField(Constants.HIB_PROPERTIES_PRIVACY).stringValue()))
               
               list.add(work);
         }         
      }

      return super.getProcessor(list);
   }
}


Code that removes a 'work' from the queue and raises the exception below:
Code:
@Override
   public Runnable getProcessor(List<LuceneWork> queue) {
      
      for (LuceneWork work: queue) {
         
         if (Image.class.equals(work.getEntityClass())) {
            //Only keep the LuceneWork if it is a "DELETE from index" OR an "ADD to index" of a PUBLIC image" 
            if (work.getDocument() != null && ! Constants.VALUES_PUBLIC.equals(work.getDocument().getField(Constants.HIB_PROPERTIES_PRIVACITAT).stringValue()))
               
               queue.remove(work);
         
         }
         
      }
      
      return super.getProcessor(queue);
   }



Exception:

Code:
org.hibernate.AssertionFailure: Exception releasing cache locks
   org.hibernate.engine.ActionQueue$AfterTransactionCompletionProcessQueue.afterTransactionCompletion(ActionQueue.java:598)
   org.hibernate.engine.ActionQueue.afterTransactionCompletion(ActionQueue.java:209)
   org.hibernate.impl.SessionImpl.afterTransactionCompletion(SessionImpl.java:602)
   org.hibernate.jdbc.JDBCContext.afterTransactionCompletion(JDBCContext.java:273)
   org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:146)
   com.wikiloc.model.hibernate.HibernateManager.commitTransaction(HibernateManager.java:141)
   com.wikiloc.model.hibernate.CommitFilter.doFilter(CommitFilter.java:281)



Is that the right approach or I'm missing something?

Thanks mil,

Jordi


Top
 Profile  
 
 Post subject: Re: Extend FullTextIndexEventListener to allow selective indxing
PostPosted: Tue Apr 19, 2011 4:56 am 
Hibernate Team
Hibernate Team

Joined: Fri Oct 05, 2007 4:47 pm
Posts: 2536
Location: Third rock from the Sun
the first one is correct, you need a defensive copy on the list: you can't change a list you are iterating or you'll get an exception - this is just basic Java rules.

The stacktrace you have shown should have a "caused by" in the logs as well pointing to the exception in your code.

_________________
Sanne
http://in.relation.to/


Top
 Profile  
 
 Post subject: Re: Extend FullTextIndexEventListener to allow selective indxing
PostPosted: Wed Apr 20, 2011 9:31 am 
Newbie

Joined: Wed Apr 13, 2011 2:59 pm
Posts: 5
We've done some testing and works fine with all operations (insert/delete/update).

Thanks much Sanne for showing us the way to go with this. We were stuck with our old code.

Jordi


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.