Mga unang impression ng Amazon Neptune

Pagpupugay, mga residente ng Khabrovsk. Sa paghihintay sa pagsisimula ng kurso "AWS para sa mga Developer" Naghanda kami ng pagsasalin ng kawili-wiling materyal.

Mga unang impression ng Amazon Neptune

Sa maraming mga kaso ng paggamit na gusto namin bakdataGaya ng nakikita namin sa mga website ng aming mga kliyente, nakatago ang may-katuturang impormasyon sa mga koneksyon sa pagitan ng mga entity, halimbawa kapag sinusuri ang mga ugnayan sa pagitan ng mga user, dependency sa pagitan ng mga elemento, o koneksyon sa pagitan ng mga sensor. Ang mga ganitong kaso ng paggamit ay karaniwang na-modelo sa isang graph. Mas maaga sa taong ito, inilabas ng Amazon ang bagong database ng graph nito, ang Neptune. Sa post na ito gusto naming ibahagi ang aming mga unang ideya, magagandang kasanayan at kung ano ang maaaring mapabuti sa paglipas ng panahon.

Bakit kailangan namin ang Amazon Neptune

Nangangako ang mga database ng graph na pangasiwaan ang mataas na konektadong mga set ng data nang mas mahusay kaysa sa kanilang mga katumbas na relasyon. Sa ganitong mga dataset, ang nauugnay na impormasyon ay karaniwang nakaimbak sa mga relasyon sa pagitan ng mga bagay. Gumamit kami ng kamangha-manghang open data project para subukan ang Neptune MusicBrainz. Kinokolekta ng MusicBrainz ang lahat ng uri ng metadata ng musika na maiisip, tulad ng impormasyon tungkol sa mga artist, kanta, release ng album o konsiyerto, pati na rin kung sino ang nakipagtulungan ng artist sa likod ng kanta o noong inilabas ang album sa kung saang bansa. Ang MusicBrainz ay makikita bilang isang malaking network ng mga entity na kahit papaano ay konektado sa industriya ng musika.

Ang dataset ng MusicBrainz ay ibinigay bilang isang CSV dump ng isang relational database. Sa kabuuan, ang dump ay naglalaman ng humigit-kumulang 93 milyong mga hilera sa 157 mga talahanayan. Habang ang ilan sa mga talahanayang ito ay naglalaman ng pangunahing data gaya ng mga artist, kaganapan, pag-record, release o track, iba pa link na mga talahanayan — mag-imbak ng mga ugnayan sa pagitan ng mga artist at recording, iba pang mga artist o release, atbp... Ipinapakita nila ang istraktura ng graph ng isang set ng data. Kapag kino-convert ang dataset sa RDF triple, nakakuha kami ng humigit-kumulang 500 milyong mga pagkakataon.

Batay sa karanasan at mga impression ng mga kasosyo sa proyekto kung kanino kami nagtatrabaho, nagpapakita kami ng setting kung saan ginagamit ang base ng kaalaman na ito upang makakuha ng bagong impormasyon. Bilang karagdagan, inaasahan namin na regular itong maa-update, halimbawa sa pamamagitan ng pagdaragdag ng mga bagong release o pag-update ng mga miyembro ng grupo.

pag-aayos

Tulad ng inaasahan, ang pag-install ng Amazon Neptune ay simple. Medyo detalyado siya dokumentado. Maaari kang maglunsad ng database ng graph sa ilang pag-click lamang. Gayunpaman, pagdating sa mas detalyadong pagsasaayos, kinakailangang impormasyon mahirap hanapin. Samakatuwid, nais naming ituro ang isang parameter ng pagsasaayos.

Mga unang impression ng Amazon Neptune
Screenshot ng configuration para sa mga pangkat ng parameter

