我想在我的項目中使用Hibernate搜索(現在使用junit + dbunit編寫測試),但搜索查詢不會返回任何結果。我昨天就這樣做了,得出的結論是,Hibernate Search與dbunit @DatabaseSetup不兼容(類似於此未解答的問題:link)。我會用更多的細節去,但杉杉的事情首先,有我的實體類:Hibernate搜索不索引/ reindex實體
@Entity
@Indexed
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "userId")
private Long id;
(...)
@Column(nullable = false, unique = true)
@Field(index = Index.YES, analyze=Analyze.YES, store=Store.NO)
private String email;
(...)
@Column(nullable = false, unique = true)
@Field(index = Index.YES, analyze=Analyze.YES, store=Store.NO)
private String username;
(...)
}
我將它保存在我的DAO DB:
@Repository
public class UserDAOImpl implements UserDAO {
@Autowired
private SessionFactory sessionFactory;
@Override
public long save(User toSave) {
return (Long) this.sessionFactory.getCurrentSession().save(toSave);
}
(...)
}
這是負責運行Lucene的查詢代碼:
@Override
public List<User> searchByEmail(String email) throws InterruptedException {
return generateHibernateSearchQueryFor("email", email).list();
}
private org.hibernate.Query generateHibernateSearchQueryFor(String field, String searchParam) {
FullTextSession fullTextSession = Search.getFullTextSession(sessionFactory.getCurrentSession());
QueryBuilder queryBuilder = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(User.class).get();
org.apache.lucene.search.Query lQuery = queryBuilder.keyword().onFields(field).matching(searchParam).createQuery();
org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery(lQuery, User.class);
return fullTextQuery;
}
而這件事是如何在Spring配置配置:
<bean id="hibernate4AnnotatedSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="me.ksiazka.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.search.default.directory_provider">filesystem</prop>
<prop key="hibernate.search.default.indexBase">src/searching_indexes</prop>
</props>
</property>
</bean>
現在我是怎麼開始測試的。我配置我用DbUnit和創建測試方法測試數據集是這樣的:
@Test
@DatabaseSetup("classpath:/testsDataset.xml")
public void searchByEmailTest() {
User u1 = new User("Maciej", "Adamowicz", "k2", "[email protected]", "MacAda");
userDAO.save(u1);
List<User> u = null;
try {
//It worked at first - as new user was saved with hibernate he got his index in hibernate search indexes folder and searching found him.
u = searchService.searchByEmail("[email protected]");
} catch (InterruptedException e) {
e.printStackTrace();
}
//I know there should be asserts, its just for simplification for need of moment.
System.out.println(":: " + u.size());
System.out.println(":: " + u.get(0).getName());
}
List<User> u2 = null;
try {
//[email protected] is in db - setted up by @DatabaseSetup
u2 = searchService.searchByEmail("[email protected]");
} catch (InterruptedException e) {
e.printStackTrace();
}
//This didnt work, rows putted into db by dbunit doesn't have indexes in my indexing folder.
System.out.println(":: " + u2.size());
System.out.println(":: " + u2.get(0).getName());
}
尋找Hibernate Search的資料後,我發現fullTextSession.createIndexer().startAndWait();
方法。我用它,但它仍然不適用於來自@DatabaseSetup的行。反正它用,所以我認爲它是用DbUnit唯一的問題是我考試前的推杆「手」與SQL行工作,只是寫了@Before設置:
@Before
public void setupDatabase() {
if(!doneBefore) {
try {
//It calls createIndexer().startAndWait() to make sure everything is indexed before test
searchService.reindex();
} catch (InterruptedException e) {
e.printStackTrace();
}
User u1 = new User("Maciej", "Adamowicz", "k2", "[email protected]", "MacAda");
userDAO.save(u1);
doneBefore = true;
}
}
並運行這個測試:
@Test
public void searchByEmailTest() {
List<User> u = null;
try {
u = searchService.searchByEmail("[email protected]");
} catch (InterruptedException e) {
e.printStackTrace();
}
//Also asserts here, I know.
System.out.println(":: " + u.size());
System.out.println(":: " + u.get(0).getName());
}
雖然通過休眠保存數據,但它不起作用。我試圖找到bug並將我的代碼恢復到了測試通過的版本(使用@DatabaseSetup的版本,但僅限於使用我的dao保存的行),現在這個版本也不能通過。我非常困惑,爲什麼不索引新對象,並不是說爲什麼在調用大量索引器時不重新索引所有數據庫。任何幫助將不勝感激。
編輯:
潛在的答案後,我做了一些更多的測試。關於事實上搜索有時會導致兩倍或三倍的行,我嘗試了.purgeAll()
並將索引提供程序更改爲RAM,以確保在開始測試時我的索引是乾淨的。它基本上沒有改變。如前所述,我使用.startAndWait()
來構建我的索引。嘗試用.index()
「手動」構建它,但是在嘗試使用fullTextSession時遇到了一些嵌套事務問題。明確提交交易(或設置@Rollback(false)
- 都嘗試)不起作用。 我在Hibernate搜索文檔中發現的所有內容 - link。 索引和搜索工作正常,如果我在搜索之前使用DAO保存某些內容,但是執行相同的操作時,@Before然後搜索不起作用。
不幸的是,顯式聲明事務並沒有幫助。還有什麼 - 搜索結果有時不會返回任何內容,然後在下一次測試運行時返回結果的兩倍或三倍(例如,搜索「[email protected]」時發現它並返回三個對象,即使在db中只有一行時也是如此)。它也會發現奇怪的結果,比如搜索「[email protected]」它會返回在其電子郵件字段中沒有「[email protected]」的對象。我在這個錯誤中看不到任何模式,所以我什至不知道它們中的哪一個發生。 另外,它似乎重新索引更多的實體,它應該當startAndWait被調用。 – Plebejusz 2014-11-03 14:40:52