7.3. 应用程序的 Hibernate 搜索


7.3.2. 使用 Maven 启用 Hibernate Search

在 Maven 项目中使用以下配置添加 hibernate-search-orm 依赖项:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-search-orm</artifactId>
      <version>5.5.1.Final-redhat-1</version>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-search-orm</artifactId>
    <scope>provided</scope>
  </dependency>
</dependencies>
Copy to Clipboard Toggle word wrap

7.3.3. 添加注解

对于本节,请考虑您拥有包含图书详细信息的数据库的示例。您的应用包含 Hibernate 管理的类 example.Bookexample.Author,您想要为您的应用添加免费文本搜索功能以启用搜索图书。

示例:在添加 Hibernate 搜索特定注释前实体书和授权

package example;
...
@Entity
public class Book {

  @Id
  @GeneratedValue
  private Integer id;

  private String title;

  private String subtitle;

  @ManyToMany
  private Set<Author> authors = new HashSet<Author>();

  private Date publicationDate;

  public Book() {}

  // standard getters/setters follow here
  ...
}
Copy to Clipboard Toggle word wrap

package example;
...
@Entity
public class Author {

  @Id
  @GeneratedValue
  private Integer id;

  private String name;

  public Author() {}

  // standard getters/setters follow here
  ...
}
Copy to Clipboard Toggle word wrap

要达到此目的,您必须向 Book 和 Author 类添加一些注释。第一个注释 @Indexed 将 Book 标记为可索引。按照设计,Hibernate Search 在索引中存储一个未描述的 ID,以确保给定实体的索引不可变。@DocumentId 标记用于此目的的属性,并且在大多数情况下与数据库主密钥相同。如果存在 @Id 注释,则 @Document Id 注释是可选的。

接下来,您要使可搜索的字段必须标记为。在本例中,以标题 和副 标题 开头,并以 @Field 标注。参数 index=Index.YES 将确保对文本进行索引,而 analyze=Analyze.YES 则确保将使用默认的 Lucene 分析器分析文本。通常,分析意味着将句子划分为单独的单词,并可能不包括 "a"或"the "等常见词语。我们稍后将深入探讨分析器。我们在 @Field,store=Store.NO 中指定的第三个参数可确保实际数据不会存储在索引中。此数据存储在索引中是否与搜索它的能力无关。从 Lucene 的角度来看,在索引创建后不需要保留数据。存储它的好处是通过 预测 检索它的功能。

如果不进行预测,Hibernate Search 默认为执行 Lucene 查询,以查找符合查询条件的实体的数据库标识符,并使用这些标识符从数据库中检索受管对象。对预测或预测的决定必须逐例做出。建议使用默认行为,因为它返回受管对象,而 仅返回对象数组。请注意,index=Index.YES,analyze=Analyze.YESstore=Store.NO 是这些参数的默认值,可以省略。

尚未讨论的另一个注释是 @DateBridge。此注释是 Hibernate Search 中的内置字段桥之一。Lucene 索引纯粹基于字符串。因此,Hibernate Search 必须将索引字段的数据类型转换为字符串,反之亦然。提供了一系列预定义的网桥,包括 DateBridge,它使用指定的解析将 java.util.Date 转换为字符串。如需了解更多详细信息,请参阅 网桥

这将为我们保留 @IndexedEmbedded。此注释用于为所属实体(@ManyToMany、@*ToOne@Embedded@ElementCollection)索引关联实体。这是必要的,因为 Lucene 索引文档是一个扁平数据结构,它不知道对象关系。为确保作者姓名可以搜索,您必须确保将姓名作为本书本身的一部分进行索引。在 @IndexedEmbedded 的顶部,您还必须标记您希望在 @Indexed 索引中包含的关联实体的所有字段。如需了解更多详细信息,请参阅 嵌入式对象和关联对象

这些设置现在应该已足够。有关实体映射的详情 ,请参阅映射实体

示例:添加 Hibernate 搜索注解后的实体

package example;
...
@Entity

public class Book {

  @Id
  @GeneratedValue
  private Integer id;

  private String title;

  private String subtitle;

  @Field(index = Index.YES, analyze=Analyze.NO, store = Store.YES)
  @DateBridge(resolution = Resolution.DAY)
  private Date publicationDate;

  @ManyToMany
  private Set<Author> authors = new HashSet<Author>();

  public Book() {
  }

  // standard getters/setters follow here
  ...
}
Copy to Clipboard Toggle word wrap

package example;
...
@Entity
public class Author {

  @Id
  @GeneratedValue
  private Integer id;

  private String name;

  public Author() {
  }

  // standard getters/setters follow here
  ...
}
Copy to Clipboard Toggle word wrap

7.3.4. 索引

Hibernate Search 将通过 Hibernate 核心以透明的方式索引每个实体保留、更新或删除。但是,您必须为数据库中已存在的数据创建初始 Lucene 索引。添加上述属性和注释后,应当触发工作簿中的初始批处理索引。您可以使用以下代码片段之一来实现此目的(请参阅 ):

示例:使用 Hibernate 会话索引数据

FullTextSession fullTextSession = org.hibernate.search.Search.getFullTextSession(session);
fullTextSession.createIndexer().startAndWait();
Copy to Clipboard Toggle word wrap

示例:使用 Jakarta Persistence 来索引数据

