Introduktion til dvale-søgning

1. Oversigt

I denne artikel diskuterer vi det grundlæggende i Hibernate Search, hvordan du konfigurerer det, og vi implementerer nogle enkle forespørgsler.

2. Grundlæggende om dvale-søgning

Når vi skal implementere søgning i fuldtekst, er det altid et plus at bruge værktøjer, som vi allerede er fortrolige med.

Hvis vi allerede bruger dvale og JPA til ORM, er vi kun et skridt væk fra dvale-søgning.

Hibernate Search integrerer Apache Lucene, et højtydende og udvideligt søgemaskinebibliotek med fuld tekst skrevet i Java. Dette kombinerer kraften fra Lucene med enkelheden i dvale og JPA.

Kort sagt, vi er bare nødt til at tilføje nogle yderligere kommentarer til vores domæneklasser, og værktøjet tager sig af ting som database / indeks synkronisering.

Hibernate Search giver også en Elasticsearch-integration; Men da det stadig er i en eksperimentel fase, vil vi fokusere på Lucene her.

3. Konfigurationer

3.1. Maven afhængigheder

Før vi kommer i gang, skal vi først tilføje de nødvendige afhængigheder til vores pom.xml:

 org. dvale-dvale-søg-orm 5.8.2.Final 

Af hensyn til enkelheden bruger vi H2 som vores database:

 com.h2database h2 1.4.196 

3.2. Konfigurationer

Vi skal også specificere, hvor Lucene skal gemme indekset.

Dette kan gøres via ejendommen hibernate.search.default.directory_provider.

Vi vælger filsystem, som er den mest enkle mulighed for vores brugssag. Flere muligheder er angivet i den officielle dokumentation. Filsystem-master/filsystem-slave og infinispan er bemærkelsesværdige for klyngede applikationer, hvor indekset skal synkroniseres mellem noder.

Vi skal også definere en standardbasekatalog, hvor indekser gemmes:

hibernate.search.default.directory_provider = filsystem hibernate.search.default.indexBase = / data / index / default

4. Modelklasser

Efter konfigurationen er vi nu klar til at specificere vores model.

Oven på JPA-kommentarerne @Enhed og @Bord, vi er nødt til at tilføje en @Indekseret kommentar. Det fortæller dvale-søgning, at enheden Produkt skal indekseres.

Derefter skal vi definere de krævede attributter som søgbare ved at tilføje en @Mark kommentar:

