Uvod u Hibernate Search

1. Pregled

U ovom ćemo članku razgovarati o osnovama Hibernate pretraživanja, načinu konfiguriranja i implementirat ćemo nekoliko jednostavnih upita.

2. Osnove pretraživanja hibernacije

Kad god moramo implementirati funkcionalnost pretraživanja cijelog teksta, korištenje alata s kojima smo već dobro upućeni uvijek je plus.

U slučaju da već koristimo Hibernate i JPA za ORM, samo smo korak do Hibernate Search.

Hibernate Search integrira Apache Lucene, visokokvalitetnu i proširivu biblioteku tražilica s punim tekstom napisanu na Javi. Ovo kombinira snagu lucena s jednostavnošću hibernacije i JPA.

Jednostavno rečeno, samo moramo dodati neke dodatne napomene u svoje klase domene i alat će se pobrinuti za stvari poput sinkronizacije baze podataka / indeksa.

Hibernate Search također pruža integraciju Elasticsearch; međutim, kako je to još uvijek u eksperimentalnoj fazi, ovdje ćemo se usredotočiti na Lucene.

3. Konfiguracije

3.1. Ovisnosti Mavena

Prije nego što započnemo, prvo moramo dodati potrebne ovisnosti u našu pom.xml:

 org.hibernate hibernate-search-orm 5.8.2.Završni 

Radi jednostavnosti koristit ćemo H2 kao našu bazu podataka:

 com.h2data baza podataka h2 1.4.196 

3.2. Konfiguracije

Također moramo odrediti gdje Lucene treba pohraniti indeks.

To se može učiniti putem posjeda hibernate.search.default.directory_provider.

Mi ćemo izabrati sustav datoteka, što je najjednostavnija opcija za naš slučaj korištenja. Više mogućnosti navedeno je u službenoj dokumentaciji. Datotečni sustav-master/datotečni sustav-slave i infinispan značajni su za klasterirane aplikacije, gdje se indeks mora sinkronizirati između čvorova.

Također moramo definirati zadani osnovni direktorij u kojem će se pohraniti indeksi:

hibernate.search.default.directory_provider = datotečni sustav hibernate.search.default.indexBase = / data / index / default

4. Model klase

Nakon konfiguracije, sada smo spremni odrediti svoj model.

Povrh napomena JPA @ Entitet i @Stol, moramo dodati znak @Indeksirano bilješka. Hibernate Search-u govori da entitet Proizvod će se indeksirati.

Nakon toga, potrebne atribute moramo definirati kao pretražive dodavanjem a @Polje bilješka:

