簡體   English   中英

hibernate搜索+ spring3 + jpa

[英]hibernate search + spring3 + jpa

我正在嘗試將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測試都成功。 意思是錯誤完全與hibernate搜索(3.1.1.GA)有關,但哪里出錯?

理論上它一切正常但可能存在一些問題:

  • 你最初索引現有的對象了嗎? 雖然Hibernate Search索引所有新的更改,但它不知道預先存在的對象,因此您需要最初索引它們(使用ftem #index())
  • 默認情況下,HSearch掛鈎到Hibernate或JTA事務以在事務事件之前和之后進行偵聽。 也許你的Spring tx配置會繞過它,因此HSearch不會被觸發,因此無法索引。 最好的方法是使用真正的JTA事務管理器並避免這些外觀。
  • 如果你在談論初始索引(使用index()),你也可以使用#flushToIndexes()強制索引,即使tx沒有提交。
  • 最后但並非最不重要的是,您的最后一段代碼可能會拋出OutOfMemoryException,因為您在索引它們之前加載了內存中的所有對象。 查看Hibernate Search參考文檔,了解如何正確地批量索引對象的加載。 Manning的Hibernate Search in Action(我是作者)也深入研究了這一切。

最后管理讓它工作..顯然對象不會自動索引..或至少沒有承諾。 我的實現現在看起來如下:

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函數,索引可以正確地存儲在我的索引文件夾中。 然而,這個實現非常不自然,因為我為文本搜索創建了另一個實體管理器。 是否有一種“更清潔”的方法來使用@Transactional注釋索引(和提交)記錄?

最終我的問題通過附加以下屬性解決:hibernate.search.worker.batch_size = 1

我現在不僅可以正確查詢,而且每當我持久保存域對象時索引也會自動更新。 我現在唯一的問題是通過我的import.sql插入的數據不會自動編入索引。 是否有某種“魔術”hibernate.search屬性可用於此問題,還是應該手動索引它們?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM