[英]Hibernate Search doesn't index/reindex entities
我正在嘗試在我的項目中使用Hibernate Search(現在使用junit + dbunit編寫測試),但搜索查詢不會返回任何結果。 我昨天研究了這個問題並得出結論,問題是Hibernate Search與dbunit @DatabaseSetup不兼容(類似於這個未回答的問題中的類似問題: 鏈接 )。 我將提供更多細節,但首先是冷杉,有我的實體類:
@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", "mac@gmial.com", "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("mac@gmail.com");
} 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 {
//abc@gmial.com is in db - setted up by @DatabaseSetup
u2 = searchService.searchByEmail("abc@gmail.com");
} 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的行。 無論如何,它使用了我在使用sql“手動”測試之前調試的行,因此我認為這只是dbunit的問題,只是用@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", "mac@gmial.com", "MacAda");
userDAO.save(u1);
doneBefore = true;
}
}
並運行此測試:
@Test
public void searchByEmailTest() {
List<User> u = null;
try {
u = searchService.searchByEmail("mac@gmail.com");
} catch (InterruptedException e) {
e.printStackTrace();
}
//Also asserts here, I know.
System.out.println(":: " + u.size());
System.out.println(":: " + u.get(0).getName());
}
雖然hibernate保存了數據,但它並不起作用。 我試圖找到bug並將我的代碼恢復到測試通過的eariel版本(帶有@DatabaseSetup的版本,但僅用於使用我的dao保存的行),現在這個版本也沒有通過。 我很困惑並且沒有想法為什么它沒有索引新對象,更不用說為什么它不會在調用大量索引器時重新索引所有數據庫。 任何幫助將不勝感激。
編輯:
在潛在的答案后,我做了一些更多的測試 關於搜索有時會產生雙倍或三倍行的事實我嘗試.purgeAll()
並將索引提供程序更改為RAM以確保我的索引在開始測試時是干凈的。 它基本上沒有任何改變。 為了構建我的索引,我使用了前面提到的.startAndWait()
。 嘗試使用.index()
“手動”構建它,但在嘗試使用fullTextSession時遇到了一些嵌套的事務問題。 顯式提交事務(或設置@Rollback(false)
- 嘗試兩者)也不起作用。 我在Hibernate Search文檔中找到的所有嘗試 - 鏈接 。 索引和搜索工作正常,如果我在搜索它之前保存了一些東西,但做同樣的事情@Before然后搜索只是不起作用。
當我沒記錯的話,Hibernate Search會在你提交交易時更新索引。
這對於普通代碼來說沒有問題,但在測試中這種行為可能會導致問題,因為測試的常見模式是,當您開始測試時啟動事務,並且在測試結束時您將事務作用回來,但你永遠不會提交它們。
要驗證這是導致問題的原因,請創建一個測試,啟動明確的新事務,修改某些內容然后提交事務。 然后在提交后檢查你的hiberante搜索索引。
如本Hibernate Search中所述,不會索引/重新索引實體 ,您需要在保存數據后顯式提交事務以便進行索引。 索引發生在事務后同步(至少每個默認值)。
您可以嘗試使用手動索引API或質量索引器。 我不確定為什么這對你不起作用。 我也不確定@DatabaseSetup是如何工作的並且掛鈎到JUnit生命周期中。
關於三重結果。 您可能正在使用基於文件系統的索引(默認情況下使用),該索引會創建基於Lucene索引的索引,該索引在測試運行之間不會被清除。 使用RAM索引或確保清除基於文件的索引。
如果您共享Hibernate屬性配置,它可能會有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.