Hibernate Search快速上手

ragnar 1年前 ⋅ 195 阅读

本文用的Hibernate Search是 5.11 版本。根据官网指导(https://hibernate.org/search/releases/5.11/#getting_started):

  • Hibernate ORM 5.4
  • Apache Lucene 5.5
  • Elasticsearch server 2.0 - 5.6 【我们没有用这个】

官方文档: https://docs.jboss.org/hibernate/search/5.11/reference/en-US/html_single/#preface

1 使用mavan引入依赖

<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-search-orm</artifactId>
   <version>{latest_stable}</version>
</dependency>

如果把索引保存到Elasticsearch,则需要引入下面这个依赖

<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-search-elasticsearch</artifactId>
   <version>{latest_stable}</version>
</dependency>

2 配置

2.1 配置文件

项目中使用了JPA,所以可以这样配置:

spring:
  jpa:
    properties:
      # 目录提供者--文件系统
      hibernate.search.default.directory_provider: filesystem
      # 指定Lucene索引文件的存储目录
      hibernate.search.default.indexBase: /var/lucene/indexes

如果只是用了Hibernate:

# 目录提供者--文件系统
hibernate.search.default.directory_provider: filesystem
# 指定Lucene索引文件的存储目录
hibernate.search.default.indexBase: /var/lucene/indexes

2.2 实体类注解配置

  • 定义哪个实体类需要被索引 -- 加@Indexed注解
  • 指定唯一标识 -- 默认是用@Id注解的字段,但我们可以用@DocumentId注解来覆盖
  • 选择要被索引搜索的字段 -- 用@Field注解来标识,参数如下:
    • index=Index.YES -- 表示内容将被索引
    • analyze=Analyze.YES -- 表示内容会被Lucene默认的分析器去分析
    • store=Store.NO -- 表示字段的原始数据不保存到索引中,不影响搜索查询【因为Hibernate Search在执行一个Lucene查询时,是以查找与查询匹配的实体的数据库标识符(主键ID),然后再到数据库中查询】。
  • 非字符串类型要加对应的编码注解 -- Lucene的索引基本上是基于字符串的,非字符串类型被编码为更适合于范围查询的表示形式
    • 数字类型 -- 如:@Field(bridge = @FieldBridge(impl = IntegerBridge.class))
    • 布尔类型 -- 如:@Field(bridge = @FieldBridge(impl = BooleanBridge.class))
    • 日期时间类型 -- @DateBridge

3 创建索引

3.1 重新成生Lucene索引

https://hibernate.org/search/documentation/getting-started/5.11/#indexing

FullTextSession fullTextSession = org.hibernate.search.Search.getFullTextSession((Session) entityManager.getDelegate());
fullTextSession.createIndexer().startAndWait();

JPA的话可以用下面的代码:

FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
fullTextEntityManager.createIndexer().startAndWait();

3.2 Luke检查生成的索引

执行完代码后,就可以在前面配置的目录(/var/lucene/indexes)下看到生成的Lucene索引文件。 生成的索引可以用Luke(可以访问Lucene索引文件)来检查,Luke的功能:

  • 浏览文档、索引字词和发布列表
  • 在索引中搜索
  • 执行索引维护:索引健康检查、索引优化(在运行此备份之前进行备份!
  • 测试您的自定义 Lucene 分析器(Tokenizer/CharFilter/TokenFilter)

选择合适Luke版本下载:https://github.com/DmitryKey/luke/releases/
Lucene 5.5 对应 Luke:https://github.com/DmitryKey/luke/releases/tag/luke-5.5.0

4 搜索

流程如下:

// 获取全文实类管理对象
EntityManager em = entityManagerFactory.createEntityManager();
FullTextEntityManager fullTextEntityManager =
    org.hibernate.search.jpa.Search.getFullTextEntityManager(em);

// 开始事务
em.getTransaction().begin();

// 用查询DSL创建一个原生的Lucene查询 --create native Lucene query unsing the query DSL
// 也可以用Lucene查询解析类来写 --alternatively you can write the Lucene query using the Lucene query parser
// 用Lucene编辑API也可以,但推荐使用 Hibernate Search 的 DSL --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 luceneQuery = qb
  .keyword()
  .onFields("title", "subtitle", "authors.name")
  .matching("Java rocks!")
  .createQuery();

// 包装Lucene查询 --wrap Lucene query in a javax.persistence.Query
javax.persistence.Query jpaQuery =
    fullTextEntityManager.createFullTextQuery(luceneQuery, Book.class);

// 执行搜索 --execute search
List result = jpaQuery.getResultList();

// 提交事务
em.getTransaction().commit();
em.close();

5 分词

5.1 配置分词器

  • 在配置文件里配置
hibernate.search.analyzer=org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer
  • 在实体类上配置@Analyzer注解指定
  • 在实体类的字段上配置@Analyzer注解指定

5.2 自定义分词器

@AnalyzerDef注解可以在任何实体上定义声明分词器,然后可以在任意实体上通过@Analyzer注解引用它。 如下:

@Entity
@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 {

  @Id
  @GeneratedValue
  @DocumentId
  private Integer id;

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

全部评论: 0

    我有话说:

    目录