Prime impressioni su Amazon Neptune

Saluti, residenti di Khabrovsk. In attesa dell'inizio del corso "AWS per sviluppatori" Abbiamo preparato una traduzione di materiale interessante.

Prime impressioni su Amazon Neptune

In molti casi d'uso che ci piacciono bakdataCome vediamo sui siti web dei nostri clienti, le informazioni rilevanti sono nascoste nelle connessioni tra entità, ad esempio quando si analizzano le relazioni tra utenti, le dipendenze tra elementi o le connessioni tra sensori. Tali casi d'uso sono solitamente modellati su un grafico. All'inizio di quest'anno, Amazon ha rilasciato il suo nuovo database grafico, Neptune. In questo post vogliamo condividere le nostre prime idee, buone pratiche e cosa può essere migliorato nel tempo.

Perché avevamo bisogno di Amazon Neptune

I database a grafo promettono di gestire set di dati altamente connessi meglio dei loro equivalenti relazionali. In tali set di dati, le informazioni rilevanti vengono solitamente archiviate nelle relazioni tra oggetti. Abbiamo utilizzato uno straordinario progetto open data per testare Neptune MusicaBrainz. MusicBrainz raccoglie ogni tipo di metadata musicale immaginabile, come informazioni su artisti, canzoni, uscite di album o concerti, nonché con chi ha collaborato l'artista dietro la canzone o quando l'album è stato pubblicato e in quale paese. MusicBrainz può essere visto come un'enorme rete di entità in qualche modo collegate all'industria musicale.

Il set di dati MusicBrainz viene fornito come dump CSV di un database relazionale. In totale, il dump contiene circa 93 milioni di righe in 157 tabelle. Mentre alcune di queste tabelle contengono dati di base come artisti, eventi, registrazioni, pubblicazioni o brani, altre tabelle di collegamento — memorizzare le relazioni tra artisti e registrazioni, altri artisti o pubblicazioni, ecc... Dimostrano la struttura grafica di un set di dati. Convertendo il set di dati in triple RDF, abbiamo ottenuto circa 500 milioni di istanze.

Sulla base dell'esperienza e delle impressioni dei partner di progetto con cui lavoriamo, presentiamo un contesto in cui questa base di conoscenza viene utilizzata per ottenere nuove informazioni. Inoltre, ci aspettiamo che venga aggiornato regolarmente, ad esempio aggiungendo nuove versioni o aggiornando i membri del gruppo.

registrazione

Come previsto, installare Amazon Neptune è semplice. È abbastanza dettagliata documentato. Puoi avviare un database a grafo in pochi clic. Tuttavia, quando si tratta di una configurazione più dettagliata, informazioni necessarie difficile da trovare. Pertanto, vogliamo indicare un parametro di configurazione.

Prime impressioni su Amazon Neptune
Schermata di configurazione per i gruppi di parametri

Amazon afferma che Neptune si concentra su carichi di lavoro transazionali a bassa latenza, motivo per cui il timeout predefinito della richiesta è di 120 secondi. Tuttavia, abbiamo testato molti casi d'uso analitici in cui abbiamo raggiunto regolarmente questo limite. Questo timeout può essere modificato creando un nuovo gruppo di parametri per Neptune e impostandolo neptune_query_timeout corrispondente restrizione.

Caricamento dati

Di seguito discuteremo in dettaglio come abbiamo caricato i dati di MusicBrainz in Neptune.

Relazioni a tre

Innanzitutto, abbiamo convertito i dati di MusicBrainz in triple RDF. Pertanto, per ciascuna tabella, abbiamo definito un modello che definisce come ciascuna colonna è rappresentata nella tripla. In questo esempio, ogni riga della tabella degli artisti è mappata su dodici triple RDF.

<http://musicbrainz.foo/artist/${id}> <http://musicbrainz.foo/gid> "${gid}"^^<http://www.w3.org/2001/XMLSchema#string> .
 
 
<http://musicbrainz.foo/artist/${id}> <http://musicbrainz.foo/name> "${name}"^^<http://www.w3.org/2001/XMLSchema#string> .
 
<http://musicbrainz.foo/artist/${id}> <http://musicbrainz.foo/sort-name> "${sort_name}"^^<http://www.w3.org/2001/XMLSchema#string> .
 