@Entity @Indexed @Table (name = "product") offentlig klasse Produkt {@Id privat int id; @Field (termVector = TermVector.YES) privat streng produktnavn; @Field (termVector = TermVector.YES) privat strengbeskrivelse; @Field privat int hukommelse; // getters, setters og constructors}

Det termVector = TermVector.JA attribut kræves til forespørgslen "Mere som dette" senere.

5. Opbygning af Lucene-indekset

Før du starter de faktiske forespørgsler, vi er nødt til at udløse Lucene til at oprette indekset i starten:

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

Efter denne indledende build sørger Dvaletilstand for at holde indekset opdateret. I. e. vi kan oprette, manipulere og slette enheder via EntityManager som sædvanligt.

Bemærk: vi er nødt til at sikre, at enheder er fuldt ud forpligtet til databasen, før de kan opdages og indekseres af Lucene (forresten, dette er også grunden til, at den indledende import af importdata i vores eksempler på kodetest tilfælde kommer i en dedikeret JUnit test sag, kommenteret @Begå).

6. Opbygning og udførelse af forespørgsler

Nu er vi klar til at oprette vores første forespørgsel.

I det følgende afsnit, vi viser den generelle arbejdsgang til forberedelse og udførelse af en forespørgsel.

Derefter opretter vi nogle eksempler på forespørgsler til de vigtigste forespørgselstyper.

6.1. Generel arbejdsgang til oprettelse og udførelse af en forespørgsel

Forberedelse og udførelse af en forespørgsel generelt består af fire trin:

I trin 1 skal vi få en JPA FullTextEntityManager og ud fra det a QueryBuilder:

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

I trin 2 opretter vi en Lucene-forespørgsel via DSL-forespørgslen:

org.apache.lucene.search.Query forespørgsel = queryBuilder. nøgleord () .onField ("productName") .matching ("iphone") .createQuery ();

I trin 3 pakker vi Lucene-forespørgslen ind i en dvale-forespørgsel:

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

Endelig udfører vi i trin 4 forespørgslen:

Listeresultater = jpaQuery.getResultList ();

Bemærk: Lucene sorterer som standard resultaterne efter relevans.

Trin 1, 3 og 4 er de samme for alle forespørgselstyper.

I det følgende vil vi fokusere på trin 2, i. e. hvordan man opretter forskellige typer forespørgsler.

6.2. Søgeordsforespørgsler

Den mest basale brugssag er søger efter et bestemt ord.

Dette gjorde vi faktisk allerede i det foregående afsnit:

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

Her, nøgleord () angiver, at vi leder efter et bestemt ord, onField () fortæller Lucene hvor man skal kigge og matchende () hvad man skal se efter.

6.3. Fuzzy Forespørgsler

Fuzzy-forespørgsler fungerer som søgeordsforespørgsler, bortset fra det vi kan definere en grænse for "uklarhed", over hvilken Lucene accepterer de to vilkår som matchende.

Ved withEditDistanceUpTo (), vi kan definere, hvor meget et udtryk kan afvige fra det andet. Det kan indstilles til 0, 1 og 2, hvorved standardværdien er 2 (Bemærk: denne begrænsning kommer fra Lucenens implementering).

Ved withPrefixLength (), kan vi definere længden af ​​præfikset, som skal ignoreres af uklarheden:

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

6.4. Forespørgsler med jokertegn

Dvaletilstandssøgning giver os også mulighed for at udføre jokertegnsforespørgsler, dvs. e. forespørgsler, hvor en del af et ord er ukendt.

Til dette kan vi bruge “?” for en enkelt karakter, og “*” for enhver tegnrækkefølge:

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

6.5. Sætningsforespørgsler

Hvis vi vil søge efter mere end et ord, kan vi bruge sætningsforespørgsler. Vi kan enten se for nøjagtige eller omtrentlige sætninger, ved brug af udtryk() og withSlop (), Hvis det er nødvendigt. Slopfaktoren definerer antallet af andre ord, der er tilladt i sætningen:

Query phraseQuery = queryBuilder .phrase () .withSlop (1) .onField ("beskrivelse"). Fravær ("med trådløs opladning") .createQuery ();

6.6. Enkle forespørgsler om strengforespørgsler

Med de tidligere forespørgselstyper var vi nødt til at angive forespørgselstypen eksplicit.

Hvis vi vil give brugeren mere strøm, kan vi bruge enkle forespørgselsstrengforespørgsler: ved det kan han definere sine egne forespørgsler ved kørsel.

Følgende forespørgselstyper understøttes:

  • boolsk (OG ved hjælp af "+" ELLER ved brug af "|", IKKE ved brug af "-")
  • præfiks (præfiks *)
  • sætning ("nogle sætninger")
  • forrang (ved hjælp af parenteser)
  • fuzzy (fuzy ~ 2)
  • nær operatør for sætningsforespørgsler (“nogle sætninger” ~ 3)

Følgende eksempel vil kombinere fuzzy, sætning og boolske forespørgsler:

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

6.7. Område forespørgsler

Område forespørgsler søge efter enværdi mellem givne grænser. Dette kan anvendes på tal, datoer, tidsstempler og strenge:

Query rangeQuery = queryBuilder .range () .onField ("memory") .fra (64) .to (256) .createQuery ();

6.8. Mere som denne forespørgsel

Vores sidste forespørgselstype er “Mere som dette”- forespørgsel. Til dette leverer vi en enhed, og Dvalesøgning returnerer en liste med lignende enheder, hver med en lighedsscore.

Som nævnt før, termVector = TermVector.JA attribut i vores modelklasse er påkrævet i denne sag: det fortæller Lucene at gemme frekvensen for hver periode under indeksering.

Baseret på dette beregnes ligheden ved forespørgselens udførelsestidspunkt:

Forespørgsel moreLikeThisQuery = queryBuilder .moreLikeThis () .comparingField ("productName"). BoostedTo (10f) .andField ("beskrivelse"). BoostedTo (1f) .toEntity (enhed) .createQuery (); Listeresultater = (Liste) fullTextEntityManager .createFullTextQuery (moreLikeThisQuery, Product.class) .setProjection (ProjectionConstants.THIS, ProjectionConstants.SCORE) .getResultList ();

6.9. Søger mere end et felt

Indtil nu oprettede vi kun forespørgsler til søgning efter en attribut ved hjælp af onField ().

Afhængigt af brugen vi kan også søge i to eller flere attributter:

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

I øvrigt, Vi kan specificere hver attribut, der skal søges separat, e. g. hvis vi vil definere et boost for en attribut:

Forespørgsel moreLikeThisQuery = queryBuilder .moreLikeThis () .comparingField ("productName"). BoostedTo (10f) .andField ("beskrivelse"). BoostedTo (1f) .toEntity (enhed) .createQuery ();

6.10. Kombination af forespørgsler

Endelig understøtter Hibernate Search også kombination af forespørgsler ved hjælp af forskellige strategier:

  • SKULLE GERNE: forespørgslen skal indeholde de matchende elementer i underforespørgslen
  • SKAL: forespørgslen skal indeholde de matchende elementer i underforespørgslen
  • MÅ IKKE: forespørgslen må ikke indeholde de matchende elementer i underforespørgslen

Aggregeringerne er svarende til de boolske OG, ELLER og IKKE. Navnene er dog forskellige for at understrege, at de også har indflydelse på relevansen.

F.eks SKULLE GERNE mellem to forespørgsler svarer til boolsk ELLER: hvis en af ​​de to forespørgsler har et match, returneres dette match.

Hvis begge forespørgsler matcher, vil matchet dog have en højere relevans sammenlignet med, hvis kun en forespørgsel matcher:

Query combinedQuery = queryBuilder .bool () .must (queryBuilder.keyword () .onField ("productName"). Matching ("apple") .createQuery ()) .must (queryBuilder.range () .onField ("memory") .fra (64) .to (256) .createQuery ()) .should (queryBuilder.phrase () .onField ("description"). sætning ("face id") .createQuery ()) .must (queryBuilder.keyword ( ) .onField ("productName"). matching ("samsung") .createQuery ()) .not () .createQuery ();

7. Konklusion

I denne artikel diskuterede vi det grundlæggende i Hibernate Search og viste, hvordan man implementerer de vigtigste forespørgselstyper. Mere avancerede emner kan findes i den officielle dokumentation.

Som altid er den fulde kildekode for eksemplerne tilgængelig på GitHub.


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