Sinabi ng Amazon na nakatuon ang Neptune sa mga low-latency na transactional workload, kaya naman ang default na timeout ng kahilingan ay 120 segundo. Gayunpaman, sinubukan namin ang maraming mga kaso ng analytical na paggamit kung saan regular naming naabot ang limitasyong ito. Maaaring baguhin ang timeout na ito sa pamamagitan ng paggawa ng bagong pangkat ng parameter para sa Neptune at setting neptune_query_timeout kaukulang paghihigpit.

Loading data

Sa ibaba ay tatalakayin namin nang detalyado kung paano namin na-load ang data ng MusicBrainz sa Neptune.

Mga relasyon sa tatlo

Una, na-convert namin ang data ng MusicBrainz sa mga triple ng RDF. Samakatuwid, para sa bawat talahanayan, tinukoy namin ang isang template na tumutukoy kung paano kinakatawan ang bawat column sa triple. Sa halimbawang ito, ang bawat hilera mula sa talahanayan ng performer ay nakamapa sa labindalawang triple ng 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> .

maramihang pag-upload

Ang iminungkahing paraan upang mag-load ng malaking halaga ng data sa Neptune ay sa pamamagitan ng maramihang proseso ng pag-upload sa pamamagitan ng S3. Pagkatapos i-upload ang iyong mga triples na file sa S3, sisimulan mo ang pag-upload gamit ang isang kahilingan sa POST. Sa aming kaso, tumagal ng halos 24 na oras para sa 500 milyong triplets. Inaasahan namin na ito ay magiging mas mabilis.

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

Upang maiwasan ang mahabang prosesong ito sa tuwing ilulunsad namin ang Neptune, nagpasya kaming ibalik ang instance mula sa isang snapshot kung saan na-load na ang mga triplet na ito. Ang pagpapatakbo mula sa isang snapshot ay makabuluhang mas mabilis, ngunit tumatagal pa rin ng halos isang oras hanggang sa maging available ang Neptune para sa mga kahilingan.

Noong unang naglo-load ng mga triplet sa Neptune, nakatagpo kami ng iba't ibang mga error.

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

Ang ilan sa mga ito ay mga error sa pag-parse, tulad ng ipinapakita sa itaas. Sa ngayon, hindi pa rin namin naiisip kung ano ang eksaktong nangyari sa puntong ito. Ang kaunting detalye ay tiyak na makakatulong dito. Naganap ang error na ito para sa humigit-kumulang 1% ng mga ipinasok na triple. Ngunit hanggang sa pagsubok sa Neptune, tinanggap namin ang katotohanang nagtatrabaho lamang kami sa 99% ng impormasyon mula sa MusicBrainz.

Bagama't madali ito para sa mga taong pamilyar sa SPARQL, tandaan na ang mga triple ng RDF ay dapat na may annotate na mga tahasang uri ng data, na maaaring magdulot muli ng mga error.

Pag-download ng streaming

Gaya ng nabanggit sa itaas, hindi namin gustong gamitin ang Neptune bilang isang static na data store, ngunit bilang isang nababaluktot at umuusbong na base ng kaalaman. Kaya kailangan naming maghanap ng mga paraan upang magpakilala ng mga bagong triple kapag nagbago ang base ng kaalaman, halimbawa kapag may na-publish na bagong album o kapag gusto naming magkatotoo ang nakuhang kaalaman.

Sinusuportahan ng Neptune ang mga input operator sa pamamagitan ng mga query sa SPARQL, parehong raw at sample-based. Tatalakayin natin ang parehong mga diskarte sa ibaba.

Isa sa aming mga layunin ay magpasok ng data sa isang streaming na paraan. Pag-isipang maglabas ng album sa isang bagong bansa. Mula sa pananaw ng MusicBrainz, nangangahulugan ito na para sa isang release na may kasamang mga album, single, EP, atbp., isang bagong entry ang idaragdag sa talahanayan release-bansa. Sa RDF, itinutugma namin ang impormasyong ito sa dalawang bagong 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> };

