Elasticsearch forespørgsler med Spring Data

1. Introduktion

I en tidligere artikel demonstrerede vi, hvordan vi konfigurerer og bruger Spring Data Elasticsearch til et projekt. I denne artikel vil vi undersøge flere forespørgselstyper, der tilbydes af Elasticsearch, og vi vil også tale om feltanalysatorer og deres indvirkning på søgeresultaterne.

2. Analysatorer

Alle lagrede strengfelter behandles som standard af en analysator. En analysator består af en tokenizer og flere token-filtre og er normalt forud for et eller flere tegnfiltre.

Standardanalysatoren opdeler strengen efter almindelige ordseparatorer (såsom mellemrum eller tegnsætning) og sætter hvert token i små bogstaver. Det ignorerer også almindelige engelske ord.

Elasticsearch kan også konfigureres til at betragte et felt som analyseret og ikke-analyseret på samme tid.

For eksempel i en Artikel klasse, formoder vi gemmer titelfeltet som et standardanalyseret felt. Det samme felt med suffikset ordret vil blive gemt som et ikke-analyseret felt:

@MultiField (mainField = @Field (type = Text, fielddata = true), otherFields = {@InnerField (suffix = "verbatim, type = Keyword)}) privat streng titel;

Her anvender vi @MultiField kommentar for at fortælle Spring Data, at vi gerne vil have, at dette felt indekseres på flere måder. Hovedfeltet bruger navnet titel og analyseres i henhold til reglerne beskrevet ovenfor.

Men vi giver også en anden kommentar, @InnerField, der beskriver en yderligere indeksering af titel Mark. Vi bruger FieldType.keyword for at indikere, at vi ikke ønsker at bruge en analysator, når vi udfører den yderligere indeksering af feltet, og at denne værdi skal gemmes ved hjælp af et indlejret felt med suffikset ordret.

2.1. Analyserede felter

Lad os se på et eksempel. Antag at en artikel med titlen "Spring Data Elasticsearch" føjes til vores indeks. Standardanalysatoren bryder strengen op med mellemrumstegnene og producerer små bogstaver: “forår“, “data", og “elastiksøgning“.

Nu kan vi bruge enhver kombination af disse termer til at matche et dokument:

NativeSearchQuery searchQuery = ny NativeSearchQueryBuilder () .withQuery (matchQuery ("titel", "elasticsearch data")) .build ();

2.2. Ikke-analyserede felter

Et ikke-analyseret felt er ikke tokeniseret, så det kan kun matches som en helhed, når du bruger match- eller termforespørgsler:

NativeSearchQuery searchQuery = ny NativeSearchQueryBuilder () .withQuery (matchQuery ("title.verbatim", "Anden artikel om Elasticsearch")) .build ();

Ved hjælp af en matchforespørgsel søger vi muligvis kun efter den fulde titel, som også er skelnes mellem store og små bogstaver.

3. Match forespørgsel

EN match forespørgsel accepterer tekst, tal og datoer.

Der er tre typer "match" -forespørgsel:

  • boolsk
  • udtryk og
  • sætning_præfiks

I dette afsnit vil vi undersøge boolsk match forespørgsel.

3.1. Matcher med boolske operatører

boolsk er standardtypen for en matchforespørgsel; du kan angive, hvilken boolesk operatør du vil bruge (eller er standard):

NativeSearchQuery searchQuery = ny NativeSearchQueryBuilder () .withQuery (matchQuery ("titel", "Søgemaskiner"). Operator (Operator.AND)) .build (); SearchHits-artikler = elasticsearchTemplate () .search (searchQuery, Article.class, IndexCoordinates.of ("blog"));

Denne forespørgsel returnerer en artikel med titlen "Søgemaskiner" ved at angive to udtryk fra titlen med og operatør. Men hvad vil der ske, hvis vi søger med standard (eller) operatør, når kun et af udtrykkene stemmer overens?

NativeSearchQuery searchQuery = ny NativeSearchQueryBuilder () .withQuery (matchQuery ("title", "Engines Solutions")) .build (); SearchHits-artikler = elasticsearchTemplate () .search (searchQuery, Article.class, IndexCoordinates.of ("blog")); assertEquals (1, articles.getTotalHits ()); assertEquals ("Søgemaskiner", articles.getSearchHit (0) .getContent (). getTitle ());

Det "Søgemaskiner”Artiklen er stadig matchet, men den vil have en lavere score, fordi ikke alle vilkårene matchede.

Summen af ​​scoringerne for hvert matchende udtryk udgør den samlede score for hvert resulterende dokument.

Der kan være situationer, hvor et dokument, der indeholder et sjældent udtryk, der er indtastet i forespørgslen, vil have højere rang end et dokument, der indeholder flere almindelige udtryk.

3.2. Uklarhed

Når brugeren skriver en skrivefejl i et ord, er det stadig muligt at matche det med en søgning ved at angive en uklarhed parameter, som tillader unøjagtig matchning.

For strengfelter, uklarhed betyder redigeringsafstanden: antallet af ændringer i et tegn, der skal foretages i en streng for at gøre den den samme som en anden streng.

NativeSearchQuery searchQuery = ny NativeSearchQueryBuilder () .withQuery (matchQuery ("title", "spring date elasticsearch"). Operator (Operator.AND) .fuzziness (Fuzziness.ONE) .prefixLength (3)) .build ();

Det præfiks_længde parameter bruges til at forbedre ydeevnen. I dette tilfælde kræver vi, at de første tre tegn skal matche nøjagtigt, hvilket reducerer antallet af mulige kombinationer.

5. Sætning af sætninger

Fasesøgning er strengere, selvom du kan kontrollere det med slop parameter. Denne parameter fortæller sætningsforespørgslen, hvor langt fra hinanden vilkår er tilladt, mens de stadig betragter dokumentet som et match.

Med andre ord repræsenterer det antallet af gange, du har brug for at flytte et udtryk for at få forespørgslen og dokumentet til at matche:

NativeSearchQuery searchQuery = ny NativeSearchQueryBuilder () .withQuery (matchPhraseQuery ("title", "spring elasticsearch"). Slop (1)) .build ();

Her matcher forespørgslen dokumentet med titlen “Spring Data Elasticsearch”Fordi vi satte slop til en.

6. Multi Match-forespørgsel

Når du vil søge i flere felter, kan du bruge det QueryBuilders # multiMatchQuery () hvor du angiver alle de felter, der skal matche:

NativeSearchQuery searchQuery = ny NativeSearchQueryBuilder () .withQuery (multiMatchQuery ("tutorial") .field ("title") .field ("tags") .type (MultiMatchQueryBuilder.Type.BEST_FIELDS)) .build ();

Her søger vi på titel og tags felter til en kamp.

Bemærk, at her bruger vi "bedste felter" -scorestrategien. Det tager den maksimale score blandt felterne som en dokumentscore.

7. Aggregationer

I vores Artikel klasse har vi også defineret en tags felt, som ikke er analyseret. Vi kunne nemt oprette en tagsky ved hjælp af en sammenlægning.

Husk, at tags ikke bliver tokeniseret, fordi feltet ikke er analyseret:

TermsAggregationBuilder aggregation = AggregationBuilders.terms ("top_tags") .field ("tags"). Order (Terms.Order.count (false)); SearchSourceBuilder builder = ny SearchSourceBuilder (). Aggregering (aggregering); SearchRequest searchRequest = ny SearchRequest (). Indekser ("blog"). Typer ("artikel"). Kilde (builder); SearchResponse respons = client.search (searchRequest, RequestOptions.DEFAULT); Kortresultater = respons.getAggregations (). AsMap (); StringTerms topTags = (StringTerms) results.get ("top_tags"); Liste nøgler = topTags.getBuckets () .stream () .map (b -> b.getKeyAsString ()) .collect (toList ()); assertEquals (asList ("elasticsearch", "spring data", "search engine", "tutorial"), nøgler);

8. Resume

I denne artikel diskuterede vi forskellen mellem analyserede og ikke-analyserede felter, og hvordan denne forskel påvirker søgning.

Vi lærte også om flere typer forespørgsler leveret af Elasticsearch, såsom forespørgsel om match, forespørgsel om sætningstilpasning, søgning af fuldtekst og boolsk forespørgsel.

Elasticsearch giver mange andre typer forespørgsler, såsom geoforespørgsler, scriptforespørgsler og sammensatte forespørgsler. Du kan læse om dem i Elasticsearch-dokumentationen og udforske Spring Data Elasticsearch API for at bruge disse forespørgsler i din kode.

Du kan finde et projekt, der indeholder eksemplerne brugt i denne artikel i GitHub-arkivet.