Hibernate Search itself treats all entities as read-only, always: it never calls a setter anywhere. So no, there’s no built-in mechanism for this exact solution. I’m not sure I would want to introduce this in Hibernate Search since it could have unexpected ramifications.
That being said, what you’re trying to achieve essentially amounts to building a persisted queue of “reindexing events”, to be processed asynchronously. This is something we’ve wanted to address for a long time (https://hibernate.atlassian.net/browse/HSEARCH-2364), and which will probably get solved when we start working on support for clustered applications (https://hibernate.atlassian.net/browse/HSEARCH-3281). It will happen for sure, but there are more pressing matters at the moment.
Implementing this on the user side will be challenging, mainly because of
@IndexedEmbedded: an entity
A index-embedding entity
B may need to be reindexed when
B is modified and
A is not, so the condition may be much more complex than just “if indexedAt < updatedAt then reindex”.
On very simple mappings (without
@IndexedEmbedded and without any complex, custom bridge), I suppose you could implement this in a relatively simple way. You will need to:
- Make sure
updatedAt is correctly updated every time the entity is modified; you can take some inspiration from
org.hibernate.search.mapper.orm.event.impl.HibernateSearchEventListener to do that: it’s a listener to Hibernate ORM change events.
- Periodically reindex using a
SearchIndexingPlan as described here and here, updating “indexedAt” on your entities as you reindex them.
You will, however, need to rely on soft deletes in you database in order to detect deleted entities and delete the corresponding documents from the index.
On more complex mappings (with
@IndexedEmbedded), you will have to use the same mechanism on every single entity that can possibly be indexed-embedded, even those not annotated with
@Indexed. Then you will process them the same way as above, taking care to call
indexingPlan.delete even on non-
@Indexed entities, at least on those that can possibly be indexed-embedded.
Note that a more efficient approach, if you don’t expect any transient failure when indexing, would be to store “indexedAt” globally instead of per-entity, e,g. in a dedicated utility table. You’ll update it once you’re done reindexing everything. This means you won’t have to write every entity to the database just to reindex them.