Réglage des requêtes Gremlin à l'aide deexplainetprofile - Amazon Neptune

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Réglage des requêtes Gremlin à l'aide deexplainetprofile

Vous pouvez souvent ajuster vos requêtes Gremlin dans Amazon Neptune pour obtenir de meilleures performances, en utilisant les informations mises à votre disposition dans les rapports que vous recevez de NeptuneexpliqueretprofilAPIs. Pour ce faire, il est utile de comprendre comment Neptune traite les traversées de Gremlin.

Important

Un changement a été apporté dans TinkerPop version 3.4.11 qui améliore l'exactitude du traitement des requêtes, mais qui peut parfois avoir un impact sérieux sur les performances des requêtes pour le moment.

Par exemple, une requête de ce type peut s'exécuter beaucoup plus lentement :

g.V().hasLabel('airport'). order(). by(out().count(),desc). limit(10). out()

Les sommets après l'étape limite sont désormais récupérés de manière non optimale en raison de TinkerPop 3.4.11 modification. Pour éviter cela, vous pouvez modifier la requête en ajoutant l'étape barrier () à tout moment aprèsorder().by(). Par exemple :

g.V().hasLabel('airport'). order(). by(out().count(),desc). limit(10). barrier(). out()

TinkerPop 3.4.11 a été activé dans Neptuneversion du moteur 1.0.5.0.

Comprendre le traitement de traversée de Gremlin dans Neptune

Lorsqu'une traversée Gremlin est envoyée à Neptune, trois processus principaux transforment la traversée en un plan d'exécution sous-jacent à exécuter par le moteur. Il s'agit de l'analyse, de la conversion et de l'optimisation :

3 processus transforment une requête Gremlin en plan d'exécution.

Le processus d'analyse transversale

La première étape du traitement d'une traversée consiste à l'analyser dans un langage commun. Dans Neptune, ce langage commun est l'ensemble de TinkerPop les étapes qui font partie duTinkerPopAPI. Chacune de ces étapes représente une unité de calcul au sein de la traversée.

Vous pouvez envoyer une traversée de Gremlin à Neptune sous forme de chaîne ou de bytecode. Le point de terminaison REST et le pilote du client Javasubmit()méthode envoie des traversées sous forme de chaînes, comme dans cet exemple :

client.submit("g.V()")

Applications et pilotes de langage utilisantVariantes du langage Gremlin (GLV)envoyer des traversées en bytecode.

Le processus de conversion transversale

La deuxième étape du traitement d'une traversée consiste à convertir sa TinkerPop étapes d'un ensemble d'étapes Neptune converties et non converties. La plupart des étapes de l'Apache TinkerPop Les langages de requête Gremlin sont convertis en étapes spécifiques à Neptune optimisées pour s'exécuter sur le moteur Neptune sous-jacent. Lorsque un TinkerPop Une étape sans équivalent de Neptune est rencontrée dans une traversée, cette étape et toutes les étapes suivantes de la traversée sont traitées par le TinkerPop moteur de requête.

Pour plus d'informations sur les étapes pouvant être converties dans les circonstances, consultezMarchepied Gremlin.

Le processus d'optimisation de la traversée

La dernière étape du traitement transversal consiste à exécuter la série d'étapes converties et non converties via l'optimiseur, afin de déterminer le meilleur plan d'exécution. Le résultat de cette optimisation est le plan d'exécution traité par le moteur Neptune.

Utiliser le Neptune GremlinexplainAPI pour régler les requêtes

L'API d'explication de Neptune n'est pas la même que celle de Gremlinexplain()Étape. Il renvoie le plan d'exécution final que le moteur Neptune traiterait lors de l'exécution de la requête. Comme il n'effectue aucun traitement, il renvoie le même plan quels que soient les paramètres utilisés, et sa sortie ne contient aucune statistique sur l'exécution réelle.

Envisagez la traversée simple suivante qui permet de trouver tous les sommets de l'aéroport d'Anchorage :

g.V().has('code','ANC')

Vous pouvez effectuer cette traversée à travers le Neptune de deux manières.explainAPI. La première méthode consiste à effectuer un appel REST vers le point de terminaison d'explication, comme suit :

curl -X POST https://your-neptune-endpoint:port/gremlin/explain -d '{"gremlin":"g.V().has('code','ANC')"}'