<http://musicbrainz.foo/artist/${id}> <http://musicbrainz.foo/begin-date> "${begin_date_year}-${begin_date_month}-${begin_date_day}"^^xsd:<http://www.w3.org/2001/XMLSchema#date> .
 
<http://musicbrainz.foo/artist/${id}> <http://musicbrainz.foo/end-date> "${end_date_year}-${end_date_month}-${end_date_day}"^^xsd:<http://www.w3.org/2001/XMLSchema#date> .
 
<http://musicbrainz.foo/artist/${id}> <http://musicbrainz.foo/type> <http://musicbrainz.foo/artist-type/${type}> .
 
<http://musicbrainz.foo/artist/${id}> <http://musicbrainz.foo/area> <http://musicbrainz.foo/area/${area}> .
 
<http://musicbrainz.foo/artist/${id}> <http://musicbrainz.foo/gender> <http://musicbrainz.foo/gender/${gender}> .
 
<http://musicbrainz.foo/artist/${id}> <http://musicbrainz.foo/comment> "${comment}"^^<http://www.w3.org/2001/XMLSchema#string> .
 
<http://musicbrainz.foo/artist/${id}> <http://musicbrainz.foo/edits-pending> "${edits_pending}"^^<http://www.w3.org/2001/XMLSchema#int> .
 
<http://musicbrainz.foo/artist/${id}> <http://musicbrainz.foo/last-updated> "${last_updated}"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
 
<http://musicbrainz.foo/artist/${id}> <http://musicbrainz.foo/ended> "${ended}"^^<http://www.w3.org/2001/XMLSchema#boolean> .

Caricamento collettivo

Il modo suggerito per caricare grandi quantità di dati in Neptune è attraverso il processo di caricamento collettivo tramite S3. Dopo aver caricato i file triple su S3, inizi il caricamento utilizzando una richiesta POST. Nel nostro caso, ci sono volute circa 24 ore per 500 milioni di gemelli. Ci aspettavamo che fosse più veloce.

curl -X POST -H 'Content-Type: application/json' http://your-neptune-cluster:8182/loader -d '{
 
 
 "source" : "s3://your-s3-bucket",
 
 "format" : "ntriples",
 
 "iamRoleArn" : "arn:aws:iam::your-iam-user:role/NeptuneLoadFromS3",
 
 "region" : "eu-west-1",
 
 "failOnError" : "FALSE"
 
}'

Per evitare questo lungo processo ogni volta che lanciamo Neptune, abbiamo deciso di ripristinare l'istanza da uno snapshot in cui queste triplette erano già caricate. L'esecuzione da uno snapshot è notevolmente più veloce, ma richiede comunque circa un'ora prima che Neptune sia disponibile per le richieste.

Durante il caricamento iniziale delle triplette in Neptune, abbiamo riscontrato vari errori.

{
 
 
 "errorCode" : "PARSING_ERROR",
 
 "errorMessage" : "Content after '.' is not allowed",
 
 "fileName" : [...],
 
 "recordNum" : 25
 
}

Alcuni di essi stavano analizzando errori, come mostrato sopra. Ad oggi non abbiamo ancora capito cosa esattamente sia andato storto a questo punto. Un po' più di dettaglio sarebbe sicuramente d'aiuto qui. Questo errore si è verificato per circa l'1% delle triple inserite. Ma per quanto riguarda il test di Neptune, abbiamo accettato il fatto che lavoriamo solo con il 99% delle informazioni di MusicBrainz.

Anche se questo è facile per le persone che hanno familiarità con SPARQL, tieni presente che le triple RDF devono essere annotate con tipi di dati espliciti, il che può causare errori.

Scaricamento in streaming

Come accennato in precedenza, non vogliamo utilizzare Neptune come un archivio dati statico, ma piuttosto come una base di conoscenza flessibile e in evoluzione. Quindi dovevamo trovare modi per introdurre nuove triple quando la base di conoscenza cambia, ad esempio quando viene pubblicato un nuovo album o quando vogliamo materializzare la conoscenza derivata.

Neptune supporta gli operatori di input tramite query SPARQL, sia grezze che basate su campioni. Discuteremo entrambi gli approcci di seguito.

