hibernate search采用apache
lucene做全文索引,在3.0版本中,hibernate search 只支持对个单个实体单个目录和通过hash算法来定位目录,进行索引的添加,而删除是查找所有子目录,对于更新操作也是先删除后添加。这种情况对于某些索引结构可以按特定规则来划分的情况,性能上不是太适合。本来是可以通过实现IndexShardingStrategy和 DirectoryProvider这两个接口来完成自定义目录搜索。但是IndexShardingStrategy这个接口开放的方法很局限性。我已经将这个接口的定义建议提交给了hibernate search Team,可能他们没有考虑到这种情况。我自己动手修改了hibernate search 3.0.1的源代码来实现。
复制内容到剪贴板
代码:
// $Id: IndexShardingStrategy.java 14012 2007-09-16 19:57:36Z hardy.ferentschik $
package org.hibernate.search.store;
import java.io.Serializable;
import java.util.Properties;
import org.apache.lucene.document.Document;
import org.apache.lucene.search.Query;
/**
* Defines how a given virtual index shards data into different DirectoryProviders
*
* @author Emmanuel Bernard
*/
public interface IndexShardingStrategy {
/**
* provides access to sharding properties (under the suffix sharding_strategy)
* and provide access to all the DirectoryProviders for a given index
*/
void initialize(Properties properties, DirectoryProvider[] providers);
/**
* Ask for all shards (eg to query or optimize)
*/
DirectoryProvider[] getDirectoryProvidersForAllShards();
/**
* return the DirectoryProvider where the given entity will be indexed
*/
DirectoryProvider getDirectoryProviderForAddition(Class entity, Serializable id, String idInString, Document document);
/**
* return the DirectoryProvider(s) where the given entity is stored and where the deletion operation needs to be applied
* id and idInString can be null. If null, all the directory providers containing entity types should be returned
*/
/***********hibernate search code**********
DirectoryProvider[] getDirectoryProvidersForDeletion(Class entity, Serializable id, String idInString);
*****************************************/
/****************add by Jerry*************/
public DirectoryProvider[] getDirectoryProvidersForDeletion(Class entity,Serializable id, String idInString, Document document);
public DirectoryProvider[] getDirectoryProvidersForSearch(Query query);
/*****************************************/
}
修改这接口后,一些相关的引用和实现类要进行修改,原来本身实现类加上参数签名就可以。
复制内容到剪贴板
代码:
org.hibernate.search.query.FullTextQueryImpl类的buildSearcher方法中的代码
/***********hibernate search code**********
final DirectoryProvider[] directoryProviders =
builder.getDirectoryProviderSelectionStrategy().getDirectoryProvidersForAllShards();
*****************************************/
/****************add by Jerry*************/
final DirectoryProvider[] directoryProviders =
builder.getDirectoryProviderSelectionStrategy().getDirectoryProvidersForSearch(luceneQuery);
/*****************************************/
org.hibernate.search.backend.impl.lucene.LuceneBackendQueueProcessor更改接口相应方法名
org.hibernate.search.store.DirectoryProviderFactory类的createDirectoryProviders方法中的代码
/***********hibernate search code**********
for (Map.Entry entry : indexProps[0].entrySet()) {
if ( ( (String) entry.getKey() ).startsWith( SHARDING_STRATEGY ) ) {
shardingProperties.put( entry.getKey(), entry.getValue() );
}
}
******************************************/
/****************add by Jerry*************/
for (String key : indexProps[0].stringPropertyNames()) {
if ( key.startsWith( SHARDING_STRATEGY ) ) {
shardingProperties.put( key, indexProps[0].getProperty(key) );
}
}
/*****************************************/
org.hibernate.search.reader.SharedReaderProvider类的initialize方法中的代码
/***********hibernate search code**********
perDirectoryProviderManipulationLocks = Collections.unmodifiableMap( perDirectoryProviderManipulationLocks );
******************************************/
}
/****************add by Jerry*************/
public void addLock(DirectoryProvider dp){
if(perDirectoryProviderManipulationLocks.get(dp)==null)
perDirectoryProviderManipulationLocks.put( dp, new ReentrantLock() );
}
/*****************************************/
自定义动态目录分配实现类
复制内容到剪贴板
代码:
package com.search.store;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.hibernate.HibernateException;
import org.hibernate.search.SearchException;
import org.hibernate.search.reader.ReaderProvider;
import org.hibernate.search.reader.SharedReaderProvider;
import org.hibernate.search.store.DirectoryProvider;
import org.hibernate.search.store.FSDirectoryProvider;
import org.hibernate.search.store.IndexShardingStrategy;
public class LocalIndexDynamicShardingStrategy implements IndexShardingStrategy {
private static Log log = LogFactory.getLog( LocalIndexDynamicShardingStrategy.class );
private static final String LOCAL_FIELD = "artistCityId";
private DirectoryProvider[] providers;
private HashMap<String,DirectoryProvider> providerMap=new HashMap<String,DirectoryProvider>();
public void initialize(Properties properties, DirectoryProvider[] providers) {
this.providers = providers;
localDirectoryToMap(null);
System.out.println();
}
public DirectoryProvider[] getDirectoryProvidersForAllShards() {
return mapToArray();
}
public DirectoryProvider getDirectoryProviderForAddition(Class entity,
Serializable id, String idInString, Document document) {
String key=docKey(document);
return localDirectoryToMap(key);
}
public DirectoryProvider[] getDirectoryProvidersForDeletion(Class entity,
Serializable id, String idInString, Document document) {
String key=docKey(document);
if(key.equals(""))return mapToArray();
return new DirectoryProvider[] { localDirectoryToMap(key) };
}
public DirectoryProvider[] getDirectoryProvidersForSearch(Query query) {
String key=docKey(query);
if(key.equals(""))return mapToArray();
return new DirectoryProvider[] { localDirectoryToMap(key) };
}
private DirectoryProvider[] mapToArray(){
int size=providerMap.size();
Collection<DirectoryProvider> dps=providerMap.values();
return dps.toArray(new DirectoryProvider[size]);
}
private DirectoryProvider localDirectoryToMap(String key){
LocalDirectoryProvider localdp=null;
if(providers[0] instanceof LocalDirectoryProvider){
localdp=(LocalDirectoryProvider) providers[0];
}
FSDirectory dir=localdp.getDirectory();
File indexRoot=dir.getFile();
if(key==null){
File[] subIndex=indexRoot.listFiles();
for(File sub:subIndex){
localDirectoryToMap(sub.getName());
}
return localdp;
}
DirectoryProvider dp=providerMap.get(key);
if(dp!=null)return dp;
File indexFile=new File(indexRoot,key);
String indexName="";
boolean create = !indexFile.exists();
FSDirectory directory = null;
try {
indexName=indexFile.getCanonicalPath();
directory = FSDirectory.getDirectory( indexName );
if ( create ) {
log.debug( "Initialize index: '" + indexFile + "'" );
IndexWriter iw = new IndexWriter( directory, new StandardAnalyzer(), create );
iw.close();
}
} catch (IOException e) {
throw new HibernateException( "Unable to initialize index: " + indexFile, e );
}
dp=new LocalDirectoryProvider(indexName,localdp.getIndexProps(),localdp.getSearchFactoryImplementor());
ReaderProvider rp=localdp.getSearchFactoryImplementor().getReaderProvider();
if(rp instanceof SharedReaderProvider)((SharedReaderProvider)rp).addLock(dp);
providerMap.put(key, dp);
return dp;
}
private String docKey(Document doc) {
if(doc==null)return "";
String sid = doc.get(LOCAL_FIELD);
return sid;
}
private String docKey(Query query) {
String sid = "";
HashSet<Term> terms = new HashSet<Term>();
query.extractTerms(terms);
for (Term tr : terms) {
if (tr.field().equals(LOCAL_FIELD)) {
sid = tr.text();
return sid;
}
}
return sid;
}
}
自定义静态目录分配实现类
复制内容到剪贴板
代码:
package com.search.store;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.hibernate.HibernateException;
import org.hibernate.search.SearchException;
import org.hibernate.search.store.DirectoryProvider;
import org.hibernate.search.store.FSDirectoryProvider;
import org.hibernate.search.store.IndexShardingStrategy;
public class LocalIndexStaticShardingStrategy implements IndexShardingStrategy {
private static Log log = LogFactory.getLog( LocalIndexStaticShardingStrategy.class );
private static final String LOCAL_FIELD = "artistCityId";
private DirectoryProvider[] providers;
public void initialize(Properties properties, DirectoryProvider[] providers) {
this.providers = providers;
}
public DirectoryProvider[] getDirectoryProvidersForAllShards() {
return providers;
}
public DirectoryProvider getDirectoryProviderForAddition(Class entity,
Serializable id, String idInString, Document document) {
int key=docKey(document);
return providers[key];
}
public DirectoryProvider[] getDirectoryProvidersForDeletion(Class entity,
Serializable id, String idInString, Document document) {
int key=docKey(document);
if(key==0)return providers;
return new DirectoryProvider[] { providers[key] };
}
public DirectoryProvider[] getDirectoryProvidersForSearch(Query query) {
int key=docKey(query);
if(key==0)return providers;
return new DirectoryProvider[] { providers[key] };
}
private int docKey(Document doc) {
int fid = 0;
if(doc==null)return fid;
String sid = doc.get(LOCAL_FIELD);
try {
fid = Integer.parseInt(sid);
} catch (NumberFormatException e) {
throw new SearchException(LOCAL_FIELD + fid + " is not a number", e);
}
return fid;
}
private int docKey(Query query) {
int fid = 0;
HashSet<Term> terms = new HashSet<Term>();
query.extractTerms(terms);
for (Term tr : terms) {
if (tr.field().equals(LOCAL_FIELD)) {
String sid = tr.text();
try {
fid = Integer.parseInt(sid);
return fid;
} catch (NumberFormatException e) {
throw new SearchException(LOCAL_FIELD + fid
+ " is not a number", e);
}
}
}
return fid;
}
}
自定义DirectoryProvider实现类
复制内容到剪贴板
代码:
package com.search.store;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.FSDirectory;
import org.hibernate.HibernateException;
import org.hibernate.search.SearchException;
import org.hibernate.search.backend.LuceneIndexingParameters;
import org.hibernate.search.engine.SearchFactoryImplementor;
import org.hibernate.search.store.DirectoryProvider;
import org.hibernate.search.store.FSDirectoryProvider;
import org.hibernate.search.store.optimization.IncrementalOptimizerStrategy;
import org.hibernate.search.store.optimization.NoOpOptimizerStrategy;
import org.hibernate.search.store.optimization.OptimizerStrategy;
import org.hibernate.search.util.DirectoryProviderHelper;
import org.hibernate.util.StringHelper;
public class LocalDirectoryProvider extends FSDirectoryProvider{
private static Log log = LogFactory.getLog( FSDirectoryProvider.class );
private static String LUCENE_PREFIX = "hibernate.search.";
private static String LUCENE_DEFAULT = LUCENE_PREFIX + "default.";
private static final String MERGE_FACTOR = "merge_factor";
private static final String MAX_MERGE_DOCS = "max_merge_docs";
private static final String MAX_BUFFERED_DOCS = "max_buffered_docs";
private static final String BATCH = "batch.";
private static final String TRANSACTION = "transaction.";
private static final String SHARDING_STRATEGY = "sharding_strategy";
private static final String NBR_OF_SHARDS = SHARDING_STRATEGY + ".nbr_of_shards";
private FSDirectory directory;
private String indexName;
private String directoryProviderName;
private Properties indexProps;
private SearchFactoryImplementor searchFactoryImplementor;
public LocalDirectoryProvider(){}
public LocalDirectoryProvider(String indexName,Properties indexProps, SearchFactoryImplementor searchFactoryImplementor){
this.indexName=indexName;
try {
directory = FSDirectory.getDirectory( indexName );
} catch (IOException e) {
throw new HibernateException( "Unable to initialize index: " + indexName, e );
}
configureOptimizerStrategy(searchFactoryImplementor, indexProps, this);
configureIndexingParameters(searchFactoryImplementor, indexProps, this);
if ( !searchFactoryImplementor.getLockableDirectoryProviders().containsKey( this ) ) {
searchFactoryImplementor.getLockableDirectoryProviders().put( this, new ReentrantLock() );
}
}
public FSDirectory getDirectory() {
return directory;
}
public void initialize(String directoryProviderName, Properties properties,
SearchFactoryImplementor searchFactoryImplementor) {
this.indexProps=properties;
this.searchFactoryImplementor=searchFactoryImplementor;
this.directoryProviderName=directoryProviderName;
File indexDir = DirectoryProviderHelper.determineIndexDir( directoryProviderName, properties );
try {
boolean create = !indexDir.exists();
if (create) {
log.debug( "index directory not found, creating: '" + indexDir.getAbsolutePath() + "'" );
indexDir.mkdirs();
}
indexName = indexDir.getCanonicalPath();
directory = FSDirectory.getDirectory( indexName );
}
catch (IOException e) {
throw new HibernateException( "Unable to initialize index: " + directoryProviderName, e );
}
}
public void start() {
super.start();
}
@Override
public boolean equals(Object obj) {
if ( obj == this ) return true;
if ( obj == null || !( obj instanceof LocalDirectoryProvider ) ) return false;
return indexName.equals( ( (LocalDirectoryProvider) obj ).indexName );
}
@Override
public int hashCode() {
int hash = 11;
return 37 * hash + indexName.hashCode();
}
public Properties getIndexProps() {
return indexProps;
}
public SearchFactoryImplementor getSearchFactoryImplementor() {
return searchFactoryImplementor;
}
private void configureOptimizerStrategy(SearchFactoryImplementor searchFactoryImplementor, Properties indexProps, DirectoryProvider<?> provider) {
boolean incremental = indexProps.containsKey( "optimizer.operation_limit.max" )
|| indexProps.containsKey( "optimizer.transaction_limit.max" );
OptimizerStrategy optimizerStrategy;
if (incremental) {
optimizerStrategy = new IncrementalOptimizerStrategy();
optimizerStrategy.initialize( provider, indexProps, searchFactoryImplementor);
}
else {
optimizerStrategy = new NoOpOptimizerStrategy();
}
searchFactoryImplementor.addOptimizerStrategy(provider, optimizerStrategy);
}
private void configureIndexingParameters(SearchFactoryImplementor searchFactoryImplementor, Properties indexProps, DirectoryProvider<?> provider) {
LuceneIndexingParameters indexingParams = new LuceneIndexingParameters();
String s = indexProps.getProperty(TRANSACTION + MERGE_FACTOR);
if (!StringHelper.isEmpty( s )) {
try{
indexingParams.setTransactionMergeFactor(Integer.valueOf(s));
indexingParams.setBatchMergeFactor(Integer.valueOf(s));
} catch (NumberFormatException ne) {
throw new SearchException("Invalid value for " + TRANSACTION + MERGE_FACTOR + ": " + s);
}
}
s = indexProps.getProperty(TRANSACTION + MAX_MERGE_DOCS);
if (!StringHelper.isEmpty( s )) {
try{
indexingParams.setTransactionMaxMergeDocs(Integer.valueOf(s));
indexingParams.setBatchMaxMergeDocs(Integer.valueOf(s));
} catch (NumberFormatException ne) {
throw new SearchException("Invalid value for " + TRANSACTION + MAX_MERGE_DOCS + ": " + s);
}
}
s = indexProps.getProperty(TRANSACTION + MAX_BUFFERED_DOCS);
if (!StringHelper.isEmpty( s )) {
try{
indexingParams.setTransactionMaxBufferedDocs(Integer.valueOf(s));
indexingParams.setBatchMaxBufferedDocs(Integer.valueOf(s));
} catch (NumberFormatException ne) {
throw new SearchException("Invalid value for " + TRANSACTION + MAX_BUFFERED_DOCS + ": " + s);
}
}
s = indexProps.getProperty(BATCH + MERGE_FACTOR);
if (!StringHelper.isEmpty( s )) {
try{
indexingParams.setBatchMergeFactor(Integer.valueOf(s));
} catch (NumberFormatException ne) {
throw new SearchException("Invalid value for " + BATCH + MERGE_FACTOR + ": " + s);
}
}
s = indexProps.getProperty(BATCH + MAX_MERGE_DOCS);
if (!StringHelper.isEmpty( s )) {
try{
indexingParams.setBatchMaxMergeDocs(Integer.valueOf(s));
} catch (NumberFormatException ne) {
throw new SearchException("Invalid value for " + BATCH + MAX_MERGE_DOCS + ": " + s);
}
}
s = indexProps.getProperty(BATCH + MAX_BUFFERED_DOCS);
if (!StringHelper.isEmpty( s )) {
try{
indexingParams.setBatchMaxBufferedDocs(Integer.valueOf(s));
} catch (NumberFormatException ne) {
throw new SearchException("Invalid value for " + BATCH + MAX_BUFFERED_DOCS + ": " + s);
}
}
searchFactoryImplementor.addIndexingParmeters(provider, indexingParams);
}
public String getIndexName() {
return indexName;
}
}
hibernate.properties
hibernate.search.default.directory_provider=org.hibernate.search.store.FSDirectoryProvider
hibernate.search.default.indexBase=/Hibernate/lucene/indexes
hibernate.search.analyzer=net.paoding.analysis.analyzer.PaodingAnalyzer
#开始静态目录分配,意思是预先设置目录的个数
hibernate.search.song.sharding_strategy.nbr_of_shards 28
hibernate.search.song.sharding_strategy com.blok.search.store.LocalIndexStaticShardingStrategy
#结束静态目录分配
#开始动态目录分配,意思是根据LocalIndexDynamicShardingStrategy实现类中doucment field值来分配
hibernate.search.song.sharding_strategy com.blok.search.store.LocalIndexDynamicShardingStrategy
hibernate.search.song.directory_provider com.blok.search.store.LocalDirectoryProvider
#结束动态目录分配
实体类
复制内容到剪贴板
代码:
package search.entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.search.annotations.DocumentId;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.Store;
@Entity
@Table(name="song")
@Indexed(index="song")
@NamedQueries({
@NamedQuery(name="Song.list[find]",query="from Song s order by s.time desc"),
@NamedQuery(name="Song.list[count]",query="select count(*) from Song"),
@NamedQuery(name="Song.byCityId[load]",query="from Song s where s.artistCityId =?")
})
public class Song implements Serializable{
private static final long serialVersionUID = -1475639504643543299L;
@Id
@DocumentId
@GeneratedValue(generator="system_uuid")
@GenericGenerator(name="system_uuid",strategy="uuid")
private String id;
@Column(name="artist",length=36)
private String artist;
@Column(name="name",length=36,nullable=false)
@Field(index=Index.TOKENIZED,store=Store.NO)
private String name;
@Lob
@Column(name="lyric",length=2000)
@Field(index=Index.TOKENIZED,store=Store.NO)
private String lyric;
@Column(name="time",nullable=false)
@Field(index=Index.UN_TOKENIZED,store=Store.NO)
private Date time;
@Column(name="artistCityId",nullable=false)
@Field(index=Index.UN_TOKENIZED,store=Store.YES)
private Integer artistCityId;
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLyric() {
return lyric;
}
public void setLyric(String lyric) {
this.lyric = lyric;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id=id;
}
public Integer getArtistCityId() {
return artistCityId;
}
public void setArtistCityId(Integer artistCityId) {
this.artistCityId = artistCityId;
}
}
测试类
复制内容到剪贴板
代码:
package search.test;
import java.util.Date;
import java.util.List;
import net.paoding.analysis.analyzer.PaodingAnalyzer;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.Search;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import search.entity.Song;
import search.util.HibernateSessionFactory;
public class IndexTest {
private Session session;
@Before
public void before(){
session=HibernateSessionFactory.getSession();
}
@Test
public void insert(){
Transaction tx=session.beginTransaction();
try {
for(int i=0;i<1000;i++){
Song song=new Song();
song.setArtist("群星");
song.setName("北京欢迎你");
song.setLyric("北京欢迎你,welcome to beijing,第29届奥林匹克运动会");
song.setTime(new Date());
song.setArtistCityId(i%8);
session.save(song);
if(i%1000==0)session.flush();
}
// throw new RuntimeException("error");
} catch (Exception e) {
tx.rollback();
}
tx.commit();
}
@Test
public void delete(){
FullTextSession fullTextSession = Search.createFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
List<Song> songs = session.getNamedQuery("Song.byCityId[load]").setInteger(0, 1).list();
for (Song song : songs) {
session.delete(song);
}
tx.commit();
}
@Test
public void index(){
FullTextSession fullTextSession = Search.createFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
List<Song> songs = session.getNamedQuery("Song.list[find]").list();
for (Song song : songs) {
fullTextSession.index(song);
}
tx.commit();
}
@Test
public void search() throws ParseException{
FullTextSession fullTextSession = Search.createFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
BooleanQuery booleanQuery=new BooleanQuery();
MultiFieldQueryParser parser = new MultiFieldQueryParser( new String[]{"name", "lyric"},
new PaodingAnalyzer());
Query query = parser.parse( "北京欢迎你" );
booleanQuery.add(query,BooleanClause.Occur.MUST);
TermQuery tq=new TermQuery(new Term("artistCityId","0"));
booleanQuery.add(tq,BooleanClause.Occur.MUST);
org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery( booleanQuery, Song.class );
List<Song> songs = hibQuery.list();
// for(Song song:songs){
// System.out.println(song.getArtist()+":"+song.getName()+":"+song.getLyric());
// }
System.out.println("count:"+songs.size());
tx.commit();
}
@Test
public void purgeAll(){
FullTextSession fullTextSession = Search.createFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
fullTextSession.purgeAll( Song.class );
tx.commit();
fullTextSession.getSearchFactory().optimize(Song.class);
fullTextSession.getSearchFactory().optimize();
}
@After
public void close(){
HibernateSessionFactory.closeSession();
}
}
此上代码全部拷贝即可正常使用,如有不明之处,请回帖!
来源:http://www.rest4g.org/viewthread.php?tid=3&extra=page%3D1