13.3. Recherche


Hibernate Search peut exécuter des requêtes Lucene et récupérer des objets de domaine gérés par une session Hibernate. La recherche offre la puissance de Lucene sans laisser le paradigme Hibernate, donnant ainsi une autre dimension aux mécanismes de recherche classiques de Hibernate (HQL, Criteria query, native SQL query).
La préparation et l'exécution d'une requête consiste en quatre étapes :
  • La création d'une FullTextSession
  • La création d'une requête Lucene à l'aide de la DSL de requête Hibernate Search (recommandé) ou l'API de requête Lucene
  • L'inclusion d'une requête Lucene avec org.hibernate.Query
  • L'exécution de la recherche en appelant par exemple list() ou scroll()
Pour accéder aux fonctions de requêtes, utilisez une FullTextSession. Cette session spécifique à la recherche inclut une classe org.hibernate.Session régulière afin de fournir une requête et des capacités d'indexation.

Exemple 13.30. Création d'une FullTextSession

Session session = sessionFactory.openSession();
...
FullTextSession fullTextSession = Search.getFullTextSession(session);
Utilisez FullTextSession pour construire une requête en texte intégral en utilisant la DSL de requête Hibernate Search ou la requête Lucene native.
Utilisez le code suivant pour la DSL de requête Hibernate Search :
final QueryBuilder b = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity( Myth.class ).get();

org.apache.lucene.search.Query luceneQuery =
    b.keyword()
        .onField("history").boostedTo(3)
        .matching("storm")
        .createQuery();

org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );
List result = fullTextQuery.list(); //return a list of managed objects
Ou rédigez la requête Lucene avec l'analyseur de requête Lucene ou l'API de programmation Lucene.

Exemple 13.31. Création d'une requête Lucene à l'aide de QueryParser

SearchFactory searchFactory = fullTextSession.getSearchFactory();
org.apache.lucene.queryParser.QueryParser parser = 
    new QueryParser("title", searchFactory.getAnalyzer(Myth.class) );
try {
    org.apache.lucene.search.Query luceneQuery = parser.parse( "history:storm^3" );
}
catch (ParseException e) {
    //handle parsing failure
}

org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery(luceneQuery);
List result = fullTextQuery.list(); //return a list of managed objects
Une requête Hibernate créée sur la requête Lucene est une org.hibernate.Query. Cette requête demeure dans le même paradigme que d'autres fonctions de requête Hibernate, telles que HQL (Hibernate Query Language), Native et Criteria. Utilisez des méthodes telles que list(), uniqueResult(), iterate() et scroll() avec la requête.
Les mêmes extensions sont disponibles avec les API Hibernate Java Persistence :

Exemple 13.32. Création d'une requête de recherche à l'aide de l'API JPA

EntityManager em = entityManagerFactory.createEntityManager();

FullTextEntityManager fullTextEntityManager = 
    org.hibernate.search.jpa.Search.getFullTextEntityManager(em);

...
final QueryBuilder b = fullTextEntityManager.getSearchFactory()
    .buildQueryBuilder().forEntity( Myth.class ).get();

org.apache.lucene.search.Query luceneQuery =
    b.keyword()
        .onField("history").boostedTo(3)
        .matching("storm")
        .createQuery();
javax.persistence.Query fullTextQuery = fullTextEntityManager.createFullTextQuery( luceneQuery );

List result = fullTextQuery.getResultList(); //return a list of managed objects

Note

Dans les exemples suivants, nous allons utiliser les API d'Hibernate mais on peut facilement réécrire le même exemple avec un API de Java Persistence en ajustant la façon dont la FullTextQuery est extraite.

13.3.1. Création de requêtes

Les requêtes de Hibernate Search sont générées sur des requêtes Lucene, permettant ainsi aux utilisateurs d'utiliser tout type de requête Lucene. Lorsque la requête est générée, Hibernate Search utilise org.hibernate.Query comme API de manipulation de requête pour traiter les requêtes de manière approfondie.

13.3.1.1. Générer une requête Lucene avec l'API Lucene