EntityManager em = entityManagerFactory.createEntityManager();
FullTextEntityManager fullTextEntityManager = org.hibernate.search.jpa.Search.getFullTextEntityManager(em);
fullTextEntityManager.createIndexer().startAndWait();
Copy to Clipboard Toggle word wrap

执行上述代码后,您应能够在 /var/lucene/indexes/example.Book 下看到 Lucene 索引。使用 Luke 检查此索引以帮助您了解 Hibernate 搜索的工作原理。

7.3.5. 搜索

要执行搜索,请使用 Lucene API 或 Hibernate Search query DSL 创建 Lucene 查询查询。将查询嵌套在 org.hibernate.Query 中,以从 Hibernate API 获取所需的功能。以下代码根据索引字段准备查询。执行代码将返回 Books 列表。

示例:使用 Hibernate 搜索会话创建和执行搜索

FullTextSession fullTextSession = Search.getFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();

// create native Lucene query using the query DSL
// alternatively you can write the Lucene query using the Lucene query parser
// or the Lucene programmatic API. The Hibernate Search DSL is recommended though
QueryBuilder qb = fullTextSession.getSearchFactory()
    .buildQueryBuilder().forEntity( Book.class ).get();
org.apache.lucene.search.Query query = qb
  .keyword()
  .onFields("title", "subtitle", "authors.name", "publicationDate")
  .matching("Jakarta rocks!")
  .createQuery();

// wrap Lucene query in a org.hibernate.Query
org.hibernate.Query hibQuery =
    fullTextSession.createFullTextQuery(query, Book.class);

// execute search
List result = hibQuery.list();

tx.commit();
session.close();
Copy to Clipboard Toggle word wrap

示例:使用 Jakarta Persistence 创建和执行搜索

EntityManager em = entityManagerFactory.createEntityManager();
FullTextEntityManager fullTextEntityManager =
    org.hibernate.search.jpa.Search.getFullTextEntityManager(em);
em.getTransaction().begin();

// create native Lucene query using the query DSL
// alternatively you can write the Lucene query using the Lucene query parser
// or the Lucene programmatic API. The Hibernate Search DSL is recommended though
QueryBuilder qb = fullTextEntityManager.getSearchFactory()
    .buildQueryBuilder().forEntity( Book.class ).get();
org.apache.lucene.search.Query query = qb
  .keyword()
  .onFields("title", "subtitle", "authors.name", "publicationDate")
  .matching("Jakarta rocks!")
  .createQuery();

// wrap Lucene query in a javax.persistence.Query
javax.persistence.Query persistenceQuery =
    fullTextEntityManager.createFullTextQuery(query, Book.class);

// execute search
List result = persistenceQuery.getResultList();

em.getTransaction().commit();
em.close();
Copy to Clipboard Toggle word wrap

7.3.6. Analyzer

假设索引图书实体的标题 重构:改进现有代码的设计,并且 以下查询需要点击: 重构、重 构、 重构重构。在 Lucene 中选择一个分析器类,该类在索引和搜索时应用单词强制。Hibernate Search 提供多种配置分析器的方法(请参阅 默认分析器和按类分析器 ),了解更多信息:

  • 在配置文件中设置 analyzer 属性。指定类成为默认分析器。
  • 在实体级别上设置 @Analyzer 注释。
  • 在字段级别上设置 @Analyzer 注释。

指定要使用的完全限定类名称或分析器,或者查看由 @AnalyzerDef 注释定义的分析器,以及 @Analyzer 注释。使用 Solr 分析器框架及其工厂选择后一个选项。有关工厂类的更多信息,请参阅 Solr JavaDoc 或阅读 Solr Wiki 的对应章节。

在示例中,两个过滤器工厂使用 StandardTokenizerFactory:LowerCaseFilterFactory 和 SnowballPorterFilterFactory。令牌者在标点字符和连字符分割单词,但保持电子邮件地址和互联网主机名不变。标准令牌程序是这一操作和其他常规操作的理想选择。小写过滤器将令牌中的所有字母转换为小写,snowball 过滤器则应用特定于语言的逻辑。

如果使用 Solr 框架,请使用带任意数量的过滤器的令牌程序。

示例:使用 @AnalyzerDef 和 Solr Framework 来定义和使用分析器

@Indexed
@AnalyzerDef(
   name = "customanalyzer",
   tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
   filters = {
      @TokenFilterDef(factory = LowerCaseFilterFactory.class),
      @TokenFilterDef(factory = SnowballPorterFilterFactory.class,
         params = { @Parameter(name = "language", value = "English") })
 })
public class Book implements Serializable {

  @Field
  @Analyzer(definition = "customanalyzer")
  private String title;

  @Field
  @Analyzer(definition = "customanalyzer")
  private String subtitle;

  @IndexedEmbedded
  private Set authors = new HashSet();

  @Field(index = Index.YES, analyze = Analyze.NO, store = Store.YES)
  @DateBridge(resolution = Resolution.DAY)
  private Date publicationDate;

  public Book() {
  }

  // standard getters/setters follow here
  ...
}
Copy to Clipboard Toggle word wrap

使用 @AnalyzerDef 定义分析器,然后使用 @Analyzer 将它应用到实体和属性。在该示例中,定义了 customanalyzer,但不应用于实体。分析器仅适用于 标题 和副标题 属性。分析器定义是全局的。为实体定义分析器,并根据需要为实体重新利用定义。

Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2026 Red Hat
返回顶部