搜索

1.1 JPA配置

spring bean配置文件中
org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
的jpaProperties属性集合增加如下配置:

<prop key="hibernate.search.autoregister_listeners">true</prop>
<prop key="hibernate.search.default.directory_provider">filesystem</prop>
<prop key="hibernate.search.default.indexBase">lucene/indexes</prop>
<prop key="hibernate.search.default_null_token">_null_</prop>


autoregister_listeners:自动注册监听器,即在hibernate监听到对象插入、更新、删除时自动更新对象索引__
directory_provider:可选值包括ram、filesystem等,具体可参考官方文档__
indexBase:对应上一项配置为filesystem,设定索引存放的根路径。__
default_null_token:默认空值标记,此项默认值即为_null_可以不用配置__

## 1.2 索引实体注解配置

### @Indexed

index属性指定索引名称(也对应于文件系统中目录名称),不指定默认类的全名。示例:

@Indexed(index="requirement")
public class Requirement extends Backlog {
...
}

### @DocumentId

用于保证索引实体的唯一性。注解在主键上。采用JPA方式时,如果指定了@Id则不再需要标注该注解。


### @Field

index 指定是否索引,默认Index.YES
analyze 是否分析(分词器进行分词),默认Analyze.YES,目前对于不会搜索值的片段的字段都设置为了NO
store是否存储,默认Store.NO,设置为YES将占用索引空间,但支持投影,即直接从索引库得到字段值。

示例

@Field(index = Index.YES, analyze = Analyze.NO, store = Store.YES)
private String type;

@Field(index = Index.YES, analyze = Analyze.YES, store = Store.YES)
private String descr;


### @IndexedEmbedded

对需要索引的关联对象采用此注解

@IndexedEmbedded(indexNullAs = IndexedEmbedded.DEFAULT_NULL_TOKEN)
private User assignee;

indexNullAs = IndexedEmbedded.DEFAULT_NULL_TOKEN,当关联对象是空时,存储为配置的null标记,默认不存储,根据实际需要配置此项(是否要根据空值进行查询)。

### @DateBridge
日期格式存储桥接转换
resolution = org.hibernate.search.annotations.Resolution.SECOND,存储到秒,可选:
1) Resolution.DAY
2) Resolution.HOUR
3) Resolution.MILLISECOND
4) Resolution.MINUTE
5) Resolution.MONTH
6) Resolution.SECOND
7) Resolution.YEAR

# 2.API

官方文档Example 1.9中一个完整的简单例子

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

// create native Lucene query unsing 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")
.matching("Java 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();

**需要注意的是搜索必须包含在一个事务内,比如搜索方法上需要有@Transactional的注解。**
## 2.1 Query API
###QueryBuilder
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(entityClass).get();

###关键字查询

Query luceneQuery = qb.keyword().onField("descr").matching("搜索").createQuery();
keyword()方法意味着你正在尝试着去查询一个指定的词语。onField()方法指定查询哪个Lucene field。matching()方法告诉查询哪个词语。最后createQuery()方法创建Lucene query对象

###语句查询

Query luceneQuery = qb.phrase().onField("descr").matching("过滤器").createQuery();

目前主要使用此查询,因为使用keyword查询用目前默认标准分析器,查询“我们”与“们我”都会得到相同的结果

###通配符查询

Query luceneQuery = qb.keyword().wildcard().onField("id").matching("*").createQuery();
用于返回全部记录

###范围查询

TermRangeQuery query = new TermRangeQuery(field,20090101","20090105",true,true);
最后两个参数分别为是否包含起始值,目前主要用于日期范围搜索。

###组合查询

BooleanQuery boolQuery = new BooleanQuery();
boolQuery.add(lucenequery,Occur.MUST);
...
SHOULD: query之间是或关系。
MUST:query之间是并关系。
MUST NOT:必须不包含该query。

###分页

FullTextQuery ftQuery = fullTextEntityManager.createFullTextQuery(boolQuery, Backlog.class);
ftQuery .setFirstResult(15); //从第几条记录开始
ftQuery .setMaxResults(10); //返回几条记录

###排序

ftQuery.setSort(new Sort(new SortField("updated", SortField.STRING, true)));

###返回结果

ftQuery.getResultList();


## 2.2 结果转换及排序特殊处理

### 结果转换
由于索引中存储关联对象时,只保存了键值,搜索结果返回前端时需要转换为相应对象,故利用hibernate提供的ResultTransformer接口进行扩展,定义了BacklogSearchResultTransformer接口及相应实现类HtmlResultTransformerImpl(已弃用)及ObjectResultTransformerImpl进行搜索结果的逐项转换。
使用示例如下:

FullTextQuery ftQuery = fullTextEntityManager.createFullTextQuery(andQuery, entityClass);
if (resultTransformer != null) {
ftQuery.setResultTransformer(resultTransformer);
}
在调用getResultList()时会调用转换类相应方法进行转换。另外需要注意的是接口使用之间要调用接口的initDictTranslateMap方法进行初始化数据的准备,并且是每次调用前都要执行。
###排序
同样由于索引中存储关联对象只保存了键值,如果按相应关联对象进行排序时,如果不进行处理则实际上是按相应的键值(id)进行排序而不是根据相应的名称,因此在LuceneSortFieldFactory的基础上扩展了BacklogSortFieldFactory进行了相应排序字段的排序处理。
使用示例如下:

Sort sort = new Sort(sortFieldFactory.createSortField(pageAndSort.getSortField(), pageAndSort.isDesc()));
ftQuery.setSort(sort);

原文地址:https://www.cnblogs.com/suncj/p/4256645.html