Space Vatican

Quando indicizzi i dati, il mondo è raramente semplice come ogni documento esistente in isolamento. A volte, è meglio denormalizzare tutti i dati nei documenti figlio. Ad esempio, se si stavano modellando libri, aggiungere un campo autore ai libri potrebbe essere una scelta sensata (anche se nel database che è l’origine dati autorevole i dati sono suddivisi in tabelle separate authors e books). È semplice e puoi facilmente costruire query su entrambi gli attributi del libro e sul nome dell’autore.

Non è sempre pratico: potrebbero esserci troppi dati nel documento padre per duplicarli in ogni documento figlio. Se tu avessi la tua tipica app blog / commento, non vorresti ripetere l’intero contenuto del post del blog in ogni commento in quanto ciò aumenterebbe notevolmente la quantità di dati indicizzati diversi. Eppure senza di ciò non è possibile scrivere facilmente query per trovare commenti su post che corrispondono a determinati criteri (oltre a fare una fase 2 del processo di prima ricerca di post corrispondenti e quindi recuperare commenti con un certo post_id, che è spesso ingombrante o lento (o entrambi)).

un’Altra opzione è quella di posizionare il bambino di documenti all’interno del documento principale, per esempio i documenti possono essere di forma

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

Uno svantaggio è che l’aggiunta di un bambino richiede reindexing l’intero documento. Trovare autori che hanno scritto libri con un certo genere è facile, ma trovare autori che hanno avuto un libro di fantascienza pubblicato da penguin è più difficile.

Se il nostro indice contiene

allora la query più ovvia

trova entrambi gli autori – non puoi esprimere che le tue condizioni su published e genre devono corrispondere allo stesso libro.

ElasticSearch fornisce due cose che aiutano in questo. Il primo è il concetto di un documento/query nidificato. Questo ti permette di dire che stai cercando autori in cui almeno un libro soddisfi entrambi i tuoi criteri.

in Primo luogo è necessario per l’installazione di una mappatura che dice che i libri di campo sta per essere nidificati:

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

Se poi inserire gli stessi dati come prima in questo nuovo indice quindi questa query

Qui nested filtro consente di eseguire una query nidificata documenti (vale a dire i libri) e filtro autori da parte di coloro che hanno almeno uno annidato documento che soddisfa la query. L’opzione path indica a quale parte del documento degli autori si applica questa query e quindi l’opzione query è una query da eseguire su questi documenti nidificati. A differenza della query precedente, ciò richiede che venga trovato un singolo libro che soddisfi entrambi i requisiti, quindi viene restituito solo Alaistair Reynolds

Parent & child

L’altro concetto fornito da elasticsearch è quello di una relazione padre-figlio tra i documenti. L’esempio precedente può essere rielaborato con gli autori come documenti padre e libri come documenti figlio.

Questa volta, indicizza gli autori separatamente dai loro libri:

Quindi configura la mappatura per il tipo di libro e dì che il suo tipo genitore è bare_author. Devi farlo prima di creare qualsiasi libro.

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

Quando abbiamo l’indicizzazione dei libri, si deve poi dare l’id del loro padre (cioè noi fornire l’id di uno precedentemente creato autori)

Elasticsearch fornisce un has_child filtro che fa praticamente quello che si dice sulla latta: seleziona i documenti padre con almeno un figlio che soddisfa una determinata query. Questa query trova quindi solo Alastair Reynolds:

Solr 4.0 avrà apparentemente la capacità di fare join, anche se per quanto posso dire questo viene fornito con alcune restrizioni, in particolare nessun join se si è gestiti in un ambiente distribuito. Limitandosi alle relazioni di tipo genitore / figlio elasticsearch rende la vita più facile per se stessa: un bambino è sempre indicizzato nello stesso shard del suo genitore, quindi has_child non deve eseguire operazioni di cross shard imbarazzanti.

Creazione di elenchi

È inoltre possibile utilizzarlo per modellare elenchi specifici dell’utente di elementi globali condivisi, ad esempio se si desidera elementi valutati da un utente. In questo caso i documenti figlio rappresenterebbero il fatto che un utente specifico aveva valutato un post specifico – non sono altro che un user_id, post_id e un rating: una tabella di join nel gergo del database relazionale.

L’utilizzo di relazioni genitore / figlio e has_child consente di trovare facilmente tutti i post preferiti da un utente, consentendo agli utenti di cercare tra i propri preferiti in base al contenuto del post, alla data o a qualsiasi altro attributo di un post o a qualsiasi proprietà dell’elemento figlio. L’aggiunta di un elemento all’elenco degli elementi valutati è economica: richiede solo l’indicizzazione di un elemento rating molto piccolo.

Con questi documenti

Questa query

trova solo “bolivia rated 4” poiché questo è l’unico post che menziona la bolivia che è stato valutato su 3 dall’utente a cui siamo interessati. La query di primo livello sul titolo si applica ai post, dove la query all’interno del filtro has_child descrive le condizioni che i bambini devono corrispondere (in questo caso devono appartenere a un utente specifico e avere almeno una certa valutazione).

Ordinare

