Primeras impresiones de Amazon Neptune

Saludos, residentes de Khabrovsk. A la espera del inicio del curso "AWS para desarrolladores" Hemos preparado una traducción de material interesante.

Primeras impresiones de Amazon Neptune

En muchos casos de uso que nos gustan datos bakComo vemos en las webs de nuestros clientes, en las conexiones entre entidades se esconde información relevante, por ejemplo al analizar relaciones entre usuarios, dependencias entre elementos o conexiones entre sensores. Estos casos de uso suelen modelarse en un gráfico. A principios de este año, Amazon lanzó su nueva base de datos de gráficos, Neptune. En este post queremos compartir nuestras primeras ideas, buenas prácticas y lo que se puede mejorar con el tiempo.

Por qué necesitábamos Amazon Neptune

Las bases de datos de gráficos prometen manejar conjuntos de datos altamente conectados mejor que sus equivalentes relacionales. En tales conjuntos de datos, la información relevante generalmente se almacena en relaciones entre objetos. Usamos un increíble proyecto de datos abiertos para probar Neptune MusicBrainz. MusicBrainz recopila todo tipo de metadatos musicales imaginables, como información sobre artistas, canciones, lanzamientos de álbumes o conciertos, así como con quién colaboró ​​el artista detrás de la canción o cuándo se lanzó el álbum y en qué país. MusicBrainz puede verse como una enorme red de entidades que de alguna manera están conectadas con la industria de la música.

El conjunto de datos de MusicBrainz se proporciona como un volcado CSV de una base de datos relacional. En total, el volcado contiene alrededor de 93 millones de filas en 157 tablas. Si bien algunas de estas tablas contienen datos básicos como artistas, eventos, grabaciones, lanzamientos o pistas, otras tablas de enlaces — almacenar relaciones entre artistas y grabaciones, otros artistas o lanzamientos, etc... Demuestran la estructura gráfica de un conjunto de datos. Al convertir el conjunto de datos en triples RDF, obtuvimos aproximadamente 500 millones de instancias.

Basándonos en la experiencia y las impresiones de los socios del proyecto con los que trabajamos, presentamos un escenario en el que se utiliza esta base de conocimientos para obtener nueva información. Además, esperamos que se actualice periódicamente, por ejemplo agregando nuevas versiones o actualizando miembros del grupo.

Ajuste

Como era de esperar, instalar Amazon Neptune es sencillo. ella es bastante detallada documentado. Puede iniciar una base de datos de gráficos con solo unos pocos clics. Sin embargo, cuando se trata de una configuración más detallada, información necesaria Difícil de encontrar. Por tanto, queremos señalar un parámetro de configuración.

Primeras impresiones de Amazon Neptune
Captura de pantalla de configuración para grupos de parámetros

Amazon dice que Neptune se centra en cargas de trabajo transaccionales de baja latencia, razón por la cual el tiempo de espera de solicitud predeterminado es de 120 segundos. Sin embargo, hemos probado muchos casos de uso analítico en los que regularmente alcanzamos este límite. Este tiempo de espera se puede cambiar creando un nuevo grupo de parámetros para Neptune y configurando neptune_query_timeout restricción correspondiente.

Cargando datos

A continuación analizaremos en detalle cómo cargamos los datos de MusicBrainz en Neptune.

Relaciones en tres

Primero, convertimos los datos de MusicBrainz en triples RDF. Por lo tanto, para cada tabla, definimos una plantilla que define cómo se representa cada columna en el triplete. En este ejemplo, cada fila de la tabla de ejecutantes se asigna a doce tripletas 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> .

carga masiva

La forma sugerida de cargar grandes cantidades de datos en Neptune es mediante el proceso de carga masiva a través de S3. Después de cargar sus archivos triples en S3, comienza la carga mediante una solicitud POST. En nuestro caso, 24 millones de trillizos tardaron unas 500 horas. Esperábamos que fuera más rápido.

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

Para evitar este largo proceso cada vez que iniciamos Neptune, decidimos restaurar la instancia a partir de una instantánea en la que estos tripletes ya estaban cargados. Ejecutar desde una instantánea es significativamente más rápido, pero aún demora aproximadamente una hora hasta que Neptune esté disponible para solicitudes.

Al cargar inicialmente trillizos en Neptune, encontramos varios errores.

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

