2009-12-21 5 views
4

Я пытаюсь интегрировать поиск в спящий режим в моем проекте. Мои модели индексируются, но почему-то мои поисковые запросы не возвращают никаких результатов. Я пытался решить эту проблему в течение нескольких часов, но ничего не работает. Объектhibernate search + spring3 + jpa

Домен:

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

} 

Услуги:

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

} 

Тест:

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

} 

Конфигурации

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

База данных фактически заполнена роль совпадающее значение поля авторитет. Диспетчер объектов действителен, как и все мои обычные тесты CRUD. Значение ошибки - полностью спящий поиск (3.1.1.GA), но где это происходит неправильно?

+0

Вы уверены, что ваша БД поддерживает полнотекстовый поиск? – Roman

+0

Я использую HSQLDB. – Jeroen

+0

Коррекция: объекты домена неправильно проиндексированы. – Jeroen

ответ

1

Наконец-то удалось заставить его работать. По-видимому, объекты не индексируются автоматически .. или не совершенны как минимум. Моя реализация выглядит следующим образом:

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

Выполнив индекс и getTransactionCommit функции индексы правильно хранятся в моей папке индексов. Однако эта реализация довольно неестественна, поскольку я создаю альтернативный менеджер объектов для поиска текста. Существует ли «чистый» способ индексирования (и фиксации) записей с помощью аннотаций @Transactional ???

+1

Я знаю, что это немного поздно, но я буду комментировать в надежде, что это поможет кому-то в интернетах. Я использую класс, который загружается Spring во время выполнения и переиндексирует существующие данные при запуске приложения (используя аннотацию @PostConstruct для моего метода). – schmimd04

2

В теории все это работает, но там может быть несколько проблем:

  • сделал вам сначала индексировать существующие объекты? В то время как Hibernate Search индексирует все новые изменения, он не осведомлен о ранее существовавших объектах и, следовательно, вам нужно сначала проиндексировать их (используя ftem # index())
  • по умолчанию, HSearch перехватывает транзакции Hibernate или JTA для прослушивания до и после транзакций. Возможно, ваша конфигурация Spring tx обходит это, и поэтому HSearch не запускается и, следовательно, не может индексироваться. Лучший подход - это использовать реального менеджера транзакций JTA и избегать этих фасадов.
  • Если вы говорите об исходном индексировании (используя index()), вы можете использовать #flushToIndexes() для принудительной индексации, даже если tx не зафиксирован.
  • Последнее, но не менее важное: ваш последний фрагмент кода, скорее всего, выкинет OutOfMemoryException, потому что вы загружаете все объекты в памяти перед их индексированием. Проверьте справочную документацию Hibernate Search о том, как правильно индексировать нагрузки объектов в пакетном режиме. Hibernate Поиск в действии Мэннинга (я автор) также углубляется во все это.
1

В конце концов, моя проблема была решена путем присоединения следующее свойство: hibernate.search.worker.batch_size = 1

Не только я могу теперь должным образом запрос, но индексы также автоматически обновляется каждый раз, когда я настойчив мой объект домена. Единственная проблема, с которой я столкнулся сейчас, это то, что данные, вставленные через мой import.sql, не индексируются автоматически. Есть какой-то «волшебный» спящий режим.для поиска доступно свойство поиска, или я должен индексировать их вручную?