Space Vatican

når du indekserer data, er verden sjældent så enkel som hvert dokument, der findes isoleret. Nogle gange er det bedre at denormalisere alle data i barnedokumenterne. Hvis du for eksempel modellerede bøger, kunne det være et fornuftigt valg at tilføje et forfatterfelt til bøger (selvom dataene i databasen, der er din autoritative datakilde, er opdelt i separat authors og books tabel). Det er enkelt, og du kan nemt konstruere forespørgsler på begge attributter af bogen og forfatterens navn.

det er ikke altid praktisk – der kan være for mange data i det overordnede dokument til at duplikere det i hvert barnedokument. Hvis du havde din typiske blog / kommentar-app, ville du ikke gentage hele indholdet af blogindlægget i hver kommentar, da dette ville øge mængden af indekserede data betydeligt flere. Men uden det kan du ikke nemt skrive forespørgsler for at finde kommentarer til indlæg, der matcher bestemte kriterier (andet end ved at gøre et 2-trin i processen med først at finde matchende indlæg og derefter hente kommentarer med en bestemt post_id, som ofte er uhåndterlig eller langsom (eller begge dele)).

en anden mulighed er at placere børnedokumenter inde i forældredokumentet, for eksempel kan du have dokumenter i formularen

123456789101112
{ "name": "A. N Author", "biography": "A leading wordsmith", "books": }

en ulempe her er, at tilføjelse af et barn kræver genindeksering af hele dokumentet. Det er let at finde forfattere, der har skrevet bøger med en bestemt genre, men det er sværere at finde forfattere, der har haft en science fiction-bog udgivet af penguin.

hvis vores indeks indeholder

så finder den mest oplagte forespørgsel

begge forfattere – du kan ikke udtrykke, at dine betingelser på published og genre skal matche den samme bog.

ElasticSearch giver to ting, der hjælper med dette. Den første er begrebet et indlejret dokument / forespørgsel. Dette giver dig mulighed for at sige, at du leder efter forfattere, hvor mindst en bog opfylder begge dine kriterier.

først skal du opsætte en kortlægning, der siger, at feltet bøger vil blive indlejret:

123456789
curl -XPOST localhost:9200/authors/nested_author/_mapping -d '{ "nested_author":{ "properties":{ "books": { "type": "nested" } } }}'

hvis vi derefter indsætter de samme data som før i dette nye indeks, giver denne forespørgsel

her nested filteret dig mulighed for at køre en forespørgsel mod de indlejrede dokumenter (dvs.bøgerne) og filtrere forfattere efter dem, der har mindst et indlejret dokument, der matcher forespørgslen. Indstillingen path fortæller os, hvilken del af forfatterdokumentet denne forespørgsel gælder for, og derefter er indstillingen query en forespørgsel, der skal køres mod disse indlejrede dokumenter. I modsætning til den foregående forespørgsel kræver dette, at der findes en individuel bog, der opfylder begge krav, så kun Alaistair Reynolds returneres

forælder & barn

det andet koncept elasticsearch giver er forholdet mellem en forælder og barn mellem dokumenter. Det foregående eksempel kan omarbejdes med forfattere som overordnede dokumenter og bøger som barnedokumenter.

denne gang indekserer forfatterne separat fra deres bøger:

konfigurer derefter kortlægningen for bogtypen og sig, at dens overordnede type er bare_author. Du skal gøre dette, før du opretter bøger.

12345
curl -XPOST localhost:9200/authors/book/_mapping -d '{ "book":{ "_parent": {"type": "bare_author"} }}'

når vi indekserer bøger, skal du derefter give deres forældres id (dvs. vi leverer id ‘ et til en af de tidligere oprettede forfattere)

Elasticsearch giver et has_child filter, der stort set gør hvad der står på tin: det vælger overordnede dokumenter med mindst et barn, der opfylder en bestemt forespørgsel. Denne forespørgsel finder så kun Alastair Reynolds:

Solr 4.0 vil tilsyneladende have evnen til at gøre joinforbindelser, selvom så vidt jeg kan fortælle dette kommer med nogle begrænsninger, især ingen joinforbindelser, hvis du drives i et distribueret miljø. Ved at begrænse sig til forældre/barn type relationer elasticsearch gør livet lettere for sig selv: et barn er altid indekseret i samme shard som sin forælder, så has_child behøver ikke at gøre akavet cross shard operationer.

Bygningslister

du kan også bruge dette til at modellere brugerspecifikke lister over delte globale emner – f.eks. hvis du ønskede emner, som en bruger havde bedømt. I dette tilfælde ville dine barnedokumenter repræsentere det faktum, at en bestemt bruger havde bedømt et bestemt indlæg – de er intet andet end en user_id, post_id og en vurdering: en jointabel i relationsdatabase lingo.

ved hjælp af en forælder/barn relationer og has_child kan du nemt finde alle de indlæg begunstiget af en bruger, mens brugerne kan søge gennem deres favoritter baseret på indlæg indhold, dato eller andre af et indlæg attributter eller nogen af underordnede element Egenskaber. Det er billigt at tilføje en vare til listen over klassificerede varer – det kræver kun indeksering af en meget lille rating vare.

med disse dokumenter

denne forespørgsel

finder kun “bolivia bedømt 4”, da det er det eneste indlæg, der nævner bolivia, der er blevet bedømt over 3 af den bruger, vi er interesseret i. Forespørgslen på øverste niveau på titel gælder for indlægene, hvor forespørgslen inde i filteret has_child beskriver forhold, som børnene skal matche (i dette tilfælde skal de tilhøre en bestemt bruger og have mindst en bestemt vurdering).