La deuxième méthode consiste à utiliser l'établi Neptune%%Gremlinmagie cellulaire avecexplainparamètre. Cela fait passer la traversée contenue dans le corps cellulaire vers le Neptune.explainAPI, puis affiche la sortie résultante lorsque vous exécutez la cellule :

%%gremlin explain g.V().has('code','ANC')

Le résultatexplainLa sortie de l'API décrit le plan d'exécution de Neptune pour la traversée. Comme vous pouvez le voir sur l'image ci-dessous, le plan inclut chacune des 3 étapes du pipeline de traitement :

Expliquez la sortie de l'API pour une traversée simple de Gremlin.

Réglage d'une traversée en examinant les étapes qui ne sont pas converties

L'une des premières choses à rechercher dans le NeptuneexplainLa sortie de l'API concerne les étapes Gremlin qui ne sont pas converties en étapes natives de Neptune. Dans un plan de requête, lorsqu'une étape est rencontrée qui ne peut pas être convertie en étape native de Neptune, elle et toutes les étapes suivantes du plan sont traitées par le serveur Gremlin.

Dans l'exemple ci-dessus, toutes les étapes de la traversée ont été converties. ExaminonsexplainSortie de l'API pour cette traversée :

g.V().has('code','ANC').out().choose(hasLabel('airport'), values('code'), constant('Not an airport'))

Comme vous pouvez le voir dans l'image ci-dessous, Neptune n'a pas pu convertir lechoose()Étape :

Expliquez la sortie de l'API dans laquelle toutes les étapes ne peuvent pas être converties.

Il y a plusieurs choses que vous pouvez faire pour ajuster les performances de la traversée. La première serait de le réécrire de manière à éliminer l'étape qui n'a pas pu être convertie. Une autre solution serait de déplacer l'étape jusqu'à la fin de la traversée afin que toutes les autres étapes puissent être converties en étapes natives.

Un plan de requêtes dont les étapes ne sont pas converties n'a pas toujours besoin d'être ajusté. Si les étapes qui ne peuvent pas être converties se situent à la fin de la traversée et sont liées à la mise en forme de la sortie plutôt qu'à la manière dont le graphe est parcouru, elles peuvent avoir peu d'effet sur les performances.

Autre élément à rechercher lors de l'examen de la sortie du NeptuneexplainLes API sont des étapes qui n'utilisent pas d'index. La liste suivante permet de trouver tous les aéroports dont les vols atterrissent à Anchorage :

g.V().has('code','ANC').in().values('code')

La sortie de l'API d'explication pour cette traversée est la suivante :

******************************************************* Neptune Gremlin Explain ******************************************************* Query String ============ g.V().has('code','ANC').in().values('code') Original Traversal ================== [GraphStep(vertex,[]), HasStep([code.eq(ANC)]), VertexStep(IN,vertex), PropertiesStep([code],value)] Converted Traversal =================== Neptune steps: [ NeptuneGraphQueryStep(PropertyValue) { JoinGroupNode { PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .] PatternNode[(?1, <code>, "ANC", ?) . project ask .] PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .] PatternNode[(?3, <~label>, ?4, <~>) . project ask .] PatternNode[(?3, ?7, ?8, <~>) . project ?3,?8 . ContainsFilter(?7 in (<code>)) .] }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep, PropertyValue(?8):PropertiesStep], maxVarId=9} }, NeptuneTraverserConverterStep ] Optimized Traversal =================== Neptune steps: [ NeptuneGraphQueryStep(PropertyValue) { JoinGroupNode { PatternNode[(?1, <code>, "ANC", ?) . project ?1 .], {estimatedCardinality=1} PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .], {estimatedCardinality=INFINITY} PatternNode[(?3, ?7=<code>, ?8, <~>) . project ?3,?8 .], {estimatedCardinality=7564} }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep, PropertyValue(?8):PropertiesStep], maxVarId=9} }, NeptuneTraverserConverterStep ] Predicates ========== # of predicates: 26 WARNING: reverse traversal with no edge label(s) - .in() / .both() may impact query performance

Dans laWARNINGun message au bas de la sortie s'affiche parce quein()Une étape de la traversée ne peut pas être gérée à l'aide de l'un des 3 index gérés par Neptune (voirComment les relevés sont indexés dans NeptuneetDéclarations de Gremlin dans Neptune). Parce quein()l'étape ne contient aucun filtre de bord, elle ne peut pas être résolue à l'aide duSPOG,POGSouGPSOindex. Neptune doit plutôt effectuer un scan syndical pour trouver les sommets demandés, ce qui est beaucoup moins efficace.

Il existe deux façons d'ajuster la traversée dans ce cas. La première consiste à ajouter un ou plusieurs critères de filtrage à lain()étape permettant d'utiliser une recherche indexée pour résoudre la requête. Pour l'exemple ci-dessus, cela peut être :

g.V().has('code','ANC').in('route').values('code')

Données de sortie du NeptuneexplainL'API pour la traversée révisée ne contient plusWARNINGMessage :

******************************************************* Neptune Gremlin Explain ******************************************************* Query String ============ g.V().has('code','ANC').in('route').values('code') Original Traversal ================== [GraphStep(vertex,[]), HasStep([code.eq(ANC)]), VertexStep(IN,[route],vertex), PropertiesStep([code],value)] Converted Traversal =================== Neptune steps: [ NeptuneGraphQueryStep(PropertyValue) { JoinGroupNode { PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .] PatternNode[(?1, <code>, "ANC", ?) . project ask .] PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) . ContainsFilter(?5 in (<route>)) .] PatternNode[(?3, <~label>, ?4, <~>) . project ask .] PatternNode[(?3, ?7, ?8, <~>) . project ?3,?8 . ContainsFilter(?7 in (<code>)) .] }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep, PropertyValue(?8):PropertiesStep], maxVarId=9} }, NeptuneTraverserConverterStep ] Optimized Traversal =================== Neptune steps: [ NeptuneGraphQueryStep(PropertyValue) { JoinGroupNode { PatternNode[(?1, <code>, "ANC", ?) . project ?1 .], {estimatedCardinality=1} PatternNode[(?3, ?5=<route>, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .], {estimatedCardinality=32042} PatternNode[(?3, ?7=<code>, ?8, <~>) . project ?3,?8 .], {estimatedCardinality=7564} }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep, PropertyValue(?8):PropertiesStep], maxVarId=9} }, NeptuneTraverserConverterStep ] Predicates ========== # of predicates: 26

Une autre option, si vous exécutez de nombreuses traverses de ce type, consiste à les exécuter dans un cluster de base de données Neptune qui possède l'optionOSGPindex activé (voirActivation d'un index OSGP). Activation d'uneOSGPl'indice présente des inconvénients :

  • Il doit être activé dans un cluster de base de données avant tout chargement de données.

  • Les taux d'insertion pour les sommets et les arêtes peuvent ralentir jusqu'à 23 %.

  • L'utilisation du stockage augmentera d'environ 20 %.

  • Les requêtes de lecture qui dispersent les requêtes dans tous les index peuvent avoir des latences accrues.

Disposer d'unOSGPindex est très logique pour un ensemble restreint de modèles de requêtes, mais à moins que vous ne les exécutiez fréquemment, il est généralement préférable d'essayer de vous assurer que les traversées que vous écrivez peuvent être résolues à l'aide des trois index principaux.

Utilisation d'un grand nombre de prédicats

Neptune traite chaque étiquette d'arête et chaque vertex ou nom de propriété d'arête distinct de votre graphe comme un prédicat, et est conçu par défaut pour fonctionner avec un nombre relativement faible de prédicats distincts. Lorsque vos données graphiques contiennent plus de quelques milliers de prédicats, les performances peuvent se dégrader.

Neptuneexplainoutput vous avertira si c'est le cas :

Predicates ========== # of predicates: 9549 WARNING: high predicate count (# of distinct property names and edge labels)

S'il n'est pas pratique de retravailler votre modèle de données pour réduire le nombre d'étiquettes et de propriétés, et donc le nombre de prédicats, le meilleur moyen d'ajuster les traversées est de les exécuter dans un cluster de base de données qui possèdeOSGPindex activé, comme indiqué ci-dessus.

Utiliser le Neptune GremlinprofileAPI pour régler les traversées

Le NeptuneprofileL'API est très différente de celle du Gremlinprofile()Étape. Comme leexplainAPI, sa sortie inclut le plan de requête que le moteur Neptune utilise lors de l'exécution de la traversée. Par ailleurs,profilela sortie inclut les statistiques d'exécution réelles pour la traversée, en fonction de la façon dont ses paramètres sont définis.

Encore une fois, empruntez la simple traversée qui permet de trouver tous les sommets de l'aéroport d'Anchorage :

g.V().has('code','ANC')

Comme dans le cas duexplainAPI, vous pouvez appelerprofileAPI utilisant un appel REST :

curl -X POST https://your-neptune-endpoint:port/gremlin/profile -d '{"gremlin":"g.V().has('code','ANC')"}'

Vous utilisez également l'établi Neptune%%Gremlinmagie cellulaire avecprofileparamètre. Cela fait passer la traversée contenue dans le corps cellulaire vers le Neptune.profileAPI, puis affiche la sortie résultante lorsque vous exécutez la cellule :

%%gremlin profile g.V().has('code','ANC')

Le résultatprofileLa sortie de l'API contient à la fois le plan d'exécution de Neptune pour la traversée et des statistiques concernant l'exécution du plan, comme vous pouvez le voir sur cette image :

Un exemple de NeptuneprofileSortie de l'API.

Dansprofilesortie, la section du plan d'exécution contient uniquement le plan d'exécution final pour la traversée, et non les étapes intermédiaires. La section du pipeline contient les opérations physiques du pipeline qui ont été effectuées ainsi que le temps réel (en millisecondes) qu'a duré l'exécution de la traversée. La métrique d'exécution est extrêmement utile pour comparer les temps que prennent deux versions différentes d'une traversée lors de leur optimisation.

Note

Le temps d'exécution initial d'une traversée est généralement plus long que les environnements d'exécution suivants, car le premier entraîne la mise en cache des données pertinentes.

La troisième section duprofileLa sortie contient les statistiques d'exécution et les résultats de la traversée. Pour voir comment ces informations peuvent être utiles pour régler une traversée, pensez à la traversée suivante, qui permet de trouver tous les aéroports dont le nom commence par « Anchora » et tous les aéroports accessibles en deux sauts depuis ces aéroports, en renvoyant les codes d'aéroport, les itinéraires de vol et les distances :

%%gremlin profile g.withSideEffect("Neptune#fts.endpoint", "{your-OpenSearch-endpoint-URL"). V().has("city", "Neptune#fts Anchora~"). repeat(outE('route').inV().simplePath()).times(2). project('Destination', 'Route'). by('code'). by(path().by('code').by('dist'))

Métriques de traversée dans NeptuneprofileSortie d'API

Le premier ensemble de mesures disponible dans tousprofilela sortie est la métrique de traversée. Ils sont similaires au Gremlinprofile()mesures des étapes, avec quelques différences :

Traversal Metrics ================= Step Count Traversers Time (ms) % Dur ------------------------------------------------------------------------------------------------------------- NeptuneGraphQueryStep(Vertex) 3856 3856 91.701 9.09 NeptuneTraverserConverterStep 3856 3856 38.787 3.84 ProjectStep([Destination, Route],[value(code), ... 3856 3856 878.786 87.07 PathStep([value(code), value(dist)]) 3856 3856 601.359 >TOTAL - - 1009.274 -

La première colonne du tableau des métriques de traversée répertorie les étapes exécutées par la traversée. Les deux premières étapes sont généralement les étapes spécifiques à Neptune,NeptuneGraphQueryStepetNeptuneTraverserConverterStep.

NeptuneGraphQueryStepreprésente le temps d'exécution pour toute la partie de la traversée qui pourrait être convertie et exécutée nativement par le moteur Neptune.

NeptuneTraverserConverterStepreprésente le processus de conversion de la sortie de ces étapes converties en TinkerPop traverseurs qui permettent de traiter des étapes qui n'ont pas pu être converties, le cas échéant, ou de renvoyer les résultats dans un TinkerPop-format compatible.

Dans l'exemple ci-dessus, nous avons plusieurs étapes non converties, nous voyons donc que chacune d'entre elles TinkerPop Étapes (ProjectStep,PathStep) apparaît ensuite sous forme de ligne dans le tableau.

La deuxième colonne du tableau,Count, indique le nombre dereprésentéeles traverseurs qui ont franchi l'étape, tandis que la troisième colonne,Traversers, indique le nombre de traverseurs qui sont passés par cette étape, comme expliqué dansTinkerPopdocumentation des étapes du profil.

Dans notre exemple, 3 856 sommets et 3 856 traverseurs sont renvoyés parNeptuneGraphQueryStep, et ces chiffres restent les mêmes tout au long du traitement carProjectStepetPathStepmettent en forme les résultats et ne les filtrent pas.

Note

Contrairement à TinkerPop, le moteur Neptune n'optimise pas les performances engonflementdans sonNeptuneGraphQueryStepetNeptuneTraverserConverterStepÉtapes. Le groupage est le TinkerPopopération qui combine des traverseurs sur le même sommet afin de réduire les frais d'exploitation, et c'est ce qui causeCountetTraversersdes chiffres à différer. Parce que le groupage ne se produit que par étapes déléguées à Neptune TinkerPop, et non selon des étapes que Neptune gère de manière native, leCountetTraverserles colonnes diffèrent rarement.

La colonne Heure indique le nombre de millisecondes que l'étape a duré, et le% DurLa colonne indique le pourcentage du temps de traitement total que l'étape a pris. Ce sont les indicateurs qui vous indiquent où concentrer vos efforts de réglage en indiquant les étapes qui ont pris le plus de temps.

Indicez les métriques des opérations dans NeptuneprofileSortie d'API

Les opérations d'indexation constituent un autre ensemble de mesures figurant dans la sortie de l'API de profil Neptune :

Index Operations ================ Query execution: # of statement index ops: 23191 # of unique statement index ops: 5960 Duplication ratio: 3.89 # of terms materialized: 0

Ces rapports :

  • Nombre total de recherches d'index.

  • Nombre de recherches d'index uniques effectuées.

  • Le ratio entre le nombre total de recherches d'index et les recherches uniques. Un ratio plus faible indique moins de redondance.

  • Le nombre de termes matérialisés à partir du dictionnaire des termes.

Répéter les mesures dans NeptuneprofileSortie d'API

Si votre traversée utilise unrepeat()étape comme dans l'exemple ci-dessus, puis une section contenant des mesures de répétition apparaît dansprofileFile d'attente :

Repeat Metrics ============== Iteration Visited Output Until Emit Next ------------------------------------------------------ 0 2 0 0 0 2 1 53 0 0 0 53 2 3856 3856 3856 0 0 ------------------------------------------------------ 3911 3856 3856 0 55

Ces rapports :

  • Le nombre de boucles pour une ligne (leIterationColonne).

  • Le nombre d'éléments visités par la boucle (VisitedColonne).

  • Le nombre d'éléments produits par la boucle (OutputColonne).

  • Le dernier élément produit par la boucle (UntilColonne).

  • Le nombre d'éléments émis par la boucle (EmitColonne).

  • Le nombre d'éléments passés de la boucle à la boucle suivante (leNextColonne).

Ces mesures de répétition sont très utiles pour comprendre le facteur de ramification de votre traversée, afin d'avoir une idée de la quantité de travail effectuée par la base de données. Vous pouvez utiliser ces chiffres pour diagnostiquer les problèmes de performances, en particulier lorsqu'une même traversée fonctionne de manière radicalement différente selon les différents paramètres.

Statistiques de recherche en texte intégral dans NeptuneprofileSortie d'API

Lorsqu'une traversée utilise unRecherche en texte intégralsearch, comme dans l'exemple ci-dessus, une section contenant les métriques de la recherche de texte intégral (FTS) apparaît dansprofileFile d'attente :

FTS Metrics ============== SearchNode[(idVar=?1, query=Anchora~, field=city) . project ?1 .], {endpoint=your-OpenSearch-endpoint-URL, incomingSolutionsThreshold=1000, estimatedCardinality=INFINITY, remoteCallTimeSummary=[total=65, avg=32.500000, max=37, min=28], remoteCallTime=65, remoteCalls=2, joinTime=0, indexTime=0, remoteResults=2} 2 result(s) produced from SearchNode above

Cela montre la requête envoyée au ElasticSearch (ES) et rapporte plusieurs mesures concernant l'interaction avec ElasticSearch qui peuvent vous aider à identifier les problèmes de performances liés à la recherche en texte intégral :

  • Informations récapitulatives sur les appels au ElasticSearch Indice :

    • Le nombre total de millisecondes nécessaires à tous les appels à distance pour répondre à la requête (total).

    • Le nombre moyen de millisecondes passées dans un RemoteCall (avg).

    • Le nombre minimum de millisecondes passées dans un RemoteCall (min).

    • Le nombre maximum de millisecondes passées dans un RemoteCall (max).

  • Temps total consommé par RemoteCalls pour ElasticSearch (remoteCallTime).

  • Le nombre d'appels à distance effectués vers ElasticSearch (remoteCalls).

  • Le nombre de millisecondes passées en jointures de ElasticSearch résultats (joinTime).

  • Le nombre de millisecondes consacrées aux recherches d'index (indexTime).

  • Nombre total de résultats renvoyés par ElasticSearch (remoteResults).