2009-12-21 8 views
4

J'essaie d'intégrer la recherche hibernate dans mon projet. Mes modèles sont indexés, mais pour une raison quelconque, mes requêtes de recherche ne renvoient aucun résultat. J'ai essayé de résoudre ce problème pendant quelques heures maintenant, mais rien de ce que je fais ne semble fonctionner.hibernate search + spring3 + jpa

objet Domaine:

@Entity 
@Table(name = "roles") 
@Indexed 
public class Role implements GrantedAuthority { 
private static final long serialVersionUID = 8227887773948216849L; 

    @Id @GeneratedValue 
    @DocumentId 
    private Long ID; 

    @Column(name = "authority", nullable = false) 
    @Field(index = Index.TOKENIZED, store = Store.YES) 
    private String authority; 

    @ManyToMany 
    @JoinTable(name = "user_roles", joinColumns = { @JoinColumn(name = "role_id") }, inverseJoinColumns = { @JoinColumn(name = "username") }) 
    @ContainedIn 
    private List<User> users; 

    ... 

} 

OAC:

public abstract class GenericPersistenceDao<T> implements IGenericDao<T> { 

@PersistenceContext 
private EntityManager entityManager; 

... 

    @Override 
    public FullTextEntityManager getSearchManager() { 
     return Search.getFullTextEntityManager(entityManager); 
    } 

} 

Service:

@Service(value = "roleService") 
public class RoleServiceImpl implements RoleService { 

    @Autowired 
    private RoleDao roleDAO; 

    ... 

    @Override 
    @SuppressWarnings("unchecked") 
    public List<Role> searchRoles(String keyword) throws ParseException { 
     FullTextEntityManager manager = roleDAO.getSearchManager(); 
     TermQuery tquery = new TermQuery(new Term("authority", keyword)); 
     FullTextQuery query = manager.createFullTextQuery(tquery, Role.class); 
     return query.getResultList(); 
    } 

} 

Test:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext.xml" }) 
@Transactional 
public class TestRoleService extends Assert { 

    @Autowired 
    private RoleService roleService; 

    @Test 
    public void testSearchRoles() { 
     roleService.saveRole(/* role with authority="test" */); 
     List<Role> roles = roleService.searchRoles("test"); 
     assertEquals(1, roles.size()); // returns 0 
    } 

} 

Configurations

<persistence-unit name="hibernatePersistence" transaction-type="RESOURCE_LOCAL"> 
     <provider>org.hibernate.ejb.HibernatePersistence</provider> 
     <properties> 
      <property name="hibernate.search.default.directory_provider" value="org.hibernate.search.store.FSDirectoryProvider" /> 
      <property name="hibernate.search.default.indexBase" value="indexes" /> 
     </properties> 
</persistence-unit> 

<!-- Entity manager --> 
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> 
    <property name="persistenceUnitName" value="hibernatePersistence" /> 
</bean> 

<!-- Transaction manager --> 
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactory" /> 
</bean> 

<!-- Enable the configuration of transaction behavior based on annotations --> 
<tx:annotation-driven transaction-manager="transactionManager" /> 

<context:component-scan base-package="org.myproject" /> 

La base de données est en fait rempli d'un rôle correspondant à la valeur du champ d'autorité. Le gestionnaire d'entités est valide car tous mes tests CRUD réguliers réussissent. Ce qui signifie que l'erreur est entièrement liée à la recherche hibernate (3.1.1.GA), mais où cela se passe-t-il?

+0

Etes-vous sûr que votre base de données prend en charge la recherche en texte intégral? – Roman

+0

J'utilise HSQLDB. – Jeroen

+0

correction: les objets de domaine ne sont pas correctement indexés. – Jeroen

Répondre

1

Enfin réussi à le faire fonctionner .. apparemment les objets ne sont pas automatiquement indexés .. ou pas engagés au moins. Ma mise en œuvre se présente maintenant comme suit:

public List<Role> searchRoles(String keyword) { 
     // Index domain object (works) 
     EntityManager manager = factory.createEntityManager(); 
     FullTextEntityManager ftManager = Search.getFullTextEntityManager(manager); 
     ftManager.getTransaction().begin(); 

     List<Role> roles = ftManager.createQuery("select e from " + Role.class.getName() + " e").getResultList(); 
     for (Role role : roles) { 
      ftManager.index(role); 
     } 
     ftManager.getTransaction().commit(); 

     // Retrieve element from search (works) 
     TermQuery tquery = new TermQuery(new Term("authority", keyword)); 
     FullTextQuery query = ftManager.createFullTextQuery(tquery, Role.class); 
     return query.getResultList(); 
} 

En effectuant l'index et getTransactionCommit fonctions les index sont correctement stockés dans mon dossier index. Cette implémentation, cependant, n'est pas naturelle car je fais un gestionnaire d'entité alternative pour la recherche de texte. Existe-t-il un moyen plus "propre" d'indexer (et de valider) les enregistrements en utilisant les annotations @Transactional ???

+1

Je sais que c'est un peu en retard, mais je vais commenter dans l'espoir qu'il aide quelqu'un sur les internets. J'utilise une classe qui est chargée par Spring à l'exécution et réindexe les données existantes lorsque l'application démarre (en utilisant une annotation @PostConstruct sur ma méthode). – schmimd04

2

En théorie tout cela fonctionne, mais il pourrait y avoir quelques problèmes:

  • avez-vous d'abord indexer vos objets existants? Alors que Hibernate Search indexe tous les nouveaux changements, il ne connaît pas les objets préexistants et donc vous devez les indexer initialement (en utilisant ftem # index())
  • par défaut, HSearch se connecte aux transactions Hibernate ou JTA pour écouter à avant et après les événements de transaction. Peut-être que votre configuration Spring tx contourne cela et que HSearch n'est donc pas déclenché et ne peut donc pas indexer. La meilleure approche consiste vraiment à utiliser un vrai gestionnaire de transactions JTA et à éviter ces façades. Si vous parlez de l'indexation initiale (en utilisant index()), vous pouvez également utiliser #flushToIndexes() pour forcer l'indexation même si le tx n'est pas validé. Last but not least, votre dernier morceau de code lancera probablement une exception OutOfMemoryException car vous chargez tous les objets en mémoire avant de les indexer. Consultez la documentation de référence de Hibernate Search sur la manière d'indexer correctement les charges d'objets en batch. Hibernate Search in Manning (je suis l'auteur) va aussi plus loin dans tout cela.
1

Finalement, mon problème a été résolu en fixant la propriété suivante: hibernate.search.worker.batch_size = 1

Non seulement je peux maintenant correctement requête, mais les index sont automatiquement mis à jour chaque fois que je persiste mon objet de domaine. Le seul problème que j'ai maintenant est que les données insérées via mon import.sql ne sont pas automatiquement indexées. Y a-t-il une sorte d'hibernation "magique"?recherche la propriété disponible pour ce problème ou dois-je les indexer manuellement?