Avec l'API Lucene, utilisez soit l'analyseur de requête (requête simple) ou l'API de programmation Lucene (requêtes complexes). Créer une requête Lucene est en dehors du domaine de la documentation Hibernate Search. Pour plus de détails, veuillez consulter la documentation Lucene en ligne ou une copie de Lucene in Action ou Hibernate Search in Action.

13.3.1.2. Génération d'une requête Lucene

L'API programmée de Lucene active les requêtes de texte intégral. Cependant, lors de son utilisation, les paramètres doivent être convertis à leur équivalent de chaîne et doivent également appliquer le bon analyseur au champ qui convient. Un analyseur ngram utilise par exemple plusieurs ngrams comme jetons pour un mot donné et devrait être recherché comme tel. Il est recommandé d'utiliser QueryBuilder pour cette tâche.
L'API de requête de Hibernate Search est fluide, avec les caractéristiques clés suivantes :
  • Les noms de méthodes sont en anglais. Ainsi, les opérations API peuvent être lues et comprises comme une série d'expressions et instructions en anglais.
  • Elle utilise le complètement automatique IDE ce qui facilite les complètements pour le préfixe d'entrée actuel et permet à l'utilisateur de choisir l'option qui convient.
  • Elle utilise souvent le modèle de la méthode de chaîne.
  • Les opérations API sont faciles à lire et à utiliser.
Pour utiliser l'API, veuillez d'abord créer un générateur de requêtes attaché à un indexedentitytype donné. Ce QueryBuilder sait quel analyseur utiliser et quel pont de champ appliquer. Plusieurs QueryBuilder (un pour chaque type d'entité impliqué dans la racine de votre requête) peuvent être créés. Le QueryBuilder provient de SearchFactory.
QueryBuilder mythQB = searchFactory.buildQueryBuilder().forEntity( Myth.class ).get();
L'analyseur utilisé pour un ou des champ(s) donné(s) peut également être remplacé.
QueryBuilder mythQB = searchFactory.buildQueryBuilder()
    .forEntity( Myth.class )
        .overridesForField("history","stem_analyzer_definition")
    .get();
Le générateur de requêtes est désormais utilisé pour générer des requêtes Lucene. Les requêtes personnalisées générées à l'aide de l'analyseur de requêtes de Lucene ou des objets Query assemblés avec l'API programmée de Lucene sont utilisées avec Hibernate Search DSL.

13.3.1.3. Requêtes de mots-clés

L'exemple suivant explique comment rechercher un mot spécifique :
Query luceneQuery = mythQB.keyword().onField("history").matching("storm").createQuery();
Tableau 13.4. Paramètres de requête de mot-clé
Paramètre Description
keyword() Utilisez ce paramètre pour trouver un mot spécifique
onField() Utilisez ce paramètre pour spécifier le champ Lucene dans lequel rechercher le mot
matching() Utilisez ce paramètre pour spécifier la correspondance pour chaque chaîne
createQuery() Crée l'objet de requête de Lucene
  • La valeur « storm » est transmise à la classe history FieldBridge, ce qui est utile lorsque les nombres ou dates sont impliqués.
  • La valeur de pont du champ est ensuite transmise à l'analyseur utilisé pour indexer le champ history, ce qui permet de garantir que la requête utilise la même transformation de terme que l'indexation (bas de casse, ngram, analyse de radical etc.). Si le processus d'analyse génère plusieurs termes pour un même mot, une requête booléenne sera utilisée avec la logique SHOULD (semblable à une logique OR).
Pour rechercher une propriété n'étant pas de type chaîne.
@Indexed 
public class Myth {
  @Field(analyze = Analyze.NO) 
  @DateBridge(resolution = Resolution.YEAR)
  public Date getCreationDate() { return creationDate; }
  public Date setCreationDate(Date creationDate) { this.creationDate = creationDate; }
  private Date creationDate;
  
  ...
}

Date birthdate = ...;
Query luceneQuery = mythQb.keyword().onField("creationDate").matching(birthdate).createQuery();

Note

En Lucene brut, l'objet Date devait être converti en sa représentation de chaîne (dans ce cas-là, l'année)
Cette conversion fonctionne avec tous les objets, à condition que la classe FieldBridge ait une méthode objectToString (ce qui est le cas pour toutes les mises en œuvre FieldBridge intégrées).
L'exemple suivant recherche un champ utilisant des analyseurs ngram. Les analyseurs ngram indexent des successions de ngrams de mots, ce qui aide à éviter les fautes de frappe de l'utilisateur. Par exemple, les 3-grammes du mot « hibernate » sont hib, ibe, ber, ern, rna, nat, ate.
@AnalyzerDef(name = "ngram",
  tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class ),
  filters = {
    @TokenFilterDef(factory = StandardFilterFactory.class),
    @TokenFilterDef(factory = LowerCaseFilterFactory.class),
    @TokenFilterDef(factory = StopFilterFactory.class),
    @TokenFilterDef(factory = NGramFilterFactory.class,
      params = { 
        @Parameter(name = "minGramSize", value = "3"),
        @Parameter(name = "maxGramSize", value = "3") } )
  }
)