Uno dei nostri obiettivi era inserire i dati in modalità streaming. Considera l'idea di pubblicare un album in un nuovo paese. Dal punto di vista di MusicBrainz, ciò significa che per una pubblicazione che include album, singoli, EP, ecc., viene aggiunta una nuova voce alla tabella paese di rilascio. In RDF, abbiniamo queste informazioni a due nuove triple.

INSERT DATA { <http://musicbrainz.foo/release-country/737041> <http://musicbrainz.foo/release> <http://musicbrainz.foo/release/435759> };INSERT DATA { <http://musicbrainz.foo/release-country/737041> <http://musicbrainz.foo/date-year> "2018"^^<http://www.w3.org/2001/XMLSchema#int> };

Un altro obiettivo era ottenere nuova conoscenza dal grafico. Diciamo che vogliamo ottenere il numero di pubblicazioni che ciascun artista ha pubblicato nella sua carriera. Una query di questo tipo è piuttosto complessa e richiede più di 20 minuti su Nettuno, quindi dobbiamo materializzare il risultato per riutilizzare questa nuova conoscenza in qualche altra query. Quindi aggiungiamo le triple con queste informazioni al grafico, inserendo il risultato della sottoquery.

INSERT {
 
 
  ?artist_credit <http://musicbrainz.foo/number-of-releases> ?number_of_releases
 
} WHERE {
 
  SELECT ?artist_credit (COUNT(*) as ?number_of_releases)
 
  WHERE {
 
     ?artist_credit <http://musicbrainz.foo/rdftype> <http://musicbrainz.foo/artist-credit> .
 
     ?release_group <http://musicbrainz.foo/artist-credit> ?artist_credit .
 
     ?release_group <http://musicbrainz.foo/rdftype> <http://musicbrainz.foo/release-group> .
 
     ?release_group <http://musicbrainz.foo/name> ?release_group_name .
 
  }
 
  GROUP BY ?artist_credit
 
}

L'aggiunta di singole triple al grafico richiede pochi millisecondi, mentre il tempo di esecuzione per l'inserimento del risultato di una sottoquery dipende dal tempo di esecuzione della sottoquery stessa.

Sebbene non lo usiamo spesso, Neptune consente anche di rimuovere terzine basate su campioni o dati espliciti, che possono essere utilizzati per aggiornare le informazioni.

Query SPARQL

Introducendo il sottocampione precedente, che restituisce il numero di uscite per ciascun artista, abbiamo già introdotto il primo tipo di query a cui vogliamo rispondere utilizzando Neptune. Creare una query in Neptune è semplice: invia una richiesta POST all'endpoint SPARQL, come mostrato di seguito:

curl -X POST --data-binary 'query=SELECT ?artist ?p ?o where {?artist <http://musicbrainz.foo/name> "Elton John" . ?artist ?p ?o . }' http://your-neptune-cluster:8182/sparql

Inoltre, abbiamo implementato una query che restituisce un profilo artista contenente informazioni sul nome, l'età o il paese di origine. Tieni presente che gli artisti possono essere individui, gruppi musicali o orchestre. Inoltre, integriamo questi dati con informazioni sul numero di pubblicazioni rilasciate dagli artisti durante l'anno. Per gli artisti solisti, aggiungiamo anche informazioni sulle band a cui l'artista ha partecipato ogni anno.

SELECT
 
 
 ?artist_name ?year
 
 ?releases_in_year ?releases_up_year
 
 ?artist_type_name ?releases
 
 ?artist_gender ?artist_country_name
 
 ?artist_begin_date ?bands
 
 ?bands_in_year
 
WHERE {
 
 # Bands for each artist
 
 {
 
   SELECT
 
     ?year
 
     ?first_artist
 
     (group_concat(DISTINCT ?second_artist_name;separator=",") as ?bands)
 
     (COUNT(DISTINCT ?second_artist_name) AS ?bands_in_year)     
 
   WHERE {
 
     VALUES ?year {
 
       1960 1961 1962 1963 1964 1965 1966 1967 1968 1969
 
       1970 1971 1972 1973 1974 1975 1976 1977 1978 1979
 
       1980 1981 1982 1983 1984 1985 1986 1987 1988 1989
 
       1990 1991 1992 1993 1994 1995 1996 1997 1998 1999
 
       2000 2001 2002 2003 2004 2005 2006 2007 2008 2009
 
       2010 2011 2012 2013 2014 2015 2016 2017 2018
 
     }   
 
     ?first_artist <http://musicbrainz.foo/name> "Elton John" .
 
     ?first_artist <http://musicbrainz.foo/rdftype> <http://musicbrainz.foo/artist> .
 
     ?first_artist <http://musicbrainz.foo/type> ?first_artist_type .
 
     ?first_artist <http://musicbrainz.foo/name> ?first_artist_name .
 

 
 
     ?second_artist <http://musicbrainz.foo/rdftype> <http://musicbrainz.foo/artist> .
 
     ?second_artist <http://musicbrainz.foo/type> ?second_artist_type .
 
     ?second_artist <http://musicbrainz.foo/name> ?second_artist_name .
 
     optional { ?second_artist <http://musicbrainz.foo/begin-date-year> ?second_artist_begin_date_year . }
 
     optional { ?second_artist <http://musicbrainz.foo/end-date-year> ?second_artist_end_date_year . }
 

 
 
     ?l_artist_artist <http://musicbrainz.foo/entity0> ?first_artist .
 
     ?l_artist_artist <http://musicbrainz.foo/entity1> ?second_artist .
 
     ?l_artist_artist <http://musicbrainz.foo/link> ?link .
 

 
 
     optional { ?link <http://musicbrainz.foo/begin-date-year> ?link_begin_date_year . }
 
     optional { ?link <http://musicbrainz.foo/end-date-year> ?link_end_date_year . }
 

 
 
     FILTER (!bound(?link_begin_date_year) || ?link_begin_date_year <= ?year)
 
     FILTER (!bound(?link_end_date_year) || ?link_end_date_year >= ?year)
 
     FILTER (!bound(?second_artist_begin_date_year) || ?second_artist_begin_date_year <= ?year)
 
     FILTER (!bound(?second_artist_end_date_year) || ?second_artist_end_date_year >= ?year)
 
     FILTER (?first_artist_type NOT IN (<http://musicbrainz.foo/artist-type/2>, <http://musicbrainz.foo/artist-type/5>, <http://musicbrainz.foo/artist-type/6>))
 
     FILTER (?second_artist_type IN (<http://musicbrainz.foo/artist-type/2>, <http://musicbrainz.foo/artist-type/5>, <http://musicbrainz.foo/artist-type/6>))
 
   }
 
   GROUP BY ?first_artist ?year
 
 }
 
 # Releases up to a year
 
 {
 
   SELECT
 
     ?artist
 
     ?year
 
     (group_concat(DISTINCT ?release_name;separator=",") as ?releases)
 
     (COUNT(*) as ?releases_up_year)
 
   WHERE {
 
     VALUES ?year {
 
       1960 1961 1962 1963 1964 1965 1966 1967 1968 1969
 
       1970 1971 1972 1973 1974 1975 1976 1977 1978 1979
 
       1980 1981 1982 1983 1984 1985 1986 1987 1988 1989
 
       1990 1991 1992 1993 1994 1995 1996 1997 1998 1999
 
       2000 2001 2002 2003 2004 2005 2006 2007 2008 2009
 
       2010 2011 2012 2013 2014 2015 2016 2017 2018 
 
     }
 

 
 
     ?artist <http://musicbrainz.foo/name> "Elton John" .
 

 
 
     ?artist_credit_name <http://musicbrainz.foo/artist-credit> ?artist_credit .
 
     ?artist_credit_name <http://musicbrainz.foo/rdftype> <http://musicbrainz.foo/artist-credit-name> .
 
     ?artist_credit_name <http://musicbrainz.foo/artist> ?artist .
 
     ?artist_credit <http://musicbrainz.foo/rdftype> <http://musicbrainz.foo/artist-credit> .
 

 
 
     ?release_group <http://musicbrainz.foo/artist-credit> ?artist_credit .
 
     ?release_group <http://musicbrainz.foo/rdftype> <http://musicbrainz.foo/release-group> .
 
     ?release_group <http://musicbrainz.foo/name> ?release_group_name .
 
     ?release <http://musicbrainz.foo/release-group> ?release_group .
 
     ?release <http://musicbrainz.foo/name> ?release_name .
 
     ?release_country <http://musicbrainz.foo/release> ?release .
 
     ?release_country <http://musicbrainz.foo/date-year> ?release_country_year .
 

 
 
     FILTER (?release_country_year <= ?year)
 
   }
 
   GROUP BY ?artist ?year
 
 }
 
 # Releases in a year
 
 {
 
   SELECT ?artist ?year (COUNT(*) as ?releases_in_year)
 
   WHERE {
 
     VALUES ?year {
 
       1960 1961 1962 1963 1964 1965 1966 1967 1968 1969
 
       1970 1971 1972 1973 1974 1975 1976 1977 1978 1979
 
       1980 1981 1982 1983 1984 1985 1986 1987 1988 1989
 
       1990 1991 1992 1993 1994 1995 1996 1997 1998 1999
 
       2000 2001 2002 2003 2004 2005 2006 2007 2008 2009
 
       2010 2011 2012 2013 2014 2015 2016 2017 2018 
 
     }
 

 
 
     ?artist <http://musicbrainz.foo/name> "Elton John" .
 

 
 
     ?artist_credit_name <http://musicbrainz.foo/artist-credit> ?artist_credit .
 
     ?artist_credit_name <http://musicbrainz.foo/rdftype> <http://musicbrainz.foo/artist-credit-name> .
 
     ?artist_credit_name <http://musicbrainz.foo/artist> ?artist .
 
     ?artist_credit <http://musicbrainz.foo/rdftype> <http://musicbrainz.foo/artist-credit> .
 

 
 
     ?release_group <http://musicbrainz.foo/artist-credit> ?artist_credit .
 
     ?release_group <http://musicbrainz.foo/rdftype> <http://musicbrainz.foo/release-group> .
 
     ?release_group <http://musicbrainz.foo/name> ?release_group_name .
 
     ?release <http://musicbrainz.foo/release-group> ?release_group .
 
     ?release_country <http://musicbrainz.foo/release> ?release .
 
     ?release_country <http://musicbrainz.foo/date-year> ?release_country_year .
 

 
 
     FILTER (?release_country_year = ?year)
 
   }
 
   GROUP BY ?artist ?year
 
 }
 
 # Master data
 
 {
 
   SELECT DISTINCT ?artist ?artist_name ?artist_gender ?artist_begin_date ?artist_country_name
 
   WHERE {
 
     ?artist <http://musicbrainz.foo/name> ?artist_name .
 
     ?artist <http://musicbrainz.foo/name> "Elton John" .
 
     ?artist <http://musicbrainz.foo/gender> ?artist_gender_id .
 
     ?artist_gender_id <http://musicbrainz.foo/name> ?artist_gender .
 
     ?artist <http://musicbrainz.foo/area> ?birth_area .
 
     ?artist <http://musicbrainz.foo/begin-date-year> ?artist_begin_date.
 
     ?birth_area <http://musicbrainz.foo/name> ?artist_country_name .
 

 
 
     FILTER(datatype(?artist_begin_date) = xsd:int)
 
   }

A causa della complessità di tale query, potremmo eseguire query puntuali solo per un artista specifico, come Elton John, ma non per tutti gli artisti. Nettuno non sembra ottimizzare tale query inserendo i filtri nelle sottoselezioni. Pertanto, ogni selezione deve essere filtrata manualmente in base al nome dell'artista.

Neptune prevede tariffe sia orarie che per I/O. Per i nostri test, abbiamo utilizzato l'istanza minima di Neptune, che costa $ 0,384/ora. Nel caso della query precedente, che calcola il profilo di un singolo lavoratore, Amazon ci addebita decine di migliaia di operazioni I/O, il che implica un costo di $ 0.02.

conclusione

Innanzitutto, Amazon Neptune mantiene la maggior parte delle sue promesse. Come servizio gestito, è un database a grafo estremamente facile da installare e che può essere installato e funzionante senza troppe configurazioni. Ecco i nostri cinque risultati principali:

  • Il caricamento collettivo è facile ma lento. Ma può complicarsi con messaggi di errore che non sono molto utili.
  • Il download in streaming supporta tutto ciò che ci aspettavamo ed è stato abbastanza veloce
  • Le query sono semplici, ma non sufficientemente interattive per eseguire query analitiche
  • Le query SPARQL devono essere ottimizzate manualmente
  • I pagamenti di Amazon sono difficili da stimare perché è difficile stimare la quantità di dati scansionati da una query SPARQL.

È tutto. Iscriversi per webinar gratuito sul tema “Bilanciamento del carico”.


Fonte: habr.com

Aggiungi un commento