Ang isa pang layunin ay makakuha ng bagong kaalaman mula sa graph. Sabihin nating gusto nating makuha ang bilang ng mga release na nai-publish ng bawat artist sa kanilang karera. Ang ganitong query ay medyo kumplikado at tumatagal ng higit sa 20 minuto sa Neptune, kaya kailangan nating isakatuparan ang resulta upang magamit muli ang bagong kaalaman na ito sa ilang iba pang query. Kaya nagdadagdag kami ng triple kasama ang impormasyong ito pabalik sa graph, na ipinapasok ang resulta ng subquery.

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
 
}

Ang pagdaragdag ng mga solong triple sa graph ay tumatagal ng ilang millisecond, habang ang oras ng pagpapatupad para sa pagpasok ng resulta ng isang subquery ay nakasalalay sa oras ng pagpapatupad ng subquery mismo.

Bagama't hindi namin ito madalas gamitin, pinapayagan ka rin ng Neptune na mag-alis ng mga triplets batay sa mga sample o tahasang data, na magagamit para mag-update ng impormasyon.

Mga query sa SPARQL

Sa pamamagitan ng pagpapakilala sa nakaraang subsample, na nagbabalik ng bilang ng mga release para sa bawat artist, naipakilala na namin ang unang uri ng query na gusto naming sagutin gamit ang Neptune. Madali ang pagbuo ng query sa Neptune - magpadala ng POST na kahilingan sa endpoint ng SPARQL, tulad ng ipinapakita sa ibaba:

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

Bukod pa rito, nagpatupad kami ng query na nagbabalik ng profile ng artist na naglalaman ng impormasyon tungkol sa kanilang pangalan, edad, o bansang pinagmulan. Tandaan na ang mga gumaganap ay maaaring mga indibidwal, banda, o orkestra. Bilang karagdagan, dinadagdagan namin ang data na ito ng impormasyon tungkol sa bilang ng mga release na inilabas ng mga artist sa buong taon. Para sa mga solo artist, nagdaragdag din kami ng impormasyon tungkol sa mga banda na nilahukan ng artist bawat taon.

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

Dahil sa pagiging kumplikado ng naturang query, maaari lang kaming magsagawa ng mga point query para sa isang partikular na artist, gaya ni Elton John, ngunit hindi para sa lahat ng artist. Mukhang hindi ino-optimize ng Neptune ang ganoong query sa pamamagitan ng pag-drop ng mga filter sa mga subselect. Samakatuwid, ang bawat pagpipilian ay dapat na manu-manong na-filter ayon sa pangalan ng artist.

Ang Neptune ay may parehong oras-oras at per-I/O na mga singil. Para sa aming pagsubok, ginamit namin ang pinakamababang halimbawa ng Neptune, na nagkakahalaga ng $0,384/oras. Sa kaso ng query sa itaas, na kinakalkula ang profile para sa isang manggagawa, sinisingil kami ng Amazon ng libu-libong mga operasyon ng I/O, na nagpapahiwatig ng halagang $0.02.

Pagbubuhos

Una, pinapanatili ng Amazon Neptune ang karamihan sa mga pangako nito. Bilang isang pinamamahalaang serbisyo, ito ay isang graph database na napakadaling i-install at maaaring gumana nang walang maraming configuration. Narito ang aming limang pangunahing natuklasan:

  • Ang maramihang pag-upload ay madali ngunit mabagal. Ngunit maaari itong maging kumplikado sa mga mensahe ng error na hindi masyadong nakakatulong.
  • Sinusuportahan ng streaming download ang lahat ng inaasahan namin at medyo mabilis
  • Ang mga query ay simple, ngunit hindi sapat na interactive upang magpatakbo ng mga analytical na query
  • Ang mga query sa SPARQL ay dapat na i-optimize nang manu-mano
  • Ang mga pagbabayad sa Amazon ay mahirap tantiyahin dahil mahirap tantiyahin ang dami ng data na na-scan ng isang query sa SPARQL.

Iyon lang. Mag-sign up para sa libreng webinar sa paksang “Load Balancing”.


Pinagmulan: www.habr.com

Magdagdag ng komento