Algunos de ellos eran errores de análisis, como se muestra arriba. Hasta la fecha, todavía no hemos descubierto qué salió mal exactamente en este momento. Un poco más de detalle definitivamente ayudaría aquí. Este error ocurrió aproximadamente en el 1% de los triples insertados. Pero en lo que respecta a probar Neptune, aceptamos el hecho de que sólo trabajamos con el 99% de la información de MusicBrainz.

Aunque esto es fácil para las personas familiarizadas con SPARQL, tenga en cuenta que los tripletes RDF deben anotarse con tipos de datos explícitos, lo que nuevamente puede causar errores.

Descarga en streaming

Como se mencionó anteriormente, no queremos utilizar Neptune como un almacén de datos estático, sino como una base de conocimientos flexible y en evolución. Así que necesitábamos encontrar formas de introducir nuevos triples cuando cambia la base de conocimientos, por ejemplo cuando se publica un nuevo álbum o cuando queremos materializar el conocimiento derivado.

Neptune admite operadores de entrada a través de consultas SPARQL, tanto sin formato como basadas en muestras. Discutiremos ambos enfoques a continuación.

Uno de nuestros objetivos era introducir datos en forma de streaming. Considere lanzar un álbum en un nuevo país. Desde la perspectiva de MusicBrainz, esto significa que para un lanzamiento que incluye álbumes, sencillos, EP, etc., se agrega una nueva entrada a la tabla. país de lanzamiento. En RDF, comparamos esta información con dos nuevos triples.

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

Otro objetivo era obtener nuevos conocimientos a partir del gráfico. Digamos que queremos obtener la cantidad de lanzamientos que cada artista ha publicado en su carrera. Una consulta de este tipo es bastante compleja y tarda más de 20 minutos en Neptuno, por lo que necesitamos materializar el resultado para poder reutilizar este nuevo conocimiento en alguna otra consulta. Entonces agregamos tripletas con esta información nuevamente al gráfico, ingresando el resultado de la subconsulta.

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
 
}

Agregar triples simples al gráfico toma unos pocos milisegundos, mientras que el tiempo de ejecución para insertar el resultado de una subconsulta depende del tiempo de ejecución de la subconsulta misma.

Aunque no lo usamos con frecuencia, Neptune también le permite eliminar tripletes basados ​​en muestras o datos explícitos, que pueden usarse para actualizar información.

consultas SPARQL

Al presentar la submuestra anterior, que devuelve el número de lanzamientos de cada artista, ya hemos introducido el primer tipo de consulta que queremos responder usando Neptune. Crear una consulta en Neptune es fácil: envíe una solicitud POST al punto final SPARQL, como se muestra a continuación:

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

Además, hemos implementado una consulta que devuelve un perfil de artista que contiene información sobre su nombre, edad o país de origen. Tenga en cuenta que los intérpretes pueden ser individuos, bandas u orquestas. Además, complementamos estos datos con información sobre el número de lanzamientos lanzados por los artistas durante el año. Para artistas solistas, también agregamos información sobre las bandas en las que participó ese artista cada año.

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

Debido a la complejidad de dicha consulta, solo pudimos realizar consultas puntuales para un artista específico, como Elton John, pero no para todos los artistas. Neptune no parece optimizar dicha consulta colocando filtros en subselecciones. Por lo tanto, cada selección debe filtrarse manualmente por nombre de artista.

Neptune tiene cargos por hora y por E/S. Para nuestras pruebas, utilizamos la instancia mínima de Neptune, que cuesta 0,384 dólares por hora. En el caso de la consulta anterior, que calcula el perfil de un solo trabajador, Amazon nos cobra decenas de miles de operaciones de E/S, lo que implica un coste de 0.02 dólares.

conclusión

En primer lugar, Amazon Neptune cumple la mayoría de sus promesas. Como servicio administrado, es una base de datos gráfica que es extremadamente fácil de instalar y puede estar operativa sin mucha configuración. Aquí están nuestros cinco hallazgos clave:

  • La carga masiva es fácil pero lenta. Pero puede complicarse con mensajes de error que no son muy útiles.
  • La descarga en streaming es compatible con todo lo que esperábamos y fue bastante rápida.
  • Las consultas son simples, pero no lo suficientemente interactivas como para ejecutar consultas analíticas.
  • Las consultas SPARQL deben optimizarse manualmente
  • Los pagos de Amazon son difíciles de estimar porque es difícil estimar la cantidad de datos escaneados por una consulta SPARQL.

Eso es todo. Matricularse en seminario web gratuito sobre el tema "Equilibrio de carga".


Fuente: habr.com

Añadir un comentario