public class Myth {
  @Field(analyzer=@Analyzer(definition="ngram") 
  public String getName() { return name; }
  public String setName(String name) { this.name = name; }
  private String name;
  
  ...
}

Date birthdate = ...;
Query luceneQuery = mythQb.keyword().onField("name").matching("Sisiphus")
   .createQuery();
Le mot « Sisiphus » sera écrit en minuscule, puis découpé en 3-grams : sis, isi, sip, iph, phu, hus. Chacun de ces n-grams feront partie de la requête. L'utilisateur est ensuite en mesure de trouver le mythe Sysiphus (avec un y). Tout cela est fait de manière transparente pour l'utilisateur.

Note

Si l'utilisateur ne souhaite pas qu'un champ spécifique utilise le pont de champ ou l'analyseur, alors les fonctions ignoreAnalyzer() ou ignoreFieldBridge() peuvent être appelées.
Pour rechercher plusieurs mots possibles dans le même champ, ajoutez-les tous à la clause correspondante.
//search document with storm or lightning in their history
Query luceneQuery = 
    mythQB.keyword().onField("history").matching("storm lightning").createQuery();
Pour rechercher le même mot sur de multiples champs, utilisez la méthode onFields.
Query luceneQuery = mythQB
    .keyword()
    .onFields("history","description","name")
    .matching("storm")
    .createQuery();
Quelques fois, un champ doit être traité différemment d'un autre champ même si la recherche porte sur le même terme, utilisez donc la méthode andField().
Query luceneQuery = mythQB.keyword()
    .onField("history")
    .andField("name")
      .boostedTo(5)
    .andField("description")
    .matching("storm")
    .createQuery();
Dans l'exemple précédent, seul le nom de champ a été boosté à 5.

13.3.1.4. Requêtes Fuzzy (approximatives)

Pour exécuter une requête approximative (sur la base de l'algorithme de distance Levenshtein), commencez par une requête de keyword et ajoutez l'indicateur fuzzy.
Query luceneQuery = mythQB
    .keyword()
      .fuzzy()
        .withThreshold( .8f )
        .withPrefixLength( 1 )
    .onField("history")
    .matching("starm")
    .createQuery();
Le threshold est la limite au-dessus de laquelle deux termes sont considérés comme correspondant. Il s'agit d'une décimal entre 0 et 1 et la valeur par défaut est 0.5. Le prefixLength est la longueur du préfix ignoré par l'« approximation ». Bien que la valeur par défaut soit 0, une valeur autre que 0 est recommandée pour les indexes contenant un grand nombre de termes distincts.

13.3.1.5. Requêtes Wildcard

Les requêtes Wildcard sont utiles dans les situations où seule une partie du mot est connue. Le ? représente un caractère unique et * représente plusieurs caractères. Veuillez noter que dans un soucis de performance, il est recommandé que la requête ne commence pas par ? ou *.
Query luceneQuery = mythQB
    .keyword()
      .wildcard()
    .onField("history")
    .matching("sto*")
    .createQuery();

Note

Les requêtes Wildcard n'appliquent pas l'analyseur sur les termes correspondants. Le risque de voir * ou ? altéré est trop grand.

13.3.1.6. Requêtes de phrase

Nous n'avons pour l'instant mentionné que les recherches de mots ou groupes de mots, mais l'utilisateur peut également rechercher des phrases exactes ou approximatives. Pour cela, utilisez phrase().
Query luceneQuery = mythQB
    .phrase()
    .onField("history")
    .sentence("Thou shalt not kill")
    .createQuery();
Des phrases approximatives peuvent être cherchées en ajoutant un facteur slop. Le facteur slop représente le nombre d'autres mots autorisés dans la phrase : cela fonctionne comme un opérateur interne ou rapproché.
Query luceneQuery = mythQB
    .phrase()
      .withSlop(3)
    .onField("history")
    .sentence("Thou kill")
    .createQuery();

13.3.1.7. Requêtes de portée

Une requête de portée recherche une valeur située entre certaines limites (incluse ou non) ou une valeur inférieure ou supérieure à une limite donnée (incluse ou non).
//look for 0 <= starred < 3
Query luceneQuery = mythQB
    .range()
    .onField("starred")
    .from(0).to(3).excludeLimit()
    .createQuery();

//look for myths strictly BC
Date beforeChrist = ...;
Query luceneQuery = mythQB
    .range()
    .onField("creationDate")
    .below(beforeChrist).excludeLimit()
    .createQuery();

13.3.1.8. Association de requêtes

Des requêtes peuvent être associées entre elles pour créer des requêtes plus complexes. Les opérateurs d'associations suivants sont disponibles :
  • SHOULD (devrait) : la requête devrait contenir les éléments de correspondance de la sous-requête.
  • MUST (doit) : la requête doit contenir les éléments correspondants de la sous-requête.
  • MUST NOT (ne doit pas) : la requête ne doit pas contenir les éléments correspondants de la sous-requête.
Les sous-requêtes peuvent être des requêtes Lucene dont une requête booléenne.

Exemple 13.33. Requête MUST NOT

//look for popular modern myths that are not urban
Date twentiethCentury = ...;
Query luceneQuery = mythQB
    .bool()
      .must( mythQB.keyword().onField("description").matching("urban").createQuery() )
        .not()
      .must( mythQB.range().onField("starred").above(4).createQuery() )
      .must( mythQB
        .range()
        .onField("creationDate")
        .above(twentiethCentury)
        .createQuery() )
    .createQuery();

Exemple 13.34. Requête SHOULD

//look for popular myths that are preferably urban
Query luceneQuery = mythQB
    .bool()
      .should( mythQB.keyword().onField("description").matching("urban").createQuery() )
      .must( mythQB.range().onField("starred").above(4).createQuery() )
    .createQuery();

Exemple 13.35. Requête NOT

//look for all myths except religious ones
Query luceneQuery = mythQB
    .all()
      .except( monthQb
        .keyword()
        .onField( "description_stem" )
        .matching( "religion" )
        .createQuery() 
      )
    .createQuery();

13.3.1.9. Options de requête

La DSL de requête Hibernate Search est une API de requête facile à lire et à utiliser. En acceptant et en créant les requêtes Lucene, vous pouvez incorporer des types de requête pas encore prises en charge par la DSL.
Voici un résumé d'options de requêtes pour les champs et types de requêtes :
  • La méthode boostedTo (sur les champs et types de requêtes) booste la requête entière ou le champ spécifique vers un facteur donné.
  • La méthode withConstantScore (sur requête) renvoie tous les résultats correspondants à la requête ayant un score égal au boost.
  • La méthode filteredBy(Filter) (sur requête) filtre les résultats de requêtes à l'aide de l'instance Filter.
  • La méthode ignoreAnalyzer (sur champ) ignore l'analyseur lors du traitement de ce champ.
  • La méthode ignoreFieldBridge (sur champ) ignore le pont de champ lors du traitement de ce champ.

Exemple 13.36. Associations d'options de requêtes

Query luceneQuery = mythQB
    .bool()
      .should( mythQB.keyword().onField("description").matching("urban").createQuery() )
      .should( mythQB
        .keyword()
        .onField("name")
          .boostedTo(3)
          .ignoreAnalyzer()
        .matching("urban").createQuery() )
      .must( mythQB
        .range()
          .boostedTo(5).withConstantScore()
        .onField("starred").above(4).createQuery() )
    .createQuery();

13.3.1.10. Créer une requête Hibernate Search

13.3.1.10.1. Généralités
Une fois la requête Lucene générée, incluez-la dans une requête Hibernate. La requête recherche toutes les entités indexées et renvoie tous les types de classes indexées à moins qu'elle ne soit configurée explicitement à ne pas le faire.

Exemple 13.37. Inclure une requête Lucene dans une requête Hibernate.

FullTextSession fullTextSession = Search.getFullTextSession( session );
org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );
Pour de meilleures résultats, restreignez les types comme suit :

Exemple 13.38. Filtrage des résultats de la recherche par type d'entité

fullTextQuery = fullTextSession
    .createFullTextQuery( luceneQuery, Customer.class );

// or

fullTextQuery = fullTextSession
    .createFullTextQuery( luceneQuery, Item.class, Actor.class );
La première partie du second exemple ne renvoie que les Customer correspondants. La seconde partie du même exemple renvoie des Actor et Item correspondants. La restriction de type est polymorphe. Ainsi, si les deux sous-classes Salesman et Customer de la classe de base Person apparaissent dans les résultats, spécifiez Person.class pour filtre sur la base des types de résultat.
13.3.1.10.2. Pagination
Pour éviter une dégradation de la performance, il est recommandé de restreindre le nombre d'objets renvoyés par requête. Un utilisateur naviguant d'une page à une autre est un cas d'utilisation courant. La façon de définir la pagination est semblable à la façon de définir la pagination dans une requête de Critère ou HQL brute.

Exemple 13.39. Définir une pagination pour une requête de recherche

org.hibernate.Query fullTextQuery = 
    fullTextSession.createFullTextQuery( luceneQuery, Customer.class );
fullTextQuery.setFirstResult(15); //start from the 15th element
fullTextQuery.setMaxResults(10); //return 10 elements

Note

Est-il toujours possible d'obtenir le nombre total d'éléments correspondants indépendamment de la pagination par le biais de fulltextQuery.getResultSize()
13.3.1.10.3. Tri
Apache Lucene présente un mécanisme de tri de résultats puissant et flexible à la fois. Par défaut, le tri s'effectue par pertinence et est adapté aux grandes variétés de cas d'utilisation. Le mécanisme de tri peut être changé pour effectuer un tri selon d'autres propriétés à l'aide de l'objet Lucene Sort pour appliquer une stratégie de tri Lucene.

Exemple 13.40. Spécifier un Sort Lucene

org.hibernate.search.FullTextQuery query = s.createFullTextQuery( query, Book.class );
org.apache.lucene.search.Sort sort = new Sort(
    new SortField("title", SortField.STRING));
query.setSort(sort);
List results = query.list();

Note

Les champs utilisés pour le tri ne doivent pas contenir de jetons. Pour plus d'informations sur la génération de jetons, voir Section 13.2.1.1.2, « @Field ».
13.3.1.10.4. Stratégie de récupération
Hibernate Search charge les objets à l'aide d'une requête unique si les types de résultats sont restreints à une classe. Hibernate Search est restreint par la stratégie de récupération statique définie dans le modèle de domaine. Il est utile d'affiner la stratégie de récupération pour un cas d'utilisation spécifique comme suit :

Exemple 13.41. Spécification de FetchMode dans une requête

Criteria criteria = 
    s.createCriteria( Book.class ).setFetchMode( "authors", FetchMode.JOIN );
s.createFullTextQuery( luceneQuery ).setCriteriaQuery( criteria );
Dans cet exemple, la requête renverra tous les livres correspondant à LuceneQuery. La collection d'auteurs sera chargée à partir de la même requête à l'aide d'une jointure externe SQL.
Dans une définition de requête de critère, le type est déduit d'après la requête de critère fournie. Il n'est donc pas nécessaire de restreindre les résultats de types d'entité.

Important

Le mode de récupération est la seule propriété ajustable. N'utilisez pas une restriction (une clause where) sur la requête Criteria car la méthode getResultSize() émet une SearchException lorsqu'elle est utilisée en association avec une classe Criteria avec restriction.
Si vous vous attendez à plus d'une entité, n'utilisez pas setCriteriaQuery.
13.3.1.10.5. Projection
Dans certains cas, un sous-ensemble des propriétés suffit. Utilisez Hibernate Search pour renvoyer un sous-ensemble de propriétés comme suit :
Hibernate Search extrait des propriétés de l'index Lucene et les convertit en la représentation de leur objet et renvoie une liste d'Object[]. Les projections permettent d'éviter les longs allers-retours dans la base de données, mais elles présentent également les contraintes suivantes :
  • Les propriétés projetées doivent être stockées dans l'index (@Field(store=Store.YES)), ce qui augmente la taille de l'index.
  • Les propriétés projetées doivent utiliser un FieldBridge mettant en œuvre org.hibernate.search.bridge.TwoWayFieldBridge ou org.hibernate.search.bridge.TwoWayStringBridge, ce dernier étant la version la plus simple.

