Bevezetés a hibernált keresésbe

1. Áttekintés

Ebben a cikkben megvitatjuk a hibernált keresés alapjait, a konfigurálását, és néhány egyszerű kérdést végrehajtunk.

2. A hibernált keresés alapjai

Amikor teljes szövegű keresési funkciót kell megvalósítanunk, az olyan eszközök használata, amelyekben már jártasak vagyunk, mindig plusz.

Abban az esetben, ha már a Hibernate és a JPA-t használjuk az ORM-hez, csak egy lépés választ el a Hibernate Search-től.

A hibernált keresés integrálja az Apache Lucene-t, egy nagy teljesítményű és kibővíthető teljes szövegű keresőmotor könyvtárat, amely Java-ban íródott. Ez ötvözi a Lucene erejét a Hibernate és a JPA egyszerűségével.

Egyszerűen fogalmazva, csak fel kell tennünk néhány további megjegyzést a domain osztályainkhoz, és az eszköz gondoskodni fog például az adatbázis / index szinkronizálásáról.

A hibernált keresés egy Elasticsearch integrációt is biztosít; mivel azonban még mindig kísérleti stádiumban van, itt Lucene-re fogunk koncentrálni.

3. Konfigurációk

3.1. Maven-függőségek

Mielőtt elkezdenénk, először hozzá kell adnunk a szükséges függőségeket pom.xml:

 org.hibernate hibernate-search-orm 5.8.2.Végső 

Az egyszerűség kedvéért a H2-t fogjuk használni adatbázisunkként:

 com.h2adatbázis h2 1.4.196 

3.2. Konfigurációk

Meg kell adnunk azt is, hogy a Lucene hol tárolja az indexet.

Ezt a szálláshelyen keresztül lehet megtenni hibernate.search.default.directory_provider.

Majd mi választjuk fájlrendszer, amely a legegyszerűbb lehetőség a mi esetünkben. További lehetőségeket a hivatalos dokumentáció tartalmaz. Fájlrendszer-master/fájlrendszer-szolga és infinispan figyelemre méltóak a fürtözött alkalmazások esetében, ahol az indexet szinkronizálni kell a csomópontok között.

Meg kell határoznunk egy alapértelmezett alapkönyvtárat is, ahol az indexek tárolódnak:

hibernate.search.default.directory_provider = fájlrendszer hibernate.search.default.indexBase = / data / index / default

4. A modellosztályok

A konfigurálás után készen állunk a modell megadására.

A Közös Parlamenti Közgyűlés feliratozásának tetején @Entity és @Asztal, hozzá kell adnunk egy @Teljes annotáció. Azt mondja a hibernált keresésnek, hogy az entitás Termék indexelni kell.

Ezt követően meg kell határoznunk a szükséges attribútumokat kereshetőként az a hozzáadásával @Terület annotáció:

