Space Vatican

wanneer u gegevens indexeert, is de wereld zelden zo eenvoudig als elk document dat afzonderlijk bestaat. Soms kunt u beter alle gegevens in de dochterdocumenten denormaliseren. Als u bijvoorbeeld boeken modelleert, zou het toevoegen van een auteurveld aan boeken een verstandige keuze kunnen zijn (zelfs als in de database die uw gezaghebbende datasource is, de gegevens worden opgesplitst in afzonderlijke authors en books tabel). Het is eenvoudig en u kunt eenvoudig queries op beide attributen van het boek en de naam van de auteur te construeren.

dat is niet altijd praktisch – er kunnen te veel gegevens in het ouderdocument staan om het in elk dochterdocument te dupliceren. Als u uw typische blog/commentaar app had dan zou je niet wilt dat de volledige inhoud van de blogpost in elke reactie te herhalen, omdat dit de hoeveelheid geïndexeerde gegevens veel zou verhogen. Maar zonder dat kun je niet gemakkelijk query ‘ s schrijven om commentaar te vinden op berichten die aan bepaalde criteria voldoen (anders dan door een proces van 2 stappen te doen waarbij eerst overeenkomende berichten worden gevonden en vervolgens commentaren worden opgehaald met een bepaalde post_id, wat vaak log of traag is (of beide)).

een andere optie is om dochterdocumenten in het ouderdocument te plaatsen, u kunt bijvoorbeeld documenten van het formulier hebben

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

een nadeel is dat het toevoegen van een kind het hele document opnieuw moet uitpakken. Het vinden van auteurs die boeken hebben geschreven met een bepaald genre is eenvoudig, maar het vinden van auteurs die een science fiction boek hebben gepubliceerd door penguin is moeilijker.

als onze index

bevat dan vindt de meest voor de hand liggende query

beide auteurs – u kunt niet uitdrukken dat uw voorwaarden op published en genre moeten overeenkomen met hetzelfde boek.

ElasticSearch biedt twee dingen die hierbij helpen. De eerste is het concept van een geneste document/query. Hiermee kunt u zeggen dat u op zoek bent naar auteurs waar ten minste één boek voldoet aan beide criteria.

Eerst moet je de setup van een mapping die zegt dat de boeken gebied gaat worden genest:

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

Als we vervolgens plaatst u dezelfde gegevens als in deze nieuwe index dan deze query

Hier nested filter kunt u een query uitvoeren op de geneste documenten (dat wil zeggen de boeken) en filter auteurs door degenen die ten minste één geneste document overeenkomen met de zoekopdracht. De optie path vertelt ons op welk deel van het document van de Auteur deze query van toepassing is en dan is de optie query een query om met deze geneste documenten te draaien. In tegenstelling tot de vorige vraag vereist dit dat een individueel boek wordt gevonden dat aan beide vereisten voldoet, zodat alleen Alaistair Reynolds wordt teruggegeven

ouder & kind

het andere concept dat elasticsearch biedt is dat van een ouder en kind relatie tussen documenten. Het vorige voorbeeld kan worden herwerkt met auteurs als ouderdocumenten en boeken als kinddocumenten.

indexeer deze keer de auteurs apart van hun boeken:

configureer vervolgens de toewijzing voor het boektype en zeg dat het bovenliggende type bare_authoris. Je moet dit doen voordat je boeken maakt.

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

wanneer we boeken indexeren, moet je dan de id van hun ouder geven (dat wil zeggen we leveren de id van een van de eerder gemaakte auteurs)

Elasticsearch biedt een has_child filter dat doet vrijwel wat er staat op het tin: het selecteert ouderdocumenten met ten minste één kind dat aan een bepaalde query voldoet. Deze query vindt dan alleen Alastair Reynolds:

Solr 4.0 zal blijkbaar de mogelijkheid hebben om joins te doen, hoewel voor zover ik kan vertellen dit met enkele beperkingen komt, in het bijzonder geen joins als u in een gedistribueerde omgeving wordt bediend. Door zich te beperken tot ouder/kind type relaties maakt elasticsearch het leven makkelijker voor zichzelf: een kind wordt altijd geïndexeerd in dezelfde scherf als zijn ouder, dus has_child hoeft geen lastige cross shard operaties uit te voeren.

lijsten bouwen

u kunt dit ook gebruiken om gebruikersspecifieke lijsten van gedeelde globale items te modelleren-bijvoorbeeld als u items wilde die een gebruiker had beoordeeld. In dit geval zouden uw dochterdocumenten het feit vertegenwoordigen dat een specifieke gebruiker een specifieke post had beoordeeld – ze zijn niets meer dan een user_id, post_id en een rating: een join tabel in relationele database lingo.

met behulp van een ouder/dochter relatie en has_child kunt u eenvoudig alle berichten vinden die door een gebruiker zijn favorieten zijn toegevoegd, terwijl gebruikers hun favorieten kunnen doorzoeken op basis van inhoud, datum of andere attributen van een bericht of een van de eigenschappen van het onderliggende item. Het toevoegen van een item aan de lijst met beoordeelde items is goedkoop – het vereist alleen het indexeren van een zeer klein rating item.

met deze documenten

deze zoekopdracht

vindt alleen “bolivia rating 4” aangezien dat het enige bericht is waarin bolivia wordt vermeld dat meer dan 3 is beoordeeld door de gebruiker waarin we geïnteresseerd zijn. De top level query op titel is van toepassing op de berichten, waarbij de query in het has_child filter de Voorwaarden beschrijft waaraan de kinderen moeten voldoen (in dit geval moeten ze tot een specifieke gebruiker behoren en minstens een bepaalde waardering hebben).

volgorde

