package com.ankurm.hibernatedemo.search; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import org.hibernate.search.engine.backend.types.Sortable; import org.hibernate.search.mapper.pojo.automaticindexing.ReindexOnUpdate; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexedEmbedded; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexingDependency; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.KeywordField; /** * Chapter 25's Hibernate Search entity, pinned to {@code hibernate-search-mapper-orm} * {@code 8.4.0.Final} (see {@code pom.xml} for why -- verified against Maven Central, NOT the * {@code 7.3.2.Final} this repo's blog post previously claimed). * *
{@code title} is {@code @FullTextField} (analyzed, tokenized, fuzzy-matchable), * {@code genre} is {@code @KeywordField} (stored whole, for exact-match filtering, never * tokenized), {@code releaseYear} is a plain {@code @GenericField} marked sortable, and * {@code director} is {@code @IndexedEmbedded} so a search on the director's name matches the * movie without {@code Director} itself needing to be {@code @Indexed}. * *
Docs: docs/25-hibernate-search.md. */ @Entity @Indexed public class Movie { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // No explicit analyzer name: the Lucene backend ships no predefined "english" analyzer out // of the box (confirmed the hard way -- naming one here without registering it via a // LuceneAnalysisConfigurer bean fails the whole application context at startup with // HSEARCH000353 "Unknown analyzer"). Omitting the attribute uses Hibernate Search's own // built-in default full-text analyzer, which is enough for this chapter's examples. @FullTextField private String title; @KeywordField private String genre; @GenericField(sortable = Sortable.YES) private int releaseYear; // @IndexedEmbedded on a @ManyToOne with no inverse side fails bootstrap outright // (HSEARCH700020: "Unable to find the inverse side of the association") -- Hibernate Search // needs to know how to find every Movie that embeds a given Director so it can reindex them // when that Director changes. Director has no @OneToMany back-reference in this repo's // model, and reindexing-on-director-update isn't something this chapter's tests exercise, so // @IndexingDependency(reindexOnUpdate = SHALLOW) opts out of that automatic reindexing // instead of adding a back-reference this model doesn't otherwise need. @ManyToOne @JoinColumn(name = "director_id") @IndexedEmbedded @IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW) private Director director; protected Movie() { // for Hibernate } public Movie(String title, String genre, int releaseYear, Director director) { this.title = title; this.genre = genre; this.releaseYear = releaseYear; this.director = director; } public Long getId() { return id; } public String getTitle() { return title; } public String getGenre() { return genre; } public int getReleaseYear() { return releaseYear; } public Director getDirector() { return director; } }