4 Stimmen

hibernate suche + spring3 + jpa

Ich versuche, die Hibernate-Suche in mein Projekt zu integrieren. Meine Modelle sind indiziert, aber aus irgendeinem Grund meine Suchanfragen geben keine Ergebnisse zurück. Ich habe versucht, dieses Problem für ein paar Stunden jetzt zu lösen, aber nichts, was ich tun, scheint zu funktionieren.

Domänenobjekt:

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

}

Dienst:

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

}

Konfigurationen

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

Die Datenbank ist tatsächlich mit einer Rolle gefüllt, die diesem Autoritätsfeldwert entspricht. Der Entity Manager ist gültig, da alle meine regulären CRUD-Tests erfolgreich sind. Das heißt, der Fehler ist völlig Hibernate Suche (3.1.1.GA) bezogen, aber wo geht es schief?

0 Stimmen

Sind Sie sicher, dass Ihre DB die Volltextsuche unterstützt?

0 Stimmen

Korrektur: die Domänenobjekte sind nicht korrekt indiziert.

0 Stimmen

@Roman: Der ganze Sinn von Hibernate Search ist, dass es nicht die Volltext-Suchfunktion der Datenbank nutzen, erfolgt dies in der Anwendungsschicht.

2voto

Emmanuel Bernard Punkte 890

Theoretisch funktioniert das alles, aber es könnte ein paar Probleme geben:

  • Haben Sie Ihre vorhandenen Objekte zunächst indiziert? Hibernate Search indiziert zwar alle neuen Änderungen, kennt aber die bereits vorhandenen Objekte nicht, so dass Sie diese zunächst indizieren müssen (mit ftem#index()).
  • Standardmäßig klinkt sich HSearch entweder in Hibernate- oder JTA-Transaktionen ein, um auf Ereignisse vor und nach der Transaktion zu warten. Vielleicht umgeht Ihre Spring tx-Konfiguration dies und somit wird HSearch nicht ausgelöst und kann somit nicht indizieren. Der beste Ansatz ist wirklich, einen echten JTA-Transaktionsmanager zu verwenden und diese Fassaden zu vermeiden.
  • wenn Sie über die anfängliche Indizierung (mit index()) sprechen, können Sie alternativ #flushToIndexes() verwenden, um die Indizierung zu erzwingen, auch wenn der tx nicht übergeben wird.
  • Zu guter Letzt wird Ihr letzter Teil des Codes wahrscheinlich eine OutOfMemoryException auslösen, weil Sie alle Objekte in den Speicher laden, bevor Sie sie indizieren. Lesen Sie in der Referenzdokumentation zu Hibernate Search nach, wie Sie die geladenen Objekte ordnungsgemäß im Batch indizieren. Hibernate Search in Action von Manning (ich bin der Autor) geht ebenfalls näher auf all diese Punkte ein.

1voto

Jeroen Punkte 507

Endlich hat es geklappt anscheinend werden die Objekte nicht automatisch indiziert oder zumindest nicht übertragen. Meine Implementierung sieht nun wie folgt aus:

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

Durch die Ausführung der Funktionen index und getTransactionCommit werden die Indizes korrekt in meinem Ordner indexes gespeichert. Diese Implementierung ist jedoch ziemlich unnatürlich, da ich einen alternativen Entity Manager für die Textsuche erstelle. Gibt es einen "saubereren" Weg, Datensätze mit Hilfe der @Transactional-Annotationen zu indizieren (und zu übertragen)?

1voto

Jeroen Punkte 21

Schließlich wurde mein Problem durch Anfügen der folgenden Eigenschaft gelöst: hibernate.search.worker.batch_size=1

Ich kann jetzt nicht nur richtig abfragen, sondern die Indizes werden auch automatisch aktualisiert, wenn ich mein Domänenobjekt aufrechterhalte. Das einzige Problem, das ich jetzt habe, ist, dass die Daten, die über meine import.sql eingefügt werden, nicht automatisch indiziert werden. Gibt es eine Art "magische" hibernate.search-Eigenschaft für dieses Problem oder sollte ich sie manuell indizieren?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X