bestilling

hvad has_child lader dig ikke gøre er at bestille baseret på attributter for børnene eller returnere attributter for barnet. Hvis du ønskede at bestille en brugers vurderede indlæg baseret på, hvornår de blev bedømt eller ved faldende bedømmelse, kan du søge direkte mod indlæg/vurdering, men du vil måske også anvende nogle søgekriterier på indlægene. For eksempel vil du måske kun finde klassificerede indlæg om et bestemt emne (stadig bestilling efter den vurdering, brugeren gav). Med has_child er du ude af lykke. Indlejrede dokumenter hjælper heller ikke.

fra 0.19.10 kan du bruge has_parent filteret. Dette fungerer næsten nøjagtigt det samme som har barn, men giver dig mulighed for at specificere en forespørgsel mod de overordnede elementer i stedet. Denne forespørgsel returnerer klassificeringerne efter bruger 1234 på indlæg, hvis titel matcher “bolivia”, i faldende score rækkefølge

dette returnerer klassificeringsobjekterne – du skal derefter hente de tilsvarende indlæg med en separat forespørgsel.

Faking it

hvis du sidder fast på en ældre version af elasticsearch, kan du få det meste af vejen der med top_children. Som dokumentationen siger top_children først forespørgsler barnet dokumenter og derefter aggregater dem i overordnede dokumenter. I vores eksempel betyder det, at elasticsearch først finder de vurderingsdokumenter, der matcher vores forespørgsel. Så vil det matche hver rating til sin overordnede indlæg, aggregere duplikat indlæg, hvor de findes.

den fiddly bit med top børn er, at elasticsearch ikke ved på forhånd, hvor mange dokumenter det vil miste, når aggregeringen sker. I dette særlige tilfælde er det nemt, fordi to forskellige vurderinger af den samme bruger altid svarer til to forskellige indlæg, så vi behøver ikke at genere med factor og incremental_factor indstillinger, fordi aggregeringsfasen aldrig gør noget. Tilsvarende betyder score-tilstand heller ikke noget. Hvis du har brug for at give en nøjagtig optælling af det samlede antal resultater, skal du bare indstille factor stort nok til, at den første feje elasticsearch gør af barnedokumenterne finder dem alle. Hvis du ved, at brugeren har 500 klassificerede emner på deres liste, og du beder om de første 10 emner, skal en faktor på 50 gøre tricket. Faktor behøver kun være en øvre grænse-du behøver ikke at vide præcis, hvor mange elementer brugeren har på deres liste (hvilket kan være akavet at træne uden en separat elastisk søgeforespørgsel, hvis brugeren søger en bestemt delmængde af deres vurderinger).

hvad du får efter alt dette er en liste over overordnede dokumenter (indlæg) sorteret efter forespørgselsresultatet for børnedokumenterne (ratings). For at nå det oprindelige mål om at sortere indlægene baseret på attributter af børnedokumenterne skal vi bare sikre, at denne forespørgselsscore har den rigtige værdi. For eksempel har top_children forespørgselsindpakning en custom_score forespørgsel, så du har kontrol over, hvad scoren for hvert barn er.

med de samme dokumenter i indekset returnerer denne forespørgsel de indlæg, som bruger 1234 har bedømt, sorteret efter deres vurdering:

vi kører en top_children forespørgsel, så det første, vi skal gøre, er at sige, hvad er typen af de børn, vi overvejer (rating). Så giver vi den forespørgsel, der finder disse børn. Dette er en custom_score forespørgsel, indpakning af en filtered forespørgsel. Forespørgslen filtered sikrer, at vi kun finder vurderinger givet af den bruger, vi er interesseret i, og så gør elementet script scoren af vurderingsdokumentet til at bedømme sig selv, så vi får vores indlæg sorteret efter vurdering. Funkiness med backslashes er kun fordi jeg forsøger at inkludere et bogstaveligt enkelt citat i en shell venlig streng afgrænset af enkelt Citater – den faktiske json, som vi sender, har lige "script": "doc.value".

Ruby fun

desværre understøtter dækbiblioteket ikke rigtig noget af dette sjove ting i øjeblikket – der er lidt af et moratorium for denne slags funktion, der tilføjes, fordi i øjeblikket hver eneste lille forespørgselstype og mulighed ender med at være separate metoder spredt over hele tire, som vedligeholderen forståeligt nok ikke kan lide. Du kan dog slags hacke det ind.

Tire tillader dig ikke at angive et dokuments overordnede id, når du indekserer. Dette er ligetil at tilføje og bliver kun holdt op af ovennævnte moratorium. Min gaffel tilføjer denne evne. Med det ender du med

den næste smule ulykke er, at tire ‘ s Auto-indeksoprettelse forudsætter en type pr. Jeg har endt med at gøre noget som dette for at oprette mine indekser.

hvilket ikke er helt så smukt, men får jobbet gjort.

endelig skal du faktisk gøre forespørgslen. I mangel af top_children faktisk at være en del af tire ‘ s api kan du fudge det som så

denne lille smule ubehag opbygger forespørgslen som en hash og skubber den derefter ind i tire, mens den ser den anden vej. Det er klart, at du kan strukturere det på en sådan måde, at det er let at tilføje andre betingelser (hvad enten det er på Post eller på Rating) til søgningen. Du kan også opbygge json manuelt og bruge Post.search :payload => my_json (der er en fejl med nyttelastindstillingen, der kolliderer med tire-contrib ‘ s logger-udvidelse)

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.