Próbuję użyć Hibernate Search w moim projekcie (pisanie testów teraz za pomocą junit + dbunit), ale zapytanie wyszukiwania nie zwraca żadnych wyników. Pracowałem nad tym wczoraj i doszedłem do wniosku, że problem jest Hibernate Search nie działa dobrze z dbunit @DatabaseSetup (podobny problem jak w tym nieodebranym pytaniu: link). Pójdę z większą ilością szczegółów, ale jodły rzeczy pierwsze, nie jest moja klasa podmiot:Hibernate Search nie indeksuje/reindeksuje obiektów
@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;
(...)
}
zapisać go do db mojego DAO:
@Repository
public class UserDAOImpl implements UserDAO {
@Autowired
private SessionFactory sessionFactory;
@Override
public long save(User toSave) {
return (Long) this.sessionFactory.getCurrentSession().save(toSave);
}
(...)
}
Jest to kod odpowiedzialny za prowadzenie kwerendy 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;
}
I tak sprawa jest skonfigurowany w wiosennej config:
<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>
Teraz jak się najpierw testowałem. I skonfigurowany zestaw danych z mojego testowania dbunit i stworzył metodę badania takiego:
@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());
}
Po patrząc hibernacji dokumentację Search znalazłem fullTextSession.createIndexer().startAndWait();
metody. Użyłem go, ale nadal nie działa dla wierszy z @DatabaseSetup. W każdym razie to działało z wierszy, które ja putted przed testem „ręcznie” z sql więc myślałem, że to jest tylko problem z dbunit i po prostu napisał konfigurację z @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;
}
}
i uruchomieniu tego testu:
@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());
}
I to nie działa, mimo że dane są zapisywane przez hibernację. Próbowałem znaleźć błąd i przywróciłem mój kod do wersji eariel, w której test był przekazywany (ten z @DatabaseSetup, ale tylko dla wierszy zapisanych z moim dao) i teraz ten też nie przechodzi. Jestem bardzo zdezorientowany i nie ma pomysłu, dlaczego nie indeksuje nowych obiektów, nie mówiąc, dlaczego nie reindeksuje całej bazy danych, gdy wywoływany jest masywny indexer. Każda pomoc zostanie doceniona.
EDYTOWANIE:
Po potencjalnych odpowiedziach wykonałem jeszcze kilka testów. W związku z faktem, że wyszukiwanie czasami skutkowało podwójnymi lub potrójnymi wierszami, wypróbowałem .purgeAll()
i zmieniłem dostawcę indeksowania na RAM, aby mieć pewność, że moje indeksy są czyste podczas rozpoczynania testowania. Nie zmieniło się to w zasadzie nic. Aby zbudować mój indeks, użyłem .startAndWait()
, jak wspomniano wcześniej. Próbowałem budować go "ręcznie" z .index()
, ale mam problemy z zagnieżdżonymi transakcjami, gdy próbowałem użyć fullTextSession. Jawnie zatwierdzanie transakcji (lub ustawienie @Rollback(false)
- próbował obu) również nie działa. Wszystko, co próbowałem znalazłem w dokumentacji wyszukiwania w Hibernate - link. Indeksowanie i wyszukiwanie działają dobrze, jeśli zapisuję coś z DAO tuż przed jego wyszukaniem, ale robiąc to samo, @Before, a następnie wyszukiwanie nie działa.
Niestety jawnie deklarowanie transakcji nie pomaga. Co więcej - wyniki wyszukiwania czasami nic nie zwracają, a następnie przy następnym uruchomieniu testu zwracają wynik podwójny lub potrójny (np. Dla wyszukiwania "[email protected]" znajduje on i zwraca trzy obiekty, nawet jeśli w db jest tylko jeden wiersz). Znajduje również dziwne wyniki, np. Wyszukując "[email protected]" zwraca obiekty, które nie mają "[email protected]" w polu adresu e-mail. Nie widzę żadnego wzorca w tych błędach, więc nie mogę nawet stwierdzić, kiedy ma miejsce. Również wygląda na to, że reindeksuje więcej jednostek, niż powinno, gdy zostanie wywołana funkcja startAndWait. – Plebejusz