@Entity @Indexed @Table (name = "product") public class Product {@Id private int id; @Field (termVector = TermVector.YES) private String termékNév; @Field (termVector = TermVector.YES) privát karakterlánc leírása; @Field privát int memória; // szerelők, beállítók és konstruktorok}

A termVector = TermVector.IGEN attribútumra lesz szükség a „Több hasonló” lekérdezéshez később.

5. A Lucene Index felépítése

A tényleges lekérdezések megkezdése előtt ki kell indítanunk Lucene-t, hogy kezdetben felépítse az indexet:

FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager (entitásManager); fullTextEntityManager.createIndexer (). startAndWait ();

A kezdeti összeállítás után a Hibernate Search gondoskodik az index naprakészen tartásáról. I. e. létrehozhatunk, manipulálhatunk és törölhetünk entitásokat a EntityManager mint általában.

Jegyzet: meg kell győződnünk arról, hogy az entitások teljes mértékben elkötelezettek-e az adatbázis mellett, mielőtt Lucene felfedezheti és indexelheti őket (mellesleg ez az oka annak is, hogy a példakód-teszteseteinkben a kezdeti tesztadatok importálása egy dedikált JUnit-tesztesetben történik, @Elkövetni).

6. Lekérdezések készítése és végrehajtása

Most készen állunk az első lekérdezés létrehozására.

A következő szakaszban megmutatjuk a lekérdezés előkészítésének és végrehajtásának általános munkafolyamatát.

Ezt követően létrehozunk néhány példakérdezést a legfontosabb lekérdezési típusokhoz.

6.1. Általános munkafolyamat egy lekérdezés létrehozásához és végrehajtásához

A lekérdezés előkészítése és végrehajtása általában négy lépésből áll:

Az 1. lépésben meg kell szereznünk egy JPA-t FullTextEntityManager és ettől a QueryBuilder:

FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager (entitásManager); QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory () .buildQueryBuilder () .forEntity (Product.class) .get ();

A 2. lépésben létrehozunk egy Lucene lekérdezést a hibernált lekérdezés DSL-en keresztül:

org.apache.lucene.search.Query lekérdezés = queryBuilder .keyword () .onField ("productName") .matching ("iphone") .createQuery ();

A 3. lépésben a Lucene lekérdezést hibernált lekérdezésbe csomagoljuk:

org.hibernate.search.jpa.FullTextQuery jpaQuery = fullTextEntityManager.createFullTextQuery (lekérdezés, Product.class);

Végül a 4. lépésben végrehajtjuk a lekérdezést:

Eredménylista = jpaQuery.getResultList ();

jegyzet: alapértelmezés szerint a Lucene relevancia szerint rendezi az eredményeket.

Az 1., 3. és 4. lépés minden lekérdezési típusnál megegyezik.

A következőkben a 2. lépésre koncentrálunk, azaz. e. hogyan lehet különféle típusú lekérdezéseket létrehozni.

6.2. Kulcsszó lekérdezések

A legalapvetőbb felhasználási eset az egy adott szó keresése.

Ezt tettük valójában már az előző szakaszban:

Query keywordQuery = queryBuilder .keyword () .onField ("productName") .matching ("iphone") .createQuery ();

Itt, kulcsszó () meghatározza, hogy egy konkrét szót keresünk, a pályán() megmondja Lucene-nek, hol kell keresnie és egyezés () mit kell keresni.

6.3. Fuzzy Queries

A fuzzy lekérdezések kulcsszóhoz hasonlóan működnek, kivéve meghatározhatjuk a „fuzziness” határát, amely felett Lucene elfogadja a két kifejezést egyezőnek.

Által withEditDistanceUpTo (), meghatározhatjuk, hogy egy kifejezés mennyire térhet el a másiktól. Beállítható 0, 1 és 2 értékre, ahol az alapértelmezett érték 2 (jegyzet: ez a korlát a Lucene megvalósításából származik).

Által withPrefixLength (), meghatározhatjuk az előtag hosszát, amelyet a fuzziness figyelmen kívül hagy:

Query fuzzyQuery = queryBuilder .keyword () .fuzzy () .withEditDistanceUpTo (2) .withPrefixLength (0) .onField ("productName") .matching ("iPhaen") .createQuery ();

6.4. Helyettesítő lekérdezések

A hibernált keresés lehetővé teszi számunkra a helyettesítő lekérdezések végrehajtását is, azaz e. lekérdezések, amelyeknél a szó egy része ismeretlen.

Ehhez használhatjuk a?” egyetlen karakter esetén, és*” bármilyen karaktersorozathoz:

Query wildcardQuery = queryBuilder .keyword () .wildcard () .onField ("productName") .matching ("Z *") .createQuery ();

6.5. Frázis lekérdezések

Ha egynél több szóra akarunk keresni, használhatunk kifejezéslekérdezéseket. Vagy megnézhetjük pontos vagy közelítő mondatokra, használatával kifejezés() és withSlop (), ha szükséges. A meredekségi tényező meghatározza a mondatban engedélyezett további szavak számát:

Lekérdezés kifejezésQuery = queryBuilder .phrase () .withSlop (1) .onField ("leírás") .mondat ("vezeték nélküli töltéssel") .createQuery ();

6.6. Egyszerű lekérdezési karakterlánc lekérdezések

Az előző lekérdezési típusokkal kifejezetten meg kellett adnunk a lekérdezés típusát.

Ha további erőt akarunk adni a felhasználónak, használhatunk egyszerű lekérdezési karakterlánc-lekérdezéseket: ezáltal futás közben meghatározhatja saját kérdéseit.

A következő lekérdezési típusok támogatottak:

  • logikai érték (ÉS a „+” használatával, VAGY a „|” használatával, NEM a „-“ használatával)
  • előtag (előtag *)
  • kifejezés („valamilyen kifejezés”)
  • elsőbbség (zárójelek használatával)
  • fuzzy (fuzy ~ 2)
  • operátor közelében kifejezéskérdésekhez („néhány kifejezés” ~ 3)

A következő példa egyesítené a fuzzy, a kifejezés és a logikai lekérdezéseket:

Query simpleQueryStringQuery = queryBuilder .simpleQueryString () .onFields ("productName", "description") .matching ("Aple ~ 2 + \" iPhone X \ "+ (256 | 128)") .createQuery ();

6.7. Tartomány lekérdezések

Tartomány lekérdezések aérték a megadott határok között. Ez alkalmazható számokra, dátumokra, időbélyegekre és karakterláncokra:

Query rangeQuery = queryBuilder .range () .onField ("memória") .from (64) .to (256) .createQuery ();

6.8. Több hasonló ehhez a lekérdezéshez

Utolsó lekérdezési típusunk a „Több hasonló" - lekérdezés. Ehhez biztosítunk egy entitást, és A hibernált keresés listát ad vissza hasonló entitásokkal, mindegyik hasonlósági ponttal rendelkezik.

Mint korábban említettük, a termVector = TermVector.IGEN A modellosztályunk attribútuma ebben az esetben szükséges: megmondja Lucene-nek, hogy tárolja az egyes kifejezések frekvenciáját az indexelés során.

Ez alapján a hasonlóság kiszámítása a lekérdezés végrehajtásának időpontjában történik:

Query moreLikeThisQuery = queryBuilder .moreLikeThis () .comparingField ("productName"). BoostedTo (10f) .andField ("leírás"). BoostedTo (1f) .toEntity (entitás) .createQuery (); Lista eredmények = (Lista) fullTextEntityManager .createFullTextQuery (moreLikeThisQuery, Product.class) .setProjection (ProjectionConstants.THIS, ProjectionConstants.SCORE) .getResultList ();

6.9. Több mint egy mező keresése

Eddig csak egy attribútum keresésére készítettünk lekérdezéseket a a pályán().

A felhasználási esettől függően két vagy több attribútumot is kereshetünk:

Query luceneQuery = queryBuilder .keyword () .onFields ("productName", "description") .matching (text) .createQuery ();

Ráadásul, megadhatjuk az egyes keresendő attribútumokat külön-külön, e. g. ha meg akarunk határozni egy attribútumot:

Query moreLikeThisQuery = queryBuilder .moreLikeThis () .comparingField ("productName"). BoostedTo (10f) .andField ("leírás"). BoostedTo (1f) .toEntity (entitás) .createQuery ();

6.10. A lekérdezések egyesítése

Végül a hibernált keresés támogatja a lekérdezések kombinálását különféle stratégiák segítségével:

  • KELLENE: a lekérdezésnek tartalmaznia kell az allekérdezés megfelelő elemeit
  • KELL: a lekérdezésnek tartalmaznia kell az allekérdezés megfelelő elemeit
  • TILOS: a lekérdezés nem tartalmazhatja az allekérdezés megfelelő elemeit

Az összesítések vannak hasonlóan a logikai logókhoz ÉS, VAGY és NEM. A nevek azonban különböznek annak hangsúlyozására, hogy hatással vannak a relevanciára is.

Például a KELLENE két lekérdezés között hasonló a logikai értékhez VAGY: ha a két lekérdezés egyike egyezik, akkor ezt a mérkőzést visszaküldik.

Ha azonban mindkét lekérdezés egyezik, akkor az egyezésnek nagyobb lesz a relevanciája, mint ha csak egy lekérdezés felel meg:

Lekérdezés kombináltQuery = queryBuilder .bool () .must (queryBuilder.keyword () .onField ("productName"). Matching ("apple") .createQuery ()) .must (queryBuilder.range () .onField ("memory") .from (64) .to (256) .createQuery ()) .should (queryBuilder.phrase () .onField ("leírás"). mondat ("face id") .createQuery ()) .kell (queryBuilder.keyword ( ) .onField ("productName"). matching ("samsung") .createQuery ()) .not () .createQuery ();

7. Következtetés

Ebben a cikkben megvitattuk a hibernált keresés alapjait, és bemutattuk a legfontosabb lekérdezési típusok megvalósítását. Haladóbb témák megtalálhatók a hivatalos dokumentációban.

Mint mindig, a példák teljes forráskódja elérhető a GitHubon.