@Entity @Indexed @Table (name = "product") proizvod javne klase {@Id private int id; @ Polje (termVector = TermVector.YES) privatni niz productName; @ Polje (termVector = TermVector.YES) opis privatnog niza; @Field private int memorija; // getteri, postavljači i konstruktori}

The termVector = TermVector.DA atribut će kasnije biti potreban za upit "Još poput ovog".

5. Izgradnja indeksa lucena

Prije početka stvarnih upita, moramo pokrenuti Lucene da u početku gradi indeks:

FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager (entityManager); fullTextEntityManager.createIndexer (). startAndWait ();

Nakon ove početne izrade, Hibernate Search će se pobrinuti za održavanje ažurnog indeksa. I. e. možemo stvarati, manipulirati i brisati entitete putem EntityManager kao i obično.

Bilješka: moramo biti sigurni da su entiteti u potpunosti predani bazi podataka prije nego što ih Lucene može otkriti i indeksirati (usput rečeno, to je i razlog zašto početni uvoz podataka o testiranju u našim primjerima testnih slučajeva koda dolazi u namjenskom JUnit test slučaju, označenom s @Počiniti).

6. Izrada i izvršavanje upita

Sada smo spremni za stvaranje našeg prvog upita.

U sljedećem odjeljku, pokazat ćemo opći tijek rada za pripremu i izvršavanje upita.

Nakon toga stvorit ćemo nekoliko primjera upita za najvažnije vrste upita.

6.1. Općeniti tijek rada za stvaranje i izvršavanje upita

Priprema i izvršavanje upita općenito sastoji se od četiri koraka:

U koraku 1 moramo dobiti JPA FullTextEntityManager a iz toga a QueryBuilder:

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

U koraku 2 izradit ćemo Lucene upit putem hibernacijskog upita DSL:

org.apache.lucene.search.Query query = queryBuilder .keyword () .onField ("productName") .matching ("iphone") .createQuery ();

U koraku 3 umotat ćemo upit Lucene u hibernacijski upit:

org.hibernate.search.jpa.FullTextQuery jpaQuery = fullTextEntityManager.createFullTextQuery (upit, Product.class);

Napokon, u koraku 4 izvršit ćemo upit:

Rezultati popisa = jpaQuery.getResultList ();

Bilješka: prema zadanim postavkama, Lucene sortira rezultate prema važnosti.

Koraci 1, 3 i 4 jednaki su za sve vrste upita.

U nastavku ćemo se usredotočiti na korak 2, tj. e. kako stvoriti različite vrste upita.

6.2. Upiti za ključne riječi

Najosnovniji slučaj upotrebe je traženje određene riječi.

To smo zapravo već učinili u prethodnom odjeljku:

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

Ovdje, ključna riječ () određuje da tražimo jednu određenu riječ, onField () govori Lucene gdje treba pogledati i podudaranje () što tražiti.

6.3. Nejasni upiti

Neizraziti upiti rade poput upita za ključne riječi, osim toga možemo definirati granicu "mutnoće", iznad kojeg će Lucene prihvatiti dva pojma kao podudarna.

Po withEditDistanceUpTo (), možemo definirati koliko pojam može odstupati od drugog. Može se postaviti na 0, 1 i 2, pri čemu je zadana vrijednost 2 (Bilješka: ovo ograničenje dolazi iz primjene lucena).

Po withPrefixLength (), možemo definirati duljinu prefiksa koju će nejasnoće ignorirati:

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

6.4. Upiti sa zamjenskim znakovima

Hibernate Search također nam omogućuje izvršavanje zamjenskih upita, tj. e. upiti za koje je dio riječi nepoznat.

Za to možemo koristiti “?” za jedan lik i "*” za bilo koji slijed znakova:

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

6.5. Upiti za fraze

Ako želimo pretraživati ​​više riječi, možemo upotrijebiti upite za izraze. Možemo ili pogledati za točne ili približne rečenice, koristeći fraza () i withSlop (), ako je potrebno. Faktor slop definira broj ostalih riječi dopuštenih u rečenici:

Upit phraseQuery = queryBuilder .phrase () .withSlop (1) .onField ("opis") .sentence ("s bežičnim punjenjem") .createQuery ();

6.6. Jednostavni upitni nizovi upita

S prethodnim vrstama upita morali smo eksplicitno navesti vrstu upita.

Ako želimo dati malo više snage korisniku, možemo koristiti jednostavne upite upita upita: po tome on može definirati vlastite upite tijekom izvođenja.

Podržane su sljedeće vrste upita:

  • boolean (I koristeći "+", ILI koristeći "|", NE upotrebljavajući "-")
  • prefiks (prefiks *)
  • fraza ("neka fraza")
  • prednost (pomoću zagrada)
  • nejasno (nejasno ~ 2)
  • operator u blizini za upite fraze (“neki izraz” ~ 3)

Sljedeći primjer kombinirao bi nejasne, fraze i logičke upite:

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

6.7. Upiti o rasponu

Upiti za raspon traže avrijednost između zadanih granica. To se može primijeniti na brojeve, datume, vremenske oznake i nizove:

Upit rangeQuery = queryBuilder .range () .onField ("memory") .from (64) .to (256) .createQuery ();

6.8. Još Ovakvi Upiti

Naša posljednja vrsta upita je „Ovako više”- upit. Za to pružamo entitet i Hibernate Search vraća popis sa sličnim entitetima, svaki s ocjenom sličnosti.

Kao što je već spomenuto, termVector = TermVector.DA atribut u našoj klasi modela potreban je za ovaj slučaj: on govori Luceneu da pohrani frekvenciju za svaki pojam tijekom indeksiranja.

Na temelju toga, sličnost će se izračunati za vrijeme izvršavanja upita:

Upit moreLikeThisQuery = queryBuilder .moreLikeThis () .comparingField ("productName"). BoostedTo (10f) .andField ("description"). BoostedTo (1f) .toEntity (entity) .createQuery (); Rezultati popisa = (Popis) fullTextEntityManager .createFullTextQuery (moreLikeThisQuery, Product.class) .setProjection (ProjectionConstants.THIS, ProjectionConstants.SCORE) .getResultList ();

6.9. Traženje više polja

Do sada smo stvarali samo upite za pretraživanje jednog atributa, koristeći onField ().

Ovisno o slučaju upotrebe, možemo pretraživati ​​i dva ili više atributa:

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

Štoviše, možemo zasebno odrediti svaki atribut koji se traži, npr. g. ako želimo definirati pojačanje za jedan atribut:

Upit moreLikeThisQuery = queryBuilder .moreLikeThis () .comparingField ("productName"). BoostedTo (10f) .andField ("description"). BoostedTo (1f) .toEntity (entity) .createQuery ();

6.10. Kombiniranje upita

Napokon, Hibernate Search također podržava kombiniranje upita pomoću različitih strategija:

  • TREBA: upit treba sadržavati odgovarajuće elemente potupita
  • MORA: upit mora sadržavati odgovarajuće elemente potupita
  • NE SMIJE: upit ne smije sadržavati odgovarajuće elemente potupita

Zbirke su slično onim logičkim I, ILI i NE. Međutim, nazivi su različiti kako bi se naglasilo da oni također imaju utjecaja na relevantnost.

Na primjer, a TREBA između dva upita slična je logičkoj ILI: ako se jedan od dva upita podudara, vratit će se.

Međutim, ako se podudaraju oba upita, podudaranje će imati veću važnost u odnosu na to ako se podudara samo jedan upit:

Upit kombinacijiQuery = queryBuilder .bool () .must (queryBuilder.keyword () .onField ("productName"). Matching ("apple") .createQuery ()) .must (queryBuilder.range () .onField ("memory") .od (64) .to (256) .createQuery ()) .should (queryBuilder.phrase () .onField ("description"). rečenica ("face id") .createQuery ()) .must (queryBuilder.keyword ( ) .onField ("productName"). matching ("samsung") .createQuery ()) .not () .createQuery ();

7. Zaključak

U ovom smo članku razgovarali o osnovama pretraživanja hibernacije i pokazali kako implementirati najvažnije vrste upita. Naprednije teme možete pronaći u službenoj dokumentaciji.

Kao i uvijek, puni izvorni kod primjera dostupan je na GitHub-u.


$config[zx-auto] not found$config[zx-overlay] not found