поиск в спящем режиме + spring3 + jpa - PullRequest
4 голосов
/ 21 декабря 2009

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

Объект домена:

@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), но в чем ее причина?

Ответы [ 3 ]

2 голосов
/ 22 декабря 2009

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

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

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

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

1 голос
/ 21 декабря 2009

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

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

При выполнении функций index и getTransactionCommit индексы правильно хранятся в моей папке indexes. Эта реализация, однако, довольно неестественная, так как я создаю альтернативный менеджер сущностей для поиска текста. Есть ли "более чистый" способ индексировать (и фиксировать) записи, используя аннотации @Transactional ???

...