Red Hat

Hibernate Search 4.1 CR1: soft deletes

Posted by Emmanuel Bernard    |       |    Tagged as Hibernate Search

This release will hopefully be the last before Hibernate Search 4.1 final. If you want to give feedback, now is the time :) We are simultaneously releasing Hibernate Search 3.4.2 as a minor bug fix release.

The main improvement in this candidate for release is the ability to intercept indexing operations and change them. In the team we nicknamed it the Soft Delete feature even if it can do much more. At first look, it seems like a barbarian feature but it enables a lot of interesting use cases.

Indexing interception

In some situations, you do not want to index all the entities (of a given type). For example, I want my readers to search my blog entries only when they are in PUBLISHED state. If they are in DRAFT, they should not appear in the results. Of course, to do that you can use a boolean query restriction or even better a declarative filter. Nevertheless, these DRAFT blogs are still indexed. The situation is even more critical if the majority of your entities should not be searchable. An example is invoices that should not be searchable when put in archive mode.

Indexing interception lets you decide if an entity is worthy of being indexed. The big benefits are:

  • less work at runtime: no bridge conversion, no analyzer phase, and no writes in the index
  • a smaller and more manageable index: smaller indexes makes faster queries, fit better in memory and are easier to backup and copy

Alright so how do I do this?

  • write an EntityIndexingInterceptor
  • Mark the entity as being intercepted using @Indexed.interceptor
/**
 * Only index blog when it is in published state
 *
 * @author Emmanuel Bernard <emmanuel@hibernate.org>
 */
public class IndexWhenPublishedInterceptor implements EntityIndexingInterceptor<Blog> {
    @Override
    public IndexingOverride onAdd(Blog entity) {
        if (entity.getStatus() == BlogStatus.PUBLISHED) {
            return IndexingOverride.APPLY_DEFAULT;
        }
        return IndexingOverride.SKIP;
    }

    @Override
    public IndexingOverride onUpdate(Blog entity) {
        if (entity.getStatus() == BlogStatus.PUBLISHED) {
            return IndexingOverride.UPDATE;
        }
        return IndexingOverride.REMOVE;
    }

    @Override
    public IndexingOverride onDelete(Blog entity) {
        return IndexingOverride.APPLY_DEFAULT;
    }

    @Override
    public IndexingOverride onCollectionUpdate(Blog entity) {
        return onUpdate(entity);
    }
}
@Entity
@Indexed(interceptor=IndexWhenPublishedInterceptor.class)
public class Blog {
    @Id
    @GeneratedValue
    public Integer getId() { return id; }
    public void setId(Integer id) {  this.id = id; }
    private Integer id;

    @Field
    public String getTitle() { return title; }
    public void setTitle(String title) {  this.title = title; }
    private String title;

    public BlogStatus getStatus() { return status; }
    public void setStatus(BlogStatus status) {  this.status = status; }
    private BlogStatus status;

    [...]
}

If you look at IndexWhenPublishedInterceptor, you will see that we only index the entity when it is in PUBLISHED state and we skip or remove it from the index otherwise.

This feature is still experimental as we might add more transitions depending on your feedback.

Get the release

This release is (hopefully) the last of the 4.1 series before 4.1 final. Try it out:

Hibernate Search 3.4.2

This release fixed a few bugs in particular a regression on how collections are indexed. Thanks to Guillaume Smet for his work. We encourage users stuck with the 3.4 series to upgrade. You can get the release on SourceForge and it should be available on our Maven repository within the next few hours or days.

back to top