    Note

    Tous les types d'Hibernate Search intégrés sont bidirectionnels.
  • Seules les propriétés simples de l'entité indexée ou de ses associations intégrées peuvent être projetées : une entité entière intégrée ne peut donc pas être projetée.
  • La projection ne fonctionne pas sur les collections ou cartes indexées par le biais de @IndexedEmbedded
Lucene fournit des informations de métadonnées sur les résultats de requêtes. Utilisez les constantes de projection pour récupérer les métadonnées.

Exemple 13.42. Utilisation de la projection pour récupérer les métadonnées

org.hibernate.search.FullTextQuery query = 
    s.createFullTextQuery( luceneQuery, Book.class );
query.setProjection( FullTextQuery.SCORE, FullTextQuery.THIS, "mainAuthor.name" );
List results = query.list();
Object[] firstResult = (Object[]) results.get(0);
float score = firstResult[0];
Book book = firstResult[1];
String authorName = firstResult[2];
Les champs peuvet être mélangés avec les constantes de projection suivantes :
  • FullTextQuery.THIS : renvoie l'entité gérée et initialisée (tel que l'aurait fait une requête non projetée).
  • FullTextQuery.DOCUMENT : renvoie le document Lucene lié à l'objet projeté.
  • FullTextQuery.OBJECT_CLASS : renvoie la classe de l'entité indexée.
  • FullTextQuery.SCORE : renvoie le score du document dans la requête. Les scores sont utiles pour comparer deux résultats d'une requête donnée, mais sont inutiles pour comparer le résultat de différentes requêtes.
  • FullTextQuery.ID: la valeur de propriété de l'ID de l'objet projeté.
  • FullTextQuery.DOCUMENT_ID : l'ID du document Lucene. Utilisez cette valeur avec précaution car un ID de document Lucene peut changer entre deux ouvertures IndexReader différentes.
  • FullTextQuery.EXPLANATION : renvoie l'objet d'explication Lucene pour l'objet/document correspondant dans une requête donnée mais ne convient pas à la récupération de grandes quantités de données. L'exécution d'explication coûte autant que d'exécuter la requête Lucene entière par élément correspondant. La projection est donc recommandée.
