4

プロジェクトに休止状態の検索を統合しようとしています。モデルにインデックスが付けられていますが、何らかの理由で検索クエリから結果が返されません。この問題を数時間解決しようとしていますが、何もうまくいかないようです。

ドメイン オブジェクト:

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

    ...

}

ダオ:

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)に関連していることを意味しますが、どこが間違っているのでしょうか?

4

3 に答える 3

2

理論的にはすべて動作しますが、いくつかの問題があるかもしれません:

  • 最初に既存のオブジェクトにインデックスを付けましたか? Hibernate Search はすべての新しい変更をインデックス化しますが、既存のオブジェクトを認識しないため、最初にそれらをインデックス化する必要があります (ftem#index() を使用)。
  • デフォルトでは、HSearch は Hibernate または JTA トランザクションにフックして、トランザクション イベントの前後にリッスンします。おそらく、Spring tx 構成がそれをバイパスするため、HSearch がトリガーされず、インデックスを作成できません。最善のアプローチは、実際の JTA トランザクション マネージャーを使用して、これらのファサードを回避することです。
  • (index() を使用して) 最初のインデックス作成について話している場合は、代わりに #flushToIndexes() を使用して、tx がコミットされていない場合でもインデックス作成を強制することができます。
  • 最後になりましたが、インデックスを作成する前にすべてのオブジェクトをメモリにロードするため、コードの最後の部分で OutOfMemoryException がスローされる可能性があります。オブジェクトのロードをバッチで適切にインデックス化する方法については、Hibernate Search リファレンス ドキュメントを確認してください。Manning (私は著者) による Hibernate Search in Action も、これらすべてについてさらに深く掘り下げています。
于 2009-12-22T10:42:55.347 に答える
1

最終的に、次のプロパティを添付することで問題が解決しました: hibernate.search.worker.batch_size=1

適切にクエリを実行できるだけでなく、ドメイン オブジェクトを保持するたびにインデックスも自動的に更新されます。私が今抱えている唯一の問題は、import.sql を介して挿入されたデータが自動的にインデックス化されないことです。この問題に利用できるある種の「魔法の」 hibernate.search プロパティはありますか、それとも手動でインデックスを作成する必要がありますか?

于 2009-12-23T12:13:39.407 に答える
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();
}

index および getTransactionCommit 関数を実行することにより、インデックスは正しくインデックス フォルダーに格納されます。ただし、この実装はかなり不自然です。なぜなら、テキスト検索用に別のエンティティ マネージャーを作成しているからです。@Transactional アノテーションを使用してレコードをインデックス化 (およびコミット) する「よりクリーンな」方法はありますか?

于 2009-12-21T15:05:29.730 に答える