Space Vatican

när du indexerar data är världen sällan så enkel som varje dokument som finns isolerat. Ibland är det bättre att denormalisera all data i barndokumenten. Om du till exempel modellerade böcker kan det vara ett förnuftigt val att lägga till ett författarfält i böcker (även om data i databasen som är din auktoritativa datakälla delas upp i separata authors och books – tabell). Det är enkelt och du kan enkelt konstruera frågor om både attribut av boken och författarens namn.

det är inte alltid praktiskt – det kan finnas för mycket data i det överordnade dokumentet för att duplicera det i varje barndokument. Om du hade din typiska blogg/kommentar-app skulle du inte vilja upprepa hela innehållet i blogginlägget i varje kommentar, eftersom det skulle öka mängden indexerade data flera. Men utan det kan du inte enkelt skriva frågor för att hitta kommentarer på inlägg som matchar vissa kriterier (annat än genom att göra ett 2-steg för att först hitta matchande inlägg och sedan hämta kommentarer med en viss post_id, vilket ofta är obehagligt eller långsamt (eller båda)).

ett annat alternativ är att placera underordnade dokument i det överordnade dokumentet, till exempel kan du ha dokument i formuläret

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

en nackdel här är att lägga till ett barn kräver återindexering av hela dokumentet. Att hitta författare som har skrivit böcker med en viss genre är lätt men att hitta författare som har haft en science fiction-bok publicerad av penguin är svårare.

om vårt index innehåller

hittar den mest uppenbara frågan

båda författarna – du kan inte uttrycka att dina villkor på published och genre måste matcha mot samma bok.

ElasticSearch ger två saker som hjälper till med detta. Den första är begreppet ett kapslat dokument / fråga. Detta gör att du kan säga att du letar efter Författare där minst en bok uppfyller båda dina kriterier.

först måste du ställa in en kartläggning som säger att böcker fältet kommer att kapslas:

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

om vi sedan sätter in samma data som tidigare i det här nya indexet, kan den här frågan

här nested – filtret låta dig köra en fråga mot de kapslade dokumenten (dvs. böckerna) och filtrera författare av de som har minst ett kapslat dokument som matchar frågan. Alternativet path berättar vilken del av författardokumentet den här frågan gäller och sedan är alternativet query en fråga att köra mot dessa kapslade dokument. Till skillnad från den tidigare frågan kräver detta att en enskild bok hittas som uppfyller båda kraven så att endast Alaistair Reynolds returneras

förälder & barn

det andra konceptet elasticsearch tillhandahåller är det för ett föräldra-och barnförhållande mellan dokument. Det föregående exemplet kan omarbetas med författare som överordnade dokument och böcker som underordnade dokument.

den här gången indexerar författarna separat från sina böcker:

konfigurera sedan mappningen för boktypen och säg att dess överordnade typ är bare_author. Du måste göra detta innan du skapar några böcker.

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

när vi indexerar böcker måste du sedan ge id för deras förälder (dvs vi levererar id för en av de tidigare skapade författarna)

Elasticsearch ger ett has_child filter som gör ganska mycket vad som står på tin: den väljer överordnade dokument med minst ett barn som uppfyller en viss fråga. Denna fråga hittar då bara Alastair Reynolds:

Solr 4.0 kommer tydligen att ha möjlighet att göra kopplingar, men så långt jag kan säga kommer det med vissa begränsningar, särskilt inga kopplingar om du drivs i en distribuerad miljö. Genom att begränsa sig till förälder/barn Typ relationer elasticsearch gör livet lättare för sig själv: ett barn är alltid indexeras i samma skärva som sin förälder, så has_child behöver inte göra besvärliga cross shard operationer.

Bygglistor

du kan också använda detta för att modellera användarspecifika listor över delade globala objekt-t.ex. om du ville ha objekt som en användare hade betygsatt. I det här fallet skulle dina underordnade dokument representera det faktum att en specifik användare hade betygsatt ett specifikt inlägg – de är inget annat än en user_id, post_id och ett betyg: en kopplingstabell i relationsdatabas jargong.

med hjälp av en förälder/barn relationer och has_child kan du enkelt hitta alla inlägg favorit av en användare samtidigt som användarna kan söka igenom sina favoriter baserat på inlägg innehåll, datum eller någon annan av ett inlägg attribut eller någon av de underordnade objekt egenskaper. Att lägga till ett objekt i listan över rankade objekt är billigt-det kräver bara indexering av ett mycket litet rating – objekt.

med dessa dokument

denna fråga

hittar bara ”bolivia rated 4” eftersom det är det enda inlägget som nämner bolivia som har fått betyg över 3 av användaren vi är intresserade av. Den översta nivåfrågan på titel gäller för inläggen, där frågan i filtret has_child beskriver villkor som barnen måste matcha (i det här fallet måste de tillhöra en specifik användare och ha minst ett visst betyg).

beställning

