Pozdrav, stanovnici Khabrovsk. U iščekivanju početka tečaja
U mnogim slučajevima upotrebe koji nam se sviđaju
Zašto nam je trebao Amazon Neptun
Graf baze podataka obećavaju da će rukovati visoko povezanim skupovima podataka bolje od svojih relacijskih ekvivalenata. U takvim se skupovima podataka relevantne informacije obično pohranjuju u odnosima između objekata. Za testiranje Neptuna koristili smo nevjerojatan projekt otvorenih podataka
Skup podataka MusicBrainz dostupan je kao CSV ispis relacijske baze podataka. Ukupno, dump sadrži oko 93 milijuna redaka u 157 tablica. Dok neke od ovih tablica sadrže osnovne podatke kao što su izvođači, događaji, snimke, izdanja ili pjesme, druge tablice veza — pohranjuju odnose između izvođača i snimaka, drugih izvođača ili izdanja, itd... Oni pokazuju strukturu grafikona skupa podataka. Prilikom pretvaranja skupa podataka u RDF triple, dobili smo približno 500 milijuna instanci.
Na temelju iskustva i dojmova partnera na projektu s kojima surađujemo, predstavljamo okruženje u kojem se ta baza znanja koristi za dobivanje novih informacija. Osim toga, očekujemo da će se redovito ažurirati, na primjer dodavanjem novih izdanja ili ažuriranjem članova grupe.
podešavanje
Kao što se i očekivalo, instalacija Amazon Neptuna je jednostavna. Ona je dosta detaljna
Snimka zaslona konfiguracije za grupe parametara
Amazon kaže da se Neptune fokusira na transakcijska opterećenja niske latencije, zbog čega je zadano vremensko ograničenje zahtjeva 120 sekundi. Međutim, testirali smo mnoge analitičke slučajeve upotrebe u kojima smo redovito dostizali ovu granicu. Ovo vremensko ograničenje može se promijeniti stvaranjem nove grupe parametara za Neptune i postavljanjem neptune_query_timeout
odgovarajuće ograničenje.
Učitavanje podataka
U nastavku ćemo detaljno raspravljati o tome kako smo učitali MusicBrainz podatke u Neptune.
Odnosi u troje
Prvo smo pretvorili MusicBrainz podatke u RDF trojke. Stoga smo za svaku tablicu definirali predložak koji definira kako je svaki stupac predstavljen u trojki. U ovom primjeru, svaki redak iz tablice izvođača preslikan je na dvanaest RDF trojki.
<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> .
Skupni prijenos
Predloženi način za učitavanje velikih količina podataka u Neptune je proces skupnog učitavanja putem S3. Nakon učitavanja vaših trostrukih datoteka na S3, započinjete učitavanje pomoću POST zahtjeva. U našem slučaju, za 24 milijuna trojki bilo je potrebno oko 500 sata. Očekivali smo da će biti brže.
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"
}'
Kako bismo izbjegli ovaj dugotrajan proces svaki put kada pokrenemo Neptune, odlučili smo vratiti instancu iz snimke u kojoj su ove trojke već bile učitane. Pokretanje iz snimke znatno je brže, ali i dalje traje oko sat vremena dok Neptune ne postane dostupan za zahtjeve.
Prilikom početnog učitavanja trojki u Neptune, naišli smo na razne pogreške.
{
"errorCode" : "PARSING_ERROR",
"errorMessage" : "Content after '.' is not allowed",
"fileName" : [...],
"recordNum" : 25
}
Neke od njih bile su pogreške u raščlanjivanju, kao što je gore prikazano. Do danas još uvijek nismo shvatili što je točno pošlo po zlu u ovom trenutku. Ovdje bi svakako pomoglo malo više detalja. Ova se pogreška dogodila za približno 1% umetnutih trojki. Ali što se tiče testiranja Neptuna, prihvatili smo činjenicu da radimo samo s 99% informacija iz MusicBrainza.
Iako je ovo jednostavno za ljude koji poznaju SPARQL, imajte na umu da RDF trostruki moraju biti označeni eksplicitnim tipovima podataka, što opet može uzrokovati pogreške.
Streaming preuzimanje
Kao što je gore spomenuto, Neptun ne želimo koristiti kao statičnu pohranu podataka, već kao fleksibilnu bazu znanja koja se razvija. Stoga smo morali pronaći načine za uvođenje novih trojki kada se baza znanja promijeni, na primjer kada se objavi novi album ili kada želimo materijalizirati izvedeno znanje.
Neptune podržava operatore unosa kroz SPARQL upite, neobrađene i temeljene na uzorku. U nastavku ćemo razmotriti oba pristupa.
Jedan od naših ciljeva bio je unos podataka na streaming način. Razmislite o izdavanju albuma u novoj zemlji. Iz perspektive MusicBrainza, to znači da se za izdanje koje uključuje albume, singlove, EP-ove itd. u tablicu dodaje novi unos puštanje-zemlja. U RDF-u povezujemo ove informacije s dvije nove trojke.
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> };
Drugi cilj je bio dobiti nova znanja iz grafikona. Recimo da želimo dobiti broj izdanja koje je svaki umjetnik objavio u svojoj karijeri. Takav upit je prilično složen i traje više od 20 minuta u Neptunu, pa moramo materijalizirati rezultat kako bismo to novo znanje ponovno upotrijebili u nekom drugom upitu. Stoga dodajemo trojke s ovim informacijama natrag na grafikon, unoseći rezultat podupita.
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
}
Dodavanje pojedinačne trojke na graf traje nekoliko milisekundi, dok vrijeme izvršenja za umetanje rezultata podupita ovisi o vremenu izvršenja samog podupita.
Iako ga nismo često koristili, Neptune također omogućuje uklanjanje trojki na temelju uzoraka ili eksplicitnih podataka, koji se mogu koristiti za ažuriranje informacija.
SPARQL upiti
Uvođenjem prethodnog poduzorka, koji vraća broj izdanja za svakog izvođača, već smo uveli prvu vrstu upita na koji želimo odgovoriti pomoću Neptuna. Izrada upita u Neptuneu je jednostavna - pošaljite POST zahtjev SPARQL krajnjoj točki, kao što je prikazano u nastavku:
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
Osim toga, implementirali smo upit koji vraća profil umjetnika koji sadrži informacije o njihovom imenu, dobi ili zemlji podrijetla. Imajte na umu da izvođači mogu biti pojedinci, bendovi ili orkestri. Osim toga, ove podatke dopunjujemo informacijama o broju izdanja koje su izvođači objavili tijekom godine. Za solo izvođače također dodajemo informacije o bendovima u kojima je taj izvođač sudjelovao svake godine.
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)
}
Zbog složenosti takvog upita, mogli smo izvršiti upite samo za određenog izvođača, kao što je Elton John, ali ne za sve izvođače. Čini se da Neptune ne optimizira takav upit ispuštanjem filtara u pododabrane. Stoga se svaki odabir mora ručno filtrirati prema imenu izvođača.
Neptune ima naknade po satu i po I/O. Za naše testiranje koristili smo minimalnu instancu Neptune, koja košta 0,384 USD/sat. U slučaju gornjeg upita, koji izračunava profil za jednog radnika, Amazon nam naplaćuje desetke tisuća I/O operacija, što implicira trošak od 0.02 USD.
Izlaz
Prvo, Amazon Neptune održava većinu svojih obećanja. Kao upravljana usluga, to je grafička baza podataka koja se iznimno lako instalira i može se pokrenuti bez puno konfiguracije. Evo naših pet ključnih nalaza:
- Skupni prijenos je jednostavan, ali spor. Ali može se zakomplicirati s porukama o pogreškama koje nisu od velike pomoći.
- Streaming preuzimanje podržava sve što smo očekivali i bilo je prilično brzo
- Upiti su jednostavni, ali nedovoljno interaktivni za pokretanje analitičkih upita
- SPARQL upiti moraju se optimizirati ručno
- Amazon plaćanja teško je procijeniti jer je teško procijeniti količinu podataka skeniranih SPARQL upitom.
To je sve. Prijaviti se za
Izvor: www.habr.com