Sleep Search + spring3 + jpa

I am trying to integrate sleep search in my project. My models are indexed, but for some reason my search queries do not return any results. I tried to solve this problem for several hours, but nothing works.

Domain Object:

@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; ... } 

DAO:

 public abstract class GenericPersistenceDao<T> implements IGenericDao<T> { @PersistenceContext private EntityManager entityManager; ... @Override public FullTextEntityManager getSearchManager() { return Search.getFullTextEntityManager(entityManager); } } 

Services:

 @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 } } 

Configuration

 <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" /> 

In fact, the database is filled with the role corresponding to this value of the authorization field. The object manager is valid, like all my regular CRUD tests. The meaning of the error is a completely sleeping search (3.1.1.GA), but where does this go wrong?

+4
source share
3 answers

In theory, everything works, but there can be several problems:

  • Did you initially specify your existing objects? While Hibernate Search indexes all new changes, it is not aware of pre-existing objects, and so you need to index them first (using ftem # index ())
  • By default, HSearch intercepts Hibernate or JTA transactions to listen for before and after transaction events. Perhaps your Spring tx configuration bypasses this and therefore HSearch does not start and therefore cannot be indexed. The best approach is to use a real JTA transaction manager and avoid these facades.
  • If you're talking about initial indexing (using index ()), you can use #flushToIndexes () to force indexing, even if tx is not committed.
  • last but not least, your last piece of code is likely to throw an OutOfMemoryException because you load all the objects in memory before indexing them. Check out the Hibernate Search help documentation on how to properly index object loads in batch mode. Hibernate Search in Manning's Action (I am the author) also goes deeper into all of this.
+2
source

Finally managed to get it to work. Apparently, objects are not indexed automatically .. or not perfect at least. Now my implementation is as follows:

 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(); } 

By executing the index and getTransactionCommit functions, the indexes are correctly saved in the folder of my indexes. However, this implementation is rather unnatural, as I am creating an alternative object manager to search for text. Is there a β€œcleaner” way to index (and commit) records using @Transactional annotations?

+1
source

In the end, my problem was resolved by attaching the following property: hibernate.search.worker.batch_size = 1

Now I can not only query correctly, but indexes are automatically updated whenever I save my domain object. The only problem I am facing right now is that the data inserted through my import.sql is not indexed automatically. Is there some kind of "magic" hibernate.search function for this problem or should I index them manually?

+1
source

All Articles