En enkel merking av implementering med elastisk søk

Utholdenhetstopp

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET Denne artikkelen er en del av en serie: • En enkel taggingimplementering med elastisk søk ​​(nåværende artikkel) • En enkel taggingimplementering med JPA

• En avansert implementering av tagging med JPA

• En enkel merking av implementering med MongoDB

1. Oversikt

Merking er et vanlig designmønster som lar oss kategorisere og filtrere elementer i datamodellen.

I denne artikkelen implementerer vi merking ved hjelp av Spring og Elasticsearch. Vi bruker både Spring Data og Elasticsearch API.

Først og fremst skal vi ikke dekke det grunnleggende om å få elastisearch og vårdata - du kan utforske disse her.

2. Legge til tagger

Den enkleste implementeringen av merking er en rekke strenger. Vi kan implementere dette ved å legge til et nytt felt i datamodellen vår slik:

@Document (indexName = "blog", type = "article") public class Article {// ... @Field (type = Keyword) private String [] tags; // ...}

Legg merke til bruken av Nøkkelord felttype. Vi vil bare ha eksakte samsvar med kodene våre for å filtrere et resultat. Dette lar oss bruke lignende, men separate koder som elasticsearchIsAwesome og elasticsearchIsTrrible.

Analyserte felt vil gi delvis treff som er feil oppførsel i dette tilfellet.

3. Byggspørsmål

Merker lar oss manipulere spørsmålene våre på interessante måter. Vi kan søke på dem som alle andre felt, eller vi kan bruke dem til å filtrere resultatene våre på match_all spørsmål. Vi kan også bruke dem med andre spørsmål for å stramme resultatene.

3.1. Søker i tagger

Den nye stikkord feltet vi opprettet på vår modell er akkurat som alle andre felt i indeksen vår. Vi kan søke etter en enhet som har en spesifikk tag som dette:

@Query ("{\" bool \ ": {\" must \ ": [{\" match \ ": {\" tags \ ": \"? 0 \ "}}]}}") Side findByTagUsingDeclaredQuery (streng tag, Pageable pageable);

Dette eksemplet bruker et Spring Data Repository for å konstruere spørringen vår, men vi kan like raskt bruke en hvilemal for å spørre Elasticsearch-klyngen manuelt.

På samme måte kan vi bruke Elasticsearch API:

boolQuery (). must (termQuery ("tags", "elasticsearch"));

Anta at vi bruker følgende dokumenter i indeksen vår:

[{"id": 1, "title": "Spring Data Elasticsearch", "author": [{"name": "John Doe"}, {"name": "John Smith"}], "tags": ["elasticsearch", "spring data"]}, {"id": 2, "title": "Søkemotorer", "author": [{"name": "John Doe"}], "tags": [ "søkemotorer", "tutorial"]}, {"id": 3, "title": "Andre artikkel om Elasticsearch", "author": [{"name": "John Smith"}], "tags": ["elasticsearch", "spring data"]}, {"id": 4, "title": "Elasticsearch Tutorial", "author": [{"name": "John Doe"}], "tags": [ "elasticsearch"]},]

Nå kan vi bruke dette spørsmålet:

SideartikkelByTags = articleService.findByTagUsingDeclaredQuery ("elasticsearch", PageRequest.of (0, 10)); // articleByTags vil inneholde 3 artikler [1, 3, 4] hevder at (articleByTags, inneholderInAnyOrder (hasProperty ("id", er (1)), hasProperty ("id", er (3)), hasProperty ("id", er (4))));

3.2. Filtrering av alle dokumenter

Et vanlig designmønster er å lage en Filtrert listevisning i brukergrensesnittet som viser alle enheter, men som også lar brukeren filtrere basert på forskjellige kriterier.

La oss si at vi vil returnere alle artikler filtrert etter hvilken kode brukeren velger:

@Query ("{\" bool \ ": {\" must \ ":" + "{\" match_all \ ": {}}, \" filter \ ": {\" term \ ": {\" tags \ ": \"? 0 \ "}}}}") Side findByFilteredTagQuery (strengmerke, sideviselig sidevis);

Nok en gang bruker vi vårdata til å konstruere vårt deklarerte spørsmål.

Derfor er spørringen vi bruker delt i to deler. Poengsøket er første periode, i dette tilfellet, match_all. Filterspørringen er neste og forteller Elasticsearch hvilke resultater som skal kastes.

Slik bruker vi dette spørsmålet:

SideartikkelByTags = articleService.findByFilteredTagQuery ("elasticsearch", PageRequest.of (0, 10)); // articleByTags vil inneholde 3 artikler [1, 3, 4] hevder at (articleByTags, inneholderInAnyOrder (hasProperty ("id", er (1)), hasProperty ("id", er (3)), hasProperty ("id", er (4))));

Det er viktig å innse at selv om dette gir de samme resultatene som eksemplet vårt ovenfor, vil denne spørringen fungere bedre.

3.3. Filtreringsspørsmål

Noen ganger returnerer et søk for mange resultater til å være brukbare. I så fall er det hyggelig å avsløre en filtreringsmekanisme som kan kjøre det samme søket på nytt, bare med resultatene redusert.

Her er et eksempel der vi begrenser artiklene en forfatter har skrevet, til bare de med en bestemt tag:

@Query ("{\" bool \ ": {\" must \ ":" + "{\" match \ ": {\" author.name \ ": \"? 0 \ "}}," + "\ "filter \": {\ "term \": {\ "tags \": \ "? 1 \"}}}} ") Side findByAuthorsNameAndFilteredTagQuery (strengnavn, strengmerke, sidesidig);

Igjen gjør Spring Data alt arbeidet for oss.

La oss også se på hvordan vi kan lage dette spørsmålet selv:

QueryBuilder builder = boolQuery (). Must (nestetQuery ("forfattere", boolQuery (). Must (termQuery ("forfatter.navn", "doe")), ScoreMode.None)) .filter (termQuery ("tags", " elasticsearch "));

Vi kan selvfølgelig bruke den samme teknikken til å filtrere på et hvilket som helst annet felt i dokumentet. Men tags egner seg spesielt godt til denne brukssaken.

Slik bruker du spørringen ovenfor:

SearchQuery searchQuery = ny NativeSearchQueryBuilder (). MedQuery (builder) .build (); Listeartikler = elasticsearchTemplate.queryForList (searchQuery, Article.class); // artikler inneholder [1, 4] assertThat (articleByTags, inneholderInAnyOrder (hasProperty ("id", er (1)), hasProperty ("id", er (4))));

4. Filterkontekst

Når vi bygger et spørsmål, må vi skille mellom Query Context og Filter Context. Hvert søk i Elasticsearch har en spørrekontekst, så vi bør være vant til å se dem.

Ikke alle spørringstyper støtter Filterkontekst. Derfor, hvis vi vil filtrere på koder, må vi vite hvilke søketyper vi kan bruke.

De bool spørringen har to måter å få tilgang til filterkonteksten. Den første parameteren, filter, er den vi bruker ovenfor. Vi kan også bruke en må ikke parameter for å aktivere konteksten.

Neste spørringstype vi kan filtrere er konstant_score. Dette er nyttig når du vil erstatte spørrekonteksten med resultatene av filteret og tildele hvert resultat den samme poengsummen.

Den siste spørringstypen som vi kan filtrere basert på koder, er filteraggregering. Dette lar oss lage aggregeringsgrupper basert på resultatene av filteret vårt. Med andre ord, vi kan gruppere alle artiklene etter tag i vårt aggregeringsresultat.

5. Avansert merking

Så langt har vi bare snakket om merking ved hjelp av den mest grunnleggende implementeringen. Det neste logiske trinnet er å lage koder som er seg selv nøkkelverdipar. Dette vil tillate oss å bli enda mer avanserte med spørsmålene og filtrene våre.

For eksempel kan vi endre tagfeltet vårt til dette:

@Field (type = Nestet) private listelapper;

Så ville vi bare bytte filter for å bruke nestedQuery typer.

Når vi forstår hvordan du bruker nøkkelverdipar det er et lite skritt for å bruke komplekse objekter som vår merke. Ikke mange implementeringer trenger et fullt objekt som en tag, men det er godt å vite at vi har dette alternativet hvis vi trenger det.

6. Konklusjon

I denne artikkelen har vi dekket det grunnleggende om implementering av merking ved hjelp av Elasticsearch.

Som alltid kan eksempler bli funnet på GitHub.

Neste » En enkel tagging-implementering med JPA Persistence-bunn

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET