Erste Eindrücke von Amazon Neptun

Grüße, Einwohner von Chabrowsk. Im Vorgriff auf den Kursbeginn „AWS für Entwickler“ Wir haben eine Übersetzung interessanten Materials vorbereitet.

Erste Eindrücke von Amazon Neptun

In vielen Anwendungsfällen, die uns gefallen BakdatenWie wir auf den Websites unserer Kunden sehen, verbergen sich relevante Informationen in Verbindungen zwischen Entitäten, beispielsweise bei der Analyse von Beziehungen zwischen Benutzern, Abhängigkeiten zwischen Elementen oder Verbindungen zwischen Sensoren. Solche Anwendungsfälle werden normalerweise in einem Diagramm modelliert. Anfang des Jahres veröffentlichte Amazon seine neue Graphdatenbank Neptune. In diesem Beitrag möchten wir unsere ersten Ideen, bewährten Praktiken und das, was im Laufe der Zeit verbessert werden kann, teilen.

Warum wir Amazon Neptun brauchten

Graphdatenbanken versprechen, stark vernetzte Datensätze besser zu verarbeiten als ihre relationalen Äquivalente. In solchen Datensätzen werden relevante Informationen meist in Beziehungen zwischen Objekten gespeichert. Wir haben ein erstaunliches Open-Data-Projekt genutzt, um Neptune zu testen MusicBrainz. MusicBrainz sammelt alle erdenklichen Musik-Metadaten, etwa Informationen über Künstler, Songs, Albumveröffentlichungen oder Konzerte, aber auch darüber, mit wem der Künstler hinter dem Song zusammengearbeitet hat oder wann das Album in welchem ​​Land veröffentlicht wurde. MusicBrainz kann als ein riesiges Netzwerk von Einheiten betrachtet werden, die irgendwie mit der Musikindustrie verbunden sind.

Der MusicBrainz-Datensatz wird als CSV-Dump einer relationalen Datenbank bereitgestellt. Insgesamt enthält der Dump etwa 93 Millionen Zeilen in 157 Tabellen. Während einige dieser Tabellen grundlegende Daten wie Künstler, Ereignisse, Aufnahmen, Veröffentlichungen oder Titel enthalten, andere Verknüpfungstabellen – Speichern von Beziehungen zwischen Künstlern und Aufnahmen, anderen Künstlern oder Veröffentlichungen usw. Sie demonstrieren die Diagrammstruktur eines Datensatzes. Bei der Konvertierung des Datensatzes in RDF-Tripel haben wir etwa 500 Millionen Instanzen erhalten.

Basierend auf den Erfahrungen und Eindrücken der Projektpartner, mit denen wir zusammenarbeiten, stellen wir ein Setting vor, in dem diese Wissensbasis zur Gewinnung neuer Informationen genutzt wird. Darüber hinaus erwarten wir, dass es regelmäßig aktualisiert wird, beispielsweise durch das Hinzufügen neuer Releases oder die Aktualisierung von Gruppenmitgliedern.

Einstellung

Wie erwartet ist die Installation von Amazon Neptune einfach. Sie ist ziemlich detailliert dokumentiert. Sie können eine Diagrammdatenbank mit nur wenigen Klicks starten. Wenn es jedoch um eine detailliertere Konfiguration geht, notwendige Informationen schwer zu finden. Daher möchten wir auf einen Konfigurationsparameter verweisen.

Erste Eindrücke von Amazon Neptun
Konfigurations-Screenshot für Parametergruppen

Laut Amazon konzentriert sich Neptune auf Transaktions-Workloads mit geringer Latenz, weshalb das Standard-Anfrage-Timeout 120 Sekunden beträgt. Wir haben jedoch viele analytische Anwendungsfälle getestet, bei denen wir regelmäßig diese Grenze erreichten. Dieses Timeout kann geändert werden, indem eine neue Parametergruppe für Neptune erstellt und eingestellt wird neptune_query_timeout entsprechende Einschränkung.

Daten werden geladen

Im Folgenden besprechen wir ausführlich, wie wir MusicBrainz-Daten in Neptune geladen haben.

Beziehungen zu dritt

Zuerst haben wir die MusicBrainz-Daten in RDF-Tripel umgewandelt. Daher haben wir für jede Tabelle eine Vorlage definiert, die definiert, wie jede Spalte im Tripel dargestellt wird. In diesem Beispiel wird jede Zeile aus der Performer-Tabelle zwölf RDF-Triples zugeordnet.

<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> .

Massen-Upload

Die empfohlene Methode zum Laden großer Datenmengen in Neptune ist der Massen-Upload-Prozess über S3. Nachdem Sie Ihre Triples-Dateien in S3 hochgeladen haben, beginnen Sie den Upload mit einer POST-Anfrage. In unserem Fall dauerte es für 24 Millionen Drillinge etwa 500 Stunden. Wir haben erwartet, dass es schneller geht.

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

Um diesen langwierigen Prozess bei jedem Start von Neptune zu vermeiden, haben wir uns entschieden, die Instanz anhand eines Snapshots wiederherzustellen, in dem diese Triplets bereits geladen waren. Die Ausführung von einem Snapshot ist deutlich schneller, dauert aber dennoch etwa eine Stunde, bis Neptune für Anfragen verfügbar ist.

Beim ersten Laden von Tripletts in Neptune sind verschiedene Fehler aufgetreten.

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

Bei einigen davon handelte es sich um Analysefehler, wie oben gezeigt. Bis heute haben wir immer noch nicht herausgefunden, was genau zu diesem Zeitpunkt schief gelaufen ist. Ein bisschen mehr Details würden hier auf jeden Fall helfen. Dieser Fehler trat bei etwa 1 % der eingefügten Tripel auf. Aber was das Testen von Neptune angeht, haben wir die Tatsache akzeptiert, dass wir nur mit 99 % der Informationen von MusicBrainz arbeiten.