13.3.1.10.6. Personnalisation de stratégies d'initialisation d'objet
Par défaut, Hibernate Search utilise la stratégie la mieux adaptée pour initialiser des entités correspondant à la requête de texte intégral. Il exécute une (ou plusieurs) requêtes pour récupérer les entités requises. Cette approche réduit les recherches dans la base de données où peu d'entités récupérées sont présentes dans le contexte de persistance (la session) ou le cache de second niveau.
Si des entités sont présentes dans le cache de second niveau, forcez Hibernate Search à chercher dans le cache avant de récupérer un objet de base de données.

Exemple 13.43. Vérifiez le cache de secon niveau avant d'utiliser une requête

FullTextQuery query = session.createFullTextQuery(luceneQuery, User.class);
query.initializeObjectWith(
    ObjectLookupMethod.SECOND_LEVEL_CACHE,
    DatabaseRetrievalMethod.QUERY
);
ObjectLookupMethod définit la stratégie consistant à vérifier si un objet est facilement accessible (sans avoir à le trouver dans une base de données). Autres options :
  • ObjectLookupMethod.PERSISTENCE_CONTEXT est utilisé si un grand nombre d'entités correspondantes sont déjà chargées dans le contexte de persistance (chargées dans Session ou EntityManager).
  • ObjectLookupMethod.SECOND_LEVEL_CACHE vérifie le contexte de persistance puis le cache de second niveau.
