<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<version>${hibernate-search.version}</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-smartcn</artifactId>
<version>${lucene.version}</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>${lucene.version}</version>
</dependency>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.search.default.indexBase">indexes/</prop> <!-- 索引儲存路徑 -->
<prop key="hibernate.search.analyzer">org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer</prop> <!-- 全域中文分詞 -->
</props>
</property>
</bean>
@Indexed
@AnalyzerDef(name = "enTopicAnalyzer",
charFilters = @CharFilterDef(factory = HTMLStripCharFilterFactory.class),
tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
filters = {
@TokenFilterDef(factory = StandardFilterFactory.class),
@TokenFilterDef(factory = StopFilterFactory.class),
@TokenFilterDef(factory = PhoneticFilterFactory.class, params = @Parameter(name="encoder", value="DoubleMetaphone")),
@TokenFilterDef(factory = SnowballPorterFilterFactory.class, params = @Parameter(name="language", value="English"))
})
public class Topic {
@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
@Analyzer(definition = "enTopicAnalyzer")
private String title;
@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
@Analyzer(definition = "enTopicAnalyzer")
private String content;
@Enumerated(EnumType.STRING)
@Field(index=Index.YES, analyze=Analyze.NO, store=Store.NO, bridge=@FieldBridge(impl=EnumBridge.class))
private TopicStatus status;
}
FullTextSession fts = Search.getFullTextSession(sessionFactory.openSession());
try {
fts.createIndexer().startAndWait(); // 全量建立索引
} catch (InterruptedException e) { log.error(e); }
finally { fts.close(); }
QueryBuilder qb = fts.getSearchFactory().buildQueryBuilder().forEntity(Show.class).get();
org.apache.lucene.search.Query luceneQuery = qb.keyword()
.onFields("title", "content")
.matching(keyword)
.createQuery();
FullTextQuery hibernateQuery = fts.createFullTextQuery(luceneQuery, Show.class);
List<Show> results = hibernateQuery.list();
MustJunction must = qb.bool()
.must(qb.keyword().onFields("title", "content").matching(keyword).createQuery());
if (status != null) {
must.must(qb.keyword().onField("status").matching(status).createQuery());
}
if (excludeStatus != null) {
must.must(qb.keyword().onField("status").matching(excludeStatus).createQuery()).not();
}
if (username != null) {
must.must(qb.keyword().onField("owner.username").ignoreFieldBridge().matching(username).createQuery());
}
FullTextQuery query = fts.createFullTextQuery(must.createQuery(), Topic.class);
hibernate.search.analyzer=org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer@Indexed @Analyzer(impl=SmartChineseAnalyzer.class)@Field(analyzer=@Analyzer(impl=SmartChineseAnalyzer.class))需額外引入 lucene-analyzers-smartcn 依賴。其他熱門分詞器:IKAnalyzer、paoding、mmseg4j。
createIndexer()Hibernate Search 無縫整合 Hibernate ORM 與 Lucene,透過註解驅動索引映射、支援靈活的分詞器鏈與多條件組合查詢。關鍵成功因子:正確配置中文分詞器、建立索引流程自動化、善用 MustJunction 構建複雜查詢邏輯。