vad has_child låter dig inte göra är att beställa baserat på attribut för barnen eller returattribut för barnet. Om du ville beställa en användares rankade inlägg baserat på när de betygsattes eller genom att minska betyg kan du söka mot inlägg/betyg direkt men du kanske vill använda lite sökkritera på inläggen också. Till exempel kanske du bara vill hitta rankade inlägg på ett visst ämne (beställer fortfarande efter det Betyg som användaren gav). Med has_child har du tur. Kapslade dokument hjälper inte heller.

från och med 0.19.10 kan du använda filtret has_parent. Detta fungerar nästan exakt samma som har barn men låter dig ange en fråga mot de överordnade objekten istället. Denna fråga returnerar betyg av användare 1234, på inlägg vars titel matchar” bolivia”, i minskande poängordning

detta returnerar betygsobjekten – du måste sedan hämta motsvarande inlägg med en separat fråga.

Faking it

om du sitter fast på en äldre version av elasticsearch kan du få det mesta av vägen dit med top_children. Som dokumentationen säger top_children frågar först underordnade dokument och samlar dem sedan i överordnade dokument. I vårt exempel betyder det att elasticsearch först hittar betygsdokumenten som matchar vår fråga. Då kommer det att matcha varje betyg till sin överordnade post, aggregera dubbla inlägg där de finns.

den fiddly biten med toppbarn är att elasticsearch inte vet i förväg hur många dokument det kommer att förlora när aggregeringen händer. I det här fallet är det enkelt eftersom två distinkta betyg av samma användare alltid motsvarar två distinkta inlägg, så vi behöver inte bry oss Om factor och incremental_factor inställningar eftersom aggregeringsfasen aldrig gör någonting. På samma sätt spelar poängläge ingen roll heller. Om du behöver ange ett exakt antal av det totala antalet resultat behöver du bara ställa in factor tillräckligt stor för att den första sweep elasticsearch gör av barndokumenten hittar dem alla. Om du vet att användaren har 500 rankade objekt på sin lista och du ber om de första 10 objekt, då en faktor 50 bör göra susen. Faktor behöver bara vara en övre gräns – du behöver inte veta exakt hur många objekt användaren har på sin lista (vilket kan vara besvärligt att träna utan en separat elastisk sökfråga om användaren söker en viss delmängd av sina betyg).

vad du får efter allt detta är en lista över överordnade dokument (inlägg) sorterade efter frågepoängen för barndokumenten (betyg). För att uppnå det ursprungliga målet att sortera inläggen baserat på attribut för barndokumenten behöver vi bara se till att denna frågepoäng har rätt värde. Till exempel har top_children query wrap en custom_score fråga så att du har kontroll över vad poängen för varje barn är.

med samma dokument i indexet returnerar den här frågan de inlägg som användaren 1234 har betygsatt, ordnade efter deras betyg:

vi kör en top_children – fråga, så det första vi behöver göra är att säga vilken typ av barn vi överväger (betyg). Sedan ger vi frågan som hittar dessa barn. Detta är en custom_score – fråga, som omsluter en filtered – fråga. filtered – frågan säkerställer att vi bara hittar betyg som ges av användaren vi är intresserade av, och sedan gör script – elementet poängen för betygsdokumentet att betygsätta sig, så att vi får våra inlägg sorterade efter betyg. Funkinessen med backslashes är bara för att jag försöker inkludera ett bokstavligt enda citat i en skalvänlig sträng avgränsad av enstaka citat – den faktiska json som vi skickar har bara "script": "doc.value".

Ruby fun

tyvärr stöder däckbiblioteket inte riktigt något av dessa roliga saker just nu – det finns lite moratorium för att den här typen av funktion läggs till, för just nu blir varje enskild liten frågetyp och alternativ separata metoder spridda över däck, vilket utvecklaren förståeligt inte gillar. Du kan dock hacka det.

däck tillåter inte att du anger ett dokuments överordnade id vid indexering. Detta är enkelt att lägga till och hålls bara upp av ovannämnda moratorium. Min gaffel lägger till denna förmåga. Med det slutar du med

nästa olycka är att tires automatiska indexskapande förutsätter en typ per index men för att ett förälder/barnförhållande ska existera måste båda typerna vara i samma index. Jag har slutat göra något liknande för att skapa mina index.

vilket inte är lika vackert men får jobbet gjort.

Slutligen måste du faktiskt göra frågan. I avsaknad av top_children som faktiskt är en del av tires api kan du fudge det som så

den här lilla obehagligheten bygger upp frågan som en hash och skjuter sedan in den i däck medan den tittar åt andra hållet. Självklart kan du strukturera det på ett sådant sätt att det är enkelt att lägga till andra villkor (antingen på Post eller på betyg) till sökningen. Du kan också bygga upp json manuellt och använda Post.search :payload => my_json (det finns ett fel med nyttolastalternativet som kolliderar med tire-contribs loggerförlängning)

Lämna ett svar

Din e-postadress kommer inte publiceras.