První dojmy z Amazon Neptun

Zdravím obyvatele Chabrovska. V očekávání začátku kurzu "AWS pro vývojáře" Připravili jsme překlad zajímavého materiálu.

První dojmy z Amazon Neptun

V mnoha případech použití, které se nám líbí bakdataJak vidíme na webových stránkách našich klientů, relevantní informace se skrývají ve spojeních mezi entitami, například při analýze vztahů mezi uživateli, závislostí mezi prvky nebo propojení mezi senzory. Takové případy použití jsou obvykle modelovány v grafu. Začátkem tohoto roku Amazon vydal svou novou grafickou databázi Neptun. V tomto příspěvku se chceme podělit o naše první nápady, osvědčené postupy a co lze časem zlepšit.

Proč jsme potřebovali Amazon Neptun

Grafové databáze slibují, že zpracují vysoce propojené datové sady lépe než jejich relační ekvivalenty. V takovýchto souborech dat jsou relevantní informace obvykle uloženy ve vztazích mezi objekty. K testování Neptunu jsme použili úžasný projekt otevřených dat MusicBrainz. MusicBrainz shromažďuje všechny možné hudební metadata, jako jsou informace o interpretech, skladbách, vydáních alb nebo koncertech, stejně jako o tom, s kým interpret za skladbou spolupracoval nebo kdy bylo album vydáno ve které zemi. MusicBrainz lze vnímat jako obrovskou síť subjektů, které jsou nějakým způsobem propojeny s hudebním průmyslem.

Datová sada MusicBrainz je poskytována jako výpis CSV relační databáze. Celkem výpis obsahuje asi 93 milionů řádků ve 157 tabulkách. Zatímco některé z těchto tabulek obsahují základní údaje, jako jsou umělci, události, nahrávky, vydání nebo skladby, jiné odkazové tabulky — ukládat vztahy mezi umělci a nahrávkami, jinými umělci nebo nahrávkami atd... Demonstrují grafovou strukturu souboru dat. Při převodu datové sady na trojice RDF jsme získali přibližně 500 milionů instancí.

Na základě zkušeností a dojmů partnerů projektu, se kterými spolupracujeme, představujeme prostředí, ve kterém je tato znalostní báze využívána k získávání nových informací. Navíc očekáváme, že bude pravidelně aktualizován, například přidáváním nových vydání nebo aktualizací členů skupiny.

Nastavení

Jak se očekávalo, instalace Amazon Neptune je jednoduchá. Je docela detailní zdokumentováno. Databázi grafů můžete spustit několika kliknutími. Pokud však jde o podrobnější konfiguraci, nezbytné informace těžké najít. Proto chceme poukázat na jeden konfigurační parametr.

První dojmy z Amazon Neptun
Snímek obrazovky konfigurace pro skupiny parametrů

Amazon říká, že Neptune se zaměřuje na transakční pracovní zátěže s nízkou latencí, a proto je výchozí časový limit požadavku 120 sekund. Testovali jsme však mnoho případů analytického použití, ve kterých jsme pravidelně dosahovali tohoto limitu. Tento časový limit lze změnit vytvořením nové skupiny parametrů pro Neptun a nastavením neptune_query_timeout odpovídající omezení.

Načítání dat

Níže podrobně probereme, jak jsme nahráli data MusicBrainz do Neptunu.

Vztahy ve třech

Nejprve jsme převedli data MusicBrainz na trojice RDF. Proto jsme pro každou tabulku definovali šablonu, která definuje, jak je každý sloupec reprezentován v trojici. V tomto příkladu je každý řádek z tabulky interpretů mapován na dvanáct trojic 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> .

hromadné nahrání

Navrhovaný způsob, jak načíst velké množství dat do Neptunu, je proces hromadného nahrávání přes S3. Po nahrání vašich trojitých souborů do S3 zahájíte nahrávání pomocí požadavku POST. V našem případě to trvalo asi 24 hodin pro 500 milionů trojčat. Čekali jsme, že to bude rychlejší.

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

Abychom se vyhnuli tomuto zdlouhavému procesu při každém spuštění Neptunu, rozhodli jsme se obnovit instanci ze snímku, ve kterém již byly tyto trojice načteny. Spouštění ze snímku je výrazně rychlejší, ale stále trvá asi hodinu, než bude Neptun dostupný pro požadavky.

Při prvotním načítání trojic do Neptunu jsme narazili na různé chyby.

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