Quello che has_child non ti consente di fare è ordinare in base agli attributi dei bambini o restituire gli attributi del bambino. Se si desidera ordinare i post valutati di un utente in base a quando sono stati valutati o diminuendo la valutazione, è possibile cercare direttamente i post/rating, ma è possibile applicare anche alcuni critera di ricerca ai post. Ad esempio, potresti voler trovare solo post votati su un determinato argomento (ancora ordinando in base alla valutazione che l’utente ha dato). Con has_child, sei sfortunato. I documenti annidati non aiutano neanche.

A partire da 0.19.10 è possibile utilizzare il filtro has_parent. Funziona quasi esattamente come ha child, ma consente di specificare invece una query sugli elementi padre. Questa query restituisce le valutazioni per utente 1234, sui post il cui titolo corrisponde a “bolivia”, in ordine di punteggio decrescente

Questo restituisce gli oggetti di valutazione – dovresti quindi recuperare i post corrispondenti con una query separata.

Fingendolo

Se sei bloccato su una versione precedente di elasticsearch, puoi ottenere la maggior parte del modo con top_children. Come dice la documentazione top_children prima interroga i documenti figlio e poi li aggrega in documenti padre. Nel nostro esempio, ciò significa che elasticsearch troverà prima i documenti di valutazione che corrispondono alla nostra query. Quindi abbinerà ogni valutazione al suo post genitore, aggregando post duplicati dove esistono.

Il po ‘ complicato con i bambini migliori è che elasticsearch non sa in anticipo quanti documenti perderà quando si verifica l’aggregazione. In questo caso particolare è facile perché due valutazioni distinte dello stesso utente corrispondono sempre a due post distinti, quindi non è necessario preoccuparsi delle impostazioni factor e incremental_factor perché la fase di aggregazione non fa mai nulla. Allo stesso modo, la modalità punteggio non importa neanche. Se è necessario fornire un conteggio accurato del numero totale di risultati, è sufficiente impostare factor abbastanza grande che il primo sweep elasticsearch dei documenti figlio li trovi tutti. Se sai che l’utente ha 500 articoli valutati sulla loro lista e stai chiedendo i primi 10 articoli, allora un fattore di 50 dovrebbe fare il trucco. Il fattore deve essere solo un limite superiore : non è necessario sapere esattamente quanti elementi l’utente ha nella propria lista (il che potrebbe essere scomodo da risolvere senza una query di ricerca elastica separata se l’utente sta cercando un sottoinsieme specifico delle proprie valutazioni).

Quello che ottieni dopo tutto questo è un elenco di documenti genitore (post) ordinati in base al punteggio della query dei documenti figli (valutazioni). Per raggiungere l’obiettivo originale di ordinare i post in base agli attributi dei documenti figli, dobbiamo solo assicurarci che questo punteggio di query abbia il valore giusto. Ad esempio, avere top_children query wrap una query custom_score in modo da avere il controllo su quale sia il punteggio per ogni figlio.

Con gli stessi documenti nell’indice, questa query restituisce i post che l’utente 1234 ha valutato, ordinati in base alla loro valutazione:

Stiamo eseguendo una query top_children, quindi la prima cosa che dobbiamo fare è dire qual è il tipo di bambini che stiamo considerando (valutazione). Quindi forniamo la query che trova quei bambini. Questa è una query custom_score, che avvolge una query filtered. La query filtered assicura che troviamo solo le valutazioni fornite dall’utente a cui siamo interessati, e quindi l’elemento script rende il punteggio del documento di valutazione stesso, in modo da ottenere i nostri post ordinati per valutazione. Il funkiness con i backslash è solo perché sto cercando di includere una citazione singola letterale in una stringa amichevole di shell delimitata da virgolette singole – l’effettivo json che stiamo inviando ha solo "script": "doc.value".

Ruby fun

Sfortunatamente la libreria tire non supporta davvero nessuna di queste cose divertenti al momento – c’è un po ‘ di moratoria su questo tipo di funzionalità che viene aggiunta perché al momento ogni singolo piccolo tipo di query e opzione finisce per essere metodi separati sparsi su tire, che il manutentore comprensibilmente non piace. Si può sorta di hack in però.

Tire non consente di impostare l’ID padre di un documento durante l’indicizzazione. Questo è semplice da aggiungere e viene trattenuto solo dalla moratoria di cui sopra. La mia forchetta aggiunge questa abilità. Con ciò si finisce con

Il prossimo po ‘ di infelicità è che la creazione dell’indice automatico di tire presuppone un tipo per indice, ma affinché esista una relazione genitore/figlio entrambi i tipi devono essere nello stesso indice. Ho finito per fare qualcosa di simile per creare i miei indici.

che non è così bello ma ottiene il lavoro fatto.

Infine è necessario eseguire effettivamente la query. In assenza di top_children che in realtà fa parte dell’api di tire, puoi fonderlo in questo modo

Questo po ‘ di spiacevolezza crea la query come hash e poi la infila in tire mentre sta guardando dall’altra parte. Ovviamente puoi strutturarlo in modo tale che sia facile aggiungere altre condizioni (sia sul Post che sul rating) alla ricerca. Puoi anche costruire il json manualmente e usare Post.search :payload => my_json(c’è un bug con l’opzione payload che si scontra con l’estensione logger di tire-contrib)

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.