How to omit some objects from the index with Hibernate Search?

Jochen Source

We want to enable fulltext search on a Hibernate database for only some objectes of a specific entity. Is there a way to prevent hibernate search from indexing some instances of this entity? We do not want to filter the search results, we just want some instances to not be indexed at all.

An example: We have a database with employees, both active and retired. We don't need to be able to search retired employees. We're a very old IT company, founded in 1695, therefor we have about 2 million retired employees that we are very fond of, but don't want to index, only the 10 active ones. Is there a way we can tell Hibernate Search to only index employees where retired = false?

Regards, Jochen

hibernatehibernate-search

Answers

answered 6 years ago zmf #1

You'll need a PreUpdateEventListener, in this listener inspect the entity and determine if you want to add it to the lucene index.

This code not guaranteed to work, but hopefully you'll get the idea.

public class LuceneUpdateListener implements PreUpdateEventListener {

    protected FSDirectory directory; // = path to lucene index

    public boolean onPreUpdate(PreUpdateEvent event)  {
        if (event.getEntity() instanceof Employee ) {

                try {       

                    Employee employee = (Employee) event.getEntity();

                    //Remove on update
                    remove((Employee) event.getEntity(), (Long) event.getId(), directory);

                    //Add it back if this instance should be indexed
                    try { 
                        if (employee.shouldBeIndexed()) {
                            add((Employee) event.getEntity(), (Long) event.getId(), directory);                         
                        }
                    } 
                    catch (Exception e) {

                    }
                } 
                catch (Exception e) {
                    throw new CallbackException(e.getMessage());
                }
            }
        }
        return false;
    }


    protected synchronized void add(Employee employee, Id employeeId, FSDirectory directory) {
          try{
            IndexWriter writer = new IndexWriter(directory, new StandardAnalyzer(), false);
            Document d = LuceneDocumentFactory.makeDocument(employee);
            writer.addDocument(d);
            writer.close();
            directory.close();
            }
            catch(Exception e) { 

            }
    }

    protected synchronized void remove(Long id, FSDirectory directory) throws IOException {
            try {
                IndexReader ir = IndexReader.open(directory); 
                ir.deleteDocuments(new Term("id", id.toString()));
                ir.close();
            }        
            catch(Exception e) {                
            }   
    }

    public FSDirectory getDirectory() {
            return directory;
    }

    public void setDirectory(FSDirectory directory) {
        this.directory = directory;
    }

}

In order to index these objects outside of a hibernate event you can extract the logic out of this class, and process your employees in batch.

Also don't forget to register your listener.

answered 6 years ago Hardy #2

I don't think that you should work with the IndexReader directly in your event listener. You should instead extend (or write a new version) of the existing FullTextIndexEventListener and inspect your entity in the callback method and depending on the retired field call or not call processWork.

If you want to use Hibernate Search 4 (together with Hibernate Core 4) you will also need a custom HibernateSearchIntegrator.

This solution will work, but should be considered an interim solution until HSEARCH-471 is implemented.

comments powered by Disqus