Některé z nich byly chyby analýzy, jak je uvedeno výše. Dodnes jsme stále nepřišli na to, co přesně se v tuto chvíli pokazilo. Tady by určitě pomohlo trochu více detailů. Tato chyba se vyskytla u přibližně 1 % vložených trojic. Ale pokud jde o testování Neptunu, přijali jsme fakt, že pracujeme pouze s 99 % informací z MusicBrainz.

I když je to pro lidi obeznámené se SPARQL snadné, uvědomte si, že trojice RDF musí být anotovány explicitními datovými typy, což opět může způsobit chyby.

Streamování ke stažení

Jak již bylo zmíněno výše, nechceme Neptun používat jako statické úložiště dat, ale spíše jako flexibilní a vyvíjející se znalostní základnu. Potřebovali jsme tedy najít způsoby, jak zavést nové trojky, když se mění znalostní báze, například když vychází nové album nebo když chceme zhmotnit odvozené znalosti.

Neptune podporuje vstupní operátory prostřednictvím dotazů SPARQL, a to jak nezpracovaných, tak založených na vzorcích. Oba přístupy probereme níže.

Jedním z našich cílů bylo zadávat data streamovaným způsobem. Zvažte vydání alba v nové zemi. Z pohledu MusicBrainz to znamená, že u vydání, které obsahuje alba, singly, EP atd., je do tabulky přidána nová položka vydání-země. V RDF tyto informace porovnáváme se dvěma novými trojicemi.

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

Dalším cílem bylo získat nové poznatky z grafu. Řekněme, že chceme získat počet releasů, které každý umělec publikoval ve své kariéře. Takový dotaz je poměrně složitý a v Neptunu zabere přes 20 minut, takže musíme výsledek zhmotnit, abychom mohli znovu použít tyto nové znalosti v nějakém jiném dotazu. Trojice s touto informací tedy přidáme zpět do grafu a zadáme výsledek dílčího dotazu.

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
 
}

Přidání jednotlivých trojic do grafu trvá několik milisekund, zatímco doba provádění pro vložení výsledku dílčího dotazu závisí na době provádění samotného dílčího dotazu.

Ačkoli jsme to nepoužívali často, Neptun vám také umožňuje odstranit trojice na základě vzorků nebo explicitních dat, která lze použít k aktualizaci informací.

SPARQL dotazy

Představením předchozí dílčí ukázky, která vrací počet vydání pro každého umělce, jsme již zavedli první typ dotazu, na který chceme odpovědět pomocí Neptunu. Vytvoření dotazu v Neptunu je snadné – odešlete požadavek POST do koncového bodu SPARQL, jak je znázorněno níže:

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

Navíc jsme implementovali dotaz, který vrací profil interpreta obsahující informace o jeho jménu, věku nebo zemi původu. Mějte na paměti, že účinkujícími mohou být jednotlivci, kapely nebo orchestry. Tyto údaje navíc doplňujeme o informace o počtu releasů vydaných umělci během roku. Pro sólové umělce také přidáváme informace o kapelách, kterých se umělec každý rok účastnil.

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

Kvůli složitosti takového dotazu jsme mohli provádět bodové dotazy pouze pro konkrétního umělce, jako je Elton John, ale ne pro všechny umělce. Nezdá se, že by Neptun optimalizoval takový dotaz přehazováním filtrů do dílčích výběrů. Proto musí být každý výběr ručně filtrován podle jména interpreta.

Neptun má jak hodinové poplatky, tak poplatky za I/O. Pro naše testování jsme použili holé minimum instance Neptunu, která stojí 0,384 $/hod. V případě výše uvedeného dotazu, který vypočítává profil pro jednoho pracovníka, nám Amazon účtuje desítky tisíc I/O operací, což znamená cenu 0.02 USD.

Výkon

Za prvé, Amazon Neptune dodržuje většinu svých slibů. Jako spravovaná služba se jedná o grafovou databázi, která se extrémně snadno instaluje a může být spuštěna bez velkého množství konfigurace. Zde je našich pět klíčových zjištění:

  • Hromadné nahrávání je snadné, ale pomalé. Může se to ale zkomplikovat chybovými zprávami, které nejsou příliš užitečné.
  • Streamování podporuje vše, co jsme očekávali, a bylo poměrně rychlé
  • Dotazy jsou jednoduché, ale nejsou dostatečně interaktivní, aby spouštěly analytické dotazy
  • Dotazy SPARQL je nutné optimalizovat ručně
  • Platby Amazonu je obtížné odhadnout, protože je obtížné odhadnout množství dat naskenovaných dotazem SPARQL.

To je vše. Přihlásit se bezplatný webinář na téma „Vyrovnávání zátěže“.


Zdroj: www.habr.com

Přidat komentář