Actions à effectuer pour rechercher dans le cache de second niveau :
  • Configurez et activez correctement le cache de second niveau.
  • Activez le cache de second niveau pour l'entité souhaitée à l'aide d'annotations telles que @Cacheable.
  • Activez l'accès de lecture de cache de second niveau pour Session, EntityManager ou Query. Utilisez CacheMode.NORMAL dans les API natives de Hibernate ou CacheRetrieveMode.USE dans les API de Persistance Java.

Avertissement

À moins que la mise en œuvre de cache de second niveau soit EHCache ou Infinispan, n'utilisez pas ObjectLookupMethod.SECOND_LEVEL_CACHE. D'autres fournisseurs de cache de second niveau ne mettent pas en œuvre cette opération de manière efficace.
Personnalisez le chargement des objets à partir de la base de données à l'aide de la classe DatabaseRetrievalMethod comme suit :
  • QUERY (par défaut) utilise un ensemble de requêtes pour charger différents objets dans chaque lot. Cette approche est recommandée.
  • FIND_BY_ID charge un objet à la fois à l'aide de la sémantique Session.get ou EntityManager.find. Cette approche est recommandée si la taille du lot est définie pour l'entité, ce qui permet à Hibernate Core de charger des entités par lots.
13.3.1.10.7. Limiter le temps d'une requête
Limiter le temps que prend une requête dans Hibernate Guide comme suit:
  • Lever une exception lorsque la limite est atteinte.
  • Limiter au nombre de résultats récupérés lorsque la limite de temps est levée