wat has_child u niet toestaat is volgorde op basis van attributen van de kinderen of retourneren van attributen van het kind. Als je wilde om een gebruiker beoordeelde berichten op basis van wanneer ze werden beoordeeld of door het verlagen van de rating dan kunt u zoeken tegen berichten/rating direct, maar je zou willen een aantal zoekcriteria toe te passen op de berichten te. Je wilt bijvoorbeeld alleen beoordeelde berichten over een bepaald onderwerp vinden (nog steeds op basis van de waardering die de gebruiker heeft gegeven). Met has_child heb je pech. Geneste documenten helpen ook niet.

vanaf 0.19.10 kunt u het filter has_parent gebruiken. Dit werkt bijna precies hetzelfde als child, maar stelt u in staat om een query op te geven tegen de bovenliggende items in plaats daarvan. Deze query geeft de ratings van gebruiker 1234, op berichten waarvan de titel overeenkomt met” bolivia”, in afnemende score volgorde

dit geeft de rating objecten – Je zou dan moeten halen de overeenkomstige berichten met een aparte query.

faken

als u vastzit op een oudere versie van elasticsearch, kunt u het grootste deel van de weg daar vinden met top_children. Zoals in de documentatie staat, vraagt top_children eerst de dochterdocumenten en aggregeert ze vervolgens in ouderdocumenten. In ons voorbeeld betekent dit dat elasticsearch eerst de beoordelingsdocumenten zal vinden die overeenkomen met onze zoekopdracht. Dan zal het overeenkomen met elke rating om zijn ouder post, aggregating duplicate post waar ze bestaan.

het lastige aan top kinderen is dat elasticsearch niet van tevoren weet hoeveel documenten het zal verliezen als de aggregatie plaatsvindt. In dit specifieke geval is het eenvoudig omdat twee verschillende waarderingen door dezelfde gebruiker altijd overeenkomen met twee verschillende berichten, dus we hoeven ons niet bezig te houden met factor en incremental_factor instellingen omdat de aggregatiefase nooit iets doet. Evenzo, score mode maakt ook niet uit. Als u een nauwkeurige telling van het totale aantal resultaten moet opgeven, hoeft u alleen maar factor groot genoeg in te stellen dat de eerste sweep elasticsearch doet van de dochterdocumenten ze allemaal vindt. Als u weet dat de gebruiker 500 beoordeelde items op hun lijst en je vraagt om de eerste 10 items, dan is een factor 50 moet de truc doen. Factor hoeft alleen een bovengrens – je hoeft niet te weten precies hoeveel items de gebruiker heeft op hun lijst (die onhandig zou kunnen zijn om uit te werken zonder een aparte elastische zoekopdracht als de gebruiker op zoek is naar een specifieke subset van hun ratings).

wat je uiteindelijk krijgt dit is een lijst van ouderdocumenten (berichten) gesorteerd op de query score van de children documenten (ratings). Om het oorspronkelijke doel van het sorteren van de berichten op basis van attributen van de children-documenten te bereiken, moeten we er alleen voor zorgen dat deze query score de juiste waarde heeft. Laat bijvoorbeeld top_children query een custom_score query omwikkelen, zodat u controle hebt over wat de score voor elk kind is.

met dezelfde documenten in de index, geeft deze query de berichten terug die gebruiker 1234 heeft beoordeeld, gesorteerd op hun waardering:

we draaien een top_children query, dus het eerste wat we moeten doen is zeggen wat het type is van de kinderen die we overwegen (rating). Dan geven we de zoekopdracht die die kinderen vindt. Dit is een custom_score query, waarmee een filtered query wordt afgesloten. De filtered query zorgt ervoor dat we alleen waarderingen vinden die zijn gegeven door de gebruiker waarin we geïnteresseerd zijn, en dan zorgt het script element ervoor dat de score van het ratingdocument zichzelf beoordeelt, zodat we onze berichten gesorteerd krijgen op waardering. De funkiness met de backslashes is alleen omdat ik probeer een letterlijke enkele aanhalingsteken in een shell – vriendelijke string op te nemen, gescheiden door enkele aanhalingsteken-de werkelijke json die we sturen heeft slechts "script": "doc.value".

Ruby fun

helaas ondersteunt de bandenbibliotheek op dit moment geen van deze leuke dingen – er is een beetje een moratorium op dit soort functie toegevoegd omdat op dit moment elk klein query type en optie eindigt als aparte methoden verspreid over de hele band, wat de onderhouder begrijpelijkerwijs niet leuk vindt. Je kunt het wel hacken.

band staat niet toe om de ouder-id van een document in te stellen bij het indexeren. Dit is eenvoudig toe te voegen en wordt alleen maar opgehouden door het eerder genoemde moratorium. Mijn vork voegt dit vermogen toe. Met dat je eindigt met

het volgende beetje ongeluk is dat de auto-index creatie van de band veronderstelt één type per index, maar voor een ouder/kind relatie te bestaan beide types MOETEN in dezelfde index. Ik heb uiteindelijk iets als dit te doen om mijn indexen te maken.

wat niet zo mooi is, maar de klus klaart.

ten slotte moet u de query daadwerkelijk uitvoeren. Omdat top_children geen deel uitmaakt van de API van tire, kun je het zo fudge

dit kleine beetje onplezierigheid bouwt de query op als een hash en duwt het vervolgens in tire terwijl het de andere kant opkijkt. Uiteraard kunt u het zo structureren dat het gemakkelijk is om andere voorwaarden (of op Post of op Rating) toe te voegen aan de zoekopdracht. U kunt de json ook handmatig opbouwen en Post.search :payload => my_json gebruiken (Er is een bug met de payload optie die botst met de logger extensie van tire-contrib)

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.