Primele impresii despre Amazon Neptune

Salutare, locuitori din Khabrovsk. În așteptarea începerii cursului „AWS pentru dezvoltatori” Am pregătit o traducere a unui material interesant.

Primele impresii despre Amazon Neptune

În multe cazuri de utilizare care ne plac bakdataDupă cum vedem pe site-urile clienților noștri, informațiile relevante sunt ascunse în conexiunile dintre entități, de exemplu atunci când se analizează relațiile dintre utilizatori, dependențele dintre elemente sau conexiunile dintre senzori. Astfel de cazuri de utilizare sunt de obicei modelate pe un grafic. La începutul acestui an, Amazon a lansat noua sa bază de date grafice, Neptune. În această postare dorim să împărtășim primele noastre idei, bune practici și ceea ce poate fi îmbunătățit în timp.

De ce aveam nevoie de Amazon Neptune

Bazele de date grafice promit să gestioneze seturi de date foarte conectate mai bine decât echivalentele lor relaționale. În astfel de seturi de date, informațiile relevante sunt de obicei stocate în relațiile dintre obiecte. Am folosit un proiect uimitor de date deschise pentru a testa Neptun MusicBrainz. MusicBrainz colectează orice tip de metadate muzicale imaginabile, cum ar fi informații despre artiști, melodii, lansări de albume sau concerte, precum și cu cine a colaborat artistul din spatele cântecului sau când a fost lansat albumul în ce țară. MusicBrainz poate fi văzut ca o rețea uriașă de entități care sunt cumva conectate la industria muzicală.

Setul de date MusicBrainz este furnizat ca un dump CSV al unei baze de date relaționale. În total, depozitul conține aproximativ 93 de milioane de rânduri în 157 de tabele. În timp ce unele dintre aceste tabele conțin date de bază, cum ar fi artiști, evenimente, înregistrări, lansări sau piese, altele tabele de legătură — stocarea relațiilor dintre artiști și înregistrări, alți artiști sau lansări etc... Acestea demonstrează structura grafică a unui set de date. La convertirea setului de date în triple RDF, am obținut aproximativ 500 de milioane de instanțe.

Pe baza experienței și impresiilor partenerilor de proiect cu care lucrăm, vă prezentăm un cadru în care această bază de cunoștințe este folosită pentru a obține informații noi. În plus, ne așteptăm să fie actualizat în mod regulat, de exemplu prin adăugarea de noi versiuni sau actualizarea membrilor grupului.

ajustare

După cum era de așteptat, instalarea Amazon Neptune este simplă. Ea este destul de detaliată documentat. Puteți lansa o bază de date grafică în doar câteva clicuri. Cu toate acestea, când vine vorba de o configurație mai detaliată, informatie necesara greu de gasit. Prin urmare, dorim să indicăm un parametru de configurare.

Primele impresii despre Amazon Neptune
Captură de ecran de configurare pentru grupurile de parametri

Amazon spune că Neptune se concentrează pe sarcini de lucru tranzacționale cu latență scăzută, motiv pentru care timpul de expirare implicit al cererii este de 120 de secunde. Totuși, am testat multe cazuri de utilizare analitică în care am atins regulat această limită. Acest timeout poate fi modificat prin crearea unui nou grup de parametri pentru Neptune și setare neptune_query_timeout restricție corespunzătoare.

Încărcare date

Mai jos vom discuta în detaliu cum am încărcat datele MusicBrainz în Neptune.

Relații în trei

În primul rând, am convertit datele MusicBrainz în triple RDF. Prin urmare, pentru fiecare tabel, am definit un șablon care definește modul în care fiecare coloană este reprezentată în triplu. În acest exemplu, fiecare rând din tabelul performer este mapat la douăsprezece 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> .

Încărcare în bloc

Modul sugerat de a încărca cantități mari de date în Neptune este prin procesul de încărcare în bloc prin S3. După încărcarea fișierelor triple pe S3, începeți încărcarea folosind o solicitare POST. În cazul nostru, a durat aproximativ 24 de ore pentru 500 de milioane de tripleți. Ne așteptam să fie mai rapid.

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"
 
}'

Pentru a evita acest proces îndelungat de fiecare dată când lansăm Neptune, am decis să restabilim instanța dintr-un instantaneu în care aceste triplete erau deja încărcate. Rularea dintr-un instantaneu este semnificativ mai rapidă, dar durează aproximativ o oră până când Neptune este disponibil pentru solicitări.

La încărcarea inițială a tripleților în Neptun, am întâlnit diverse erori.

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