Auch wenn dies für Leute, die mit SPARQL vertraut sind, einfach ist, sollten Sie sich darüber im Klaren sein, dass RDF-Triples mit expliziten Datentypen annotiert werden müssen, was wiederum zu Fehlern führen kann.

Streaming-Download

Wie oben erwähnt, möchten wir Neptune nicht als statischen Datenspeicher nutzen, sondern vielmehr als flexible und sich weiterentwickelnde Wissensbasis. Wir mussten also Wege finden, neue Tripel einzuführen, wenn sich die Wissensbasis ändert, beispielsweise wenn ein neues Album veröffentlicht wird oder wenn wir abgeleitetes Wissen materialisieren wollen.

Neptune unterstützt Eingabeoperatoren durch SPARQL-Abfragen, sowohl roh als auch stichprobenbasiert. Wir werden im Folgenden beide Ansätze besprechen.

Eines unserer Ziele war die Dateneingabe im Streaming-Verfahren. Erwägen Sie die Veröffentlichung eines Albums in einem neuen Land. Aus Sicht von MusicBrainz bedeutet dies, dass für eine Veröffentlichung, die Alben, Singles, EPs usw. umfasst, ein neuer Eintrag zur Tabelle hinzugefügt wird Veröffentlichungsland. In RDF gleichen wir diese Informationen mit zwei neuen Tripeln ab.

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

Ein weiteres Ziel bestand darin, neue Erkenntnisse aus der Grafik zu gewinnen. Nehmen wir an, wir möchten die Anzahl der Veröffentlichungen ermitteln, die jeder Künstler im Laufe seiner Karriere veröffentlicht hat. Eine solche Abfrage ist recht komplex und dauert in Neptune über 20 Minuten. Daher müssen wir das Ergebnis materialisieren, um dieses neue Wissen in einer anderen Abfrage wiederverwenden zu können. Also fügen wir Tripel mit diesen Informationen wieder zum Diagramm hinzu und geben das Ergebnis der Unterabfrage ein.

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
 
}

Das Hinzufügen einzelner Tripel zum Diagramm dauert einige Millisekunden, während die Ausführungszeit für das Einfügen des Ergebnisses einer Unterabfrage von der Ausführungszeit der Unterabfrage selbst abhängt.

Obwohl wir es nicht oft verwendet haben, können Sie mit Neptune auch Tripletts basierend auf Stichproben oder expliziten Daten entfernen, die zum Aktualisieren von Informationen verwendet werden können.

SPARQL-Abfragen

Durch die Einführung der vorherigen Teilstichprobe, die die Anzahl der Veröffentlichungen für jeden Künstler zurückgibt, haben wir bereits den ersten Abfragetyp eingeführt, den wir mit Neptune beantworten möchten. Das Erstellen einer Abfrage in Neptune ist einfach: Senden Sie eine POST-Anfrage an den SPARQL-Endpunkt, wie unten gezeigt:

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

Darüber hinaus haben wir eine Abfrage implementiert, die ein Künstlerprofil mit Informationen zu Name, Alter oder Herkunftsland zurückgibt. Bedenken Sie, dass es sich bei den Darstellern um Einzelpersonen, Bands oder Orchester handeln kann. Darüber hinaus ergänzen wir diese Daten mit Informationen über die Anzahl der von Künstlern im Laufe des Jahres veröffentlichten Veröffentlichungen. Für Solokünstler fügen wir auch Informationen über die Bands hinzu, in denen der Künstler jedes Jahr mitwirkte.

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

Aufgrund der Komplexität einer solchen Abfrage konnten wir Punktabfragen nur für einen bestimmten Künstler, wie etwa Elton John, durchführen, aber nicht für alle Künstler. Neptune scheint eine solche Abfrage nicht zu optimieren, indem es Filter in Unterauswahlen ablegt. Daher muss jede Auswahl manuell nach Künstlernamen gefiltert werden.

Für Neptune fallen sowohl stündliche als auch pro I/O-Gebühren an. Für unsere Tests haben wir die absolute Neptune-Instanz verwendet, die 0,384 $/Stunde kostet. Im Fall der obigen Abfrage, die das Profil für einen einzelnen Mitarbeiter berechnet, berechnet Amazon uns Zehntausende von E/A-Vorgängen, was Kosten von 0.02 US-Dollar bedeutet.

Abschluss

Erstens hält Amazon Neptune die meisten seiner Versprechen. Als Managed Service handelt es sich um eine Graphdatenbank, die äußerst einfach zu installieren ist und ohne großen Konfigurationsaufwand betriebsbereit ist. Hier sind unsere fünf wichtigsten Erkenntnisse:

  • Der Massen-Upload ist einfach, aber langsam. Bei Fehlermeldungen, die nicht sehr hilfreich sind, kann es jedoch kompliziert werden.
  • Der Streaming-Download unterstützte alles, was wir erwartet hatten, und war recht schnell
  • Abfragen sind einfach, aber nicht interaktiv genug, um analytische Abfragen auszuführen
  • SPARQL-Abfragen müssen manuell optimiert werden
  • Amazon-Zahlungen sind schwer abzuschätzen, da es schwierig ist, die Menge der von einer SPARQL-Abfrage gescannten Daten abzuschätzen.

Das ist alles. Melden Sie sich an für kostenloses Webinar zum Thema „Load Balancing“.


Source: habr.com

Kommentar hinzufügen