13.3.1.10.8. Lever une Exception de Limite de temps
Si une requête utilise un montant supérieur au temps défini, une exception QueryTimeoutException est levée (org.hibernate.QueryTimeoutException ou javax.persistence.QueryTimeoutException suivant l'API programmatique).
Pour définir la limite lors de l'utilisation des API Hibernate natives, veuillez utiliser l'une des approches suivantes :

Exemple 13.44. Définition d'un Timeout dans une exécution de requête

Query luceneQuery = ...;
FullTextQuery query = fullTextSession.createFullTextQuery(luceneQuery, User.class);

//define the timeout in seconds
query.setTimeout(5);

//alternatively, define the timeout in any given time unit
query.setTimeout(450, TimeUnit.MILLISECONDS);

try {
    query.list();
}
catch (org.hibernate.QueryTimeoutException e) {
    //do something, too slow
}
Les méthodes getResultSize(), iterate() et scroll() respectent le timeout jusqu'à la fin de la méthode. C'est pourquoi Iterable ou ScrollableResults ignorent le timeout. De plus, la méthode explain() ne respecte pas cette période de timeout. Cette méthode est utilisée pour déboguer et pour vérifier les raisons derrière la contre-performance d'une requête.
Voici la méthode standard pour limiter le temps d'exécution à l'aide du « Java Persistence API » (JPA) :

Exemple 13.45. Définition d'un Timeout dans une exécution de requête

Query luceneQuery = ...;
FullTextQuery query = fullTextEM.createFullTextQuery(luceneQuery, User.class);

//define the timeout in milliseconds
query.setHint( "javax.persistence.query.timeout", 450 );

try {
    query.getResultList();
}
catch (javax.persistence.QueryTimeoutException e) {
    //do something, too slow
}

Important

Le code pris comme exemple ne garantit pas que la requête s'arrêtera au nombre de résultats spécifié.
Red Hat logoGithubRedditYoutubeTwitter

Apprendre

Essayez, achetez et vendez

Communautés

À propos de la documentation Red Hat

Nous aidons les utilisateurs de Red Hat à innover et à atteindre leurs objectifs grâce à nos produits et services avec un contenu auquel ils peuvent faire confiance.

Rendre l’open source plus inclusif

Red Hat s'engage à remplacer le langage problématique dans notre code, notre documentation et nos propriétés Web. Pour plus de détails, consultez leBlog Red Hat.

À propos de Red Hat

Nous proposons des solutions renforcées qui facilitent le travail des entreprises sur plusieurs plates-formes et environnements, du centre de données central à la périphérie du réseau.

© 2024 Red Hat, Inc.