Unele dintre ele au fost erori de analiză, așa cum se arată mai sus. Până în prezent, încă nu ne-am dat seama ce a mers prost exact în acest moment. Un pic mai mult detaliu ar ajuta cu siguranță aici. Această eroare a apărut pentru aproximativ 1% din triplele introduse. Dar în ceea ce privește testarea lui Neptune, am acceptat faptul că lucrăm doar cu 99% din informațiile de la MusicBrainz.

Chiar dacă acest lucru este ușor pentru persoanele familiarizate cu SPARQL, fiți conștienți de faptul că triplele RDF trebuie adnotate cu tipuri de date explicite, ceea ce din nou poate provoca erori.

Descărcare în flux

După cum am menționat mai sus, nu dorim să folosim Neptune ca un depozit de date static, ci mai degrabă ca o bază de cunoștințe flexibilă și în evoluție. Așa că trebuia să găsim modalități de a introduce noi triple atunci când baza de cunoștințe se schimbă, de exemplu când este publicat un nou album sau când dorim să materializăm cunoștințele derivate.

Neptune acceptă operatorii de intrare prin interogări SPARQL, atât brute, cât și bazate pe eșantioane. Vom discuta ambele abordări mai jos.

Unul dintre obiectivele noastre a fost să introducem date într-o manieră de streaming. Luați în considerare lansarea unui album într-o țară nouă. Din perspectiva MusicBrainz, aceasta înseamnă că pentru o versiune care include albume, single-uri, EP-uri etc., o nouă intrare este adăugată la tabel. eliberare-ţară. În RDF, potrivim aceste informații cu două triple noi.

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 alt obiectiv a fost obținerea de noi cunoștințe din grafic. Să presupunem că vrem să obținem numărul de lansări pe care fiecare artist le-a publicat în cariera sa. O astfel de interogare este destul de complexă și durează peste 20 de minute în Neptune, așa că trebuie să materializăm rezultatul pentru a reutiliza aceste noi cunoștințe într-o altă interogare. Așa că adăugăm triple cu aceste informații înapoi în grafic, introducând rezultatul subinterogării.

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
 
}

Adăugarea de triple simple la grafic durează câteva milisecunde, în timp ce timpul de execuție pentru inserarea rezultatului unei subinterogări depinde de timpul de execuție al subinterogării în sine.

Deși nu l-am folosit des, Neptune vă permite, de asemenea, să eliminați tripleți pe baza mostrelor sau a datelor explicite, care pot fi folosite pentru a actualiza informații.

Interogări SPARQL

Prin introducerea subeșantionului anterior, care returnează numărul de lansări pentru fiecare artist, am introdus deja primul tip de interogare la care dorim să răspundem folosind Neptune. Crearea unei interogări în Neptune este ușoară - trimiteți o solicitare POST la punctul final SPARQL, după cum se arată mai jos:

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

În plus, am implementat o interogare care returnează un profil de artist care conține informații despre numele, vârsta sau țara de origine a acestuia. Rețineți că interpreții pot fi persoane fizice, trupe sau orchestre. În plus, completăm aceste date cu informații despre numărul de lansări lansate de artiști în cursul anului. Pentru artiștii solo, adăugăm și informații despre trupele la care artistul a participat în fiecare an.

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)
 
   }

Datorită complexității unei astfel de interogări, am putea efectua interogări de puncte doar pentru un anumit artist, cum ar fi Elton John, dar nu pentru toți artiștii. Neptune nu pare să optimizeze o astfel de interogare prin plasarea filtrelor în subselectări. Prin urmare, fiecare selecție trebuie filtrată manual după numele artistului.

Neptune are taxe atât pe oră, cât și pe I/O. Pentru testarea noastră, am folosit instanța minimă Neptune, care costă 0,384 USD/oră. În cazul interogării de mai sus, care calculează profilul pentru un singur lucrător, Amazon ne taxează cu zeci de mii de operațiuni I/O, implicând un cost de 0.02 USD.

Producție

În primul rând, Amazon Neptune își ține majoritatea promisiunilor. Ca serviciu gestionat, este o bază de date grafică care este extrem de ușor de instalat și poate fi în funcțiune și fără multă configurare. Iată cele cinci concluzii principale ale noastre:

  • Încărcarea în bloc este ușoară, dar lentă. Dar se poate complica cu mesaje de eroare care nu sunt foarte utile.
  • Descărcarea în flux acceptă tot ce ne așteptam și a fost destul de rapidă
  • Interogările sunt simple, dar nu sunt suficient de interactive pentru a rula interogări analitice
  • Interogările SPARQL trebuie optimizate manual
  • Plățile Amazon sunt dificil de estimat, deoarece este dificil de estimat cantitatea de date scanate de o interogare SPARQL.

Asta e tot. Înregistrează-te pentru webinar gratuit pe tema „Echilibrarea sarcinii”.


Sursa: www.habr.com

Adauga un comentariu