Guide pratique pour utiliser l’étape de profil d’exécution pour évaluer vos requêtes GremlinHow to use the execution profile step to evaluate your Gremlin queries

Cet article fournit une vue d’ensemble de l’utilisation de l’étape de profil d’exécution pour les bases de données de graphe d’API Gremlin Azure Cosmos DB.This article provides an overview of how to use the execution profile step for Azure Cosmos DB Gremlin API graph databases. Cette étape fournit des informations pertinentes sur la résolution des problèmes et l’optimisation des requêtes. Elle est compatible avec n’importe quelle requête Gremlin pouvant être exécutée sur un compte d’API Gremlin Cosmos DB.This step provides relevant information for troubleshooting and query optimizations, and it is compatible with any Gremlin query that can be executed against a Cosmos DB Gremlin API account.

Pour utiliser cette étape, ajoutez simplement l’appel de fonction executionProfile() à la fin de votre requête Gremlin.To use this step, simply append the executionProfile() function call at the end of your Gremlin query. Votre requête Gremlin sera exécutée et le résultat de l’opération retournera un objet de réponse JSON avec le profil d’exécution de requête.Your Gremlin query will be executed and the result of the operation will return a JSON response object with the query execution profile.

Par exemple :For example:

    // Basic traversal
    g.V('mary').out()

    // Basic traversal with execution profile call
    g.V('mary').out().executionProfile()

Après l’appel de l’étape executionProfile(), la réponse est un objet JSON qui comprend l’étape Gremlin exécutée, la durée totale nécessaire et un tableau des opérateurs de runtime Cosmos DB générés par l’instruction.After calling the executionProfile() step, the response will be a JSON object that includes the executed Gremlin step, the total time it took, and an array of the Cosmos DB runtime operators that the statement resulted in.

Notes

Cette implémentation pour le profil d’exécution n’est pas définie dans la spécification Apache Tinkerpop.This implementation for Execution Profile is not defined in the Apache Tinkerpop specification. Elle est propre à l’implémentation de l’API Gremlin Azure Cosmos DB.It is specific to Azure Cosmos DB Gremlin API's implementation.

Exemple de réponseResponse Example

Voici un exemple annoté de sortie retournée :The following is an annotated example of the output that will be returned:

Notes

Cet exemple est annoté avec des commentaires qui expliquent la structure générale de la réponse.This example is annotated with comments that explain the general structure of the response. Une réponse executionProfile réelle ne contiendra aucun commentaire.An actual executionProfile response won't contain any comments.

[
  {
    // The Gremlin statement that was executed.
    "gremlin": "g.V('mary').out().executionProfile()",

    // Amount of time in milliseconds that the entire operation took.
    "totalTime": 28,

    // An array containing metrics for each of the steps that were executed. 
    // Each Gremlin step will translate to one or more of these steps.
    // This list is sorted in order of execution.
    "metrics": [
      {
        // This operation obtains a set of Vertex objects.
        // The metrics include: time, percentTime of total execution time, resultCount, 
        // fanoutFactor, count, size (in bytes) and time.
        "name": "GetVertices",
        "time": 24,
        "annotations": {
          "percentTime": 85.71
        },
        "counts": {
          "resultCount": 2
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 2,
            "size": 696,
            "time": 0.4
          }
        ]
      },
      {
        // This operation obtains a set of Edge objects. 
        // Depending on the query, these might be directly adjacent to a set of vertices, 
        // or separate, in the case of an E() query.
        //
        // The metrics include: time, percentTime of total execution time, resultCount, 
        // fanoutFactor, count, size (in bytes) and time.
        "name": "GetEdges",
        "time": 4,
        "annotations": {
          "percentTime": 14.29
        },
        "counts": {
          "resultCount": 1
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 1,
            "size": 419,
            "time": 0.67
          }
        ]
      },
      {
        // This operation obtains the vertices that a set of edges point at.
        // The metrics include: time, percentTime of total execution time and resultCount.
        "name": "GetNeighborVertices",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 1
        }
      },
      {
        // This operation represents the serialization and preparation for a result from 
        // the preceding graph operations. The metrics include: time, percentTime of total 
        // execution time and resultCount.
        "name": "ProjectOperator",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 1
        }
      }
    ]
  }
]

Notes

L’étape executionProfile exécute la requête Gremlin.The executionProfile step will execute the Gremlin query. Cela comprend les étapes addV ou addE, qui entraînent la création et la validation des modifications spécifiées dans la requête.This includes the addV or addEsteps, which will result in the creation and will commit the changes specified in the query. Par conséquent, les unités de requête générées par la requête Gremlin seront également facturées.As a result, the Request Units generated by the Gremlin query will also be charged.

Objets de réponse de profil d’exécutionExecution profile response objects

La réponse d’une fonction executionProfile() génère une hiérarchie d’objets JSON avec la structure suivante :The response of an executionProfile() function will yield a hierarchy of JSON objects with the following structure:

  • Objet d’opération Gremlin : représente l’intégralité de l’opération Gremlin qui a été exécutée.Gremlin operation object: Represents the entire Gremlin operation that was executed. Contient les propriétés suivantes.Contains the following properties.

    • gremlin: instruction Gremlin explicite qui a été exécutée.gremlin: The explicit Gremlin statement that was executed.
    • totalTime: durée, en millisecondes, nécessaire à l’exécution de l’étape.totalTime: The time, in milliseconds, that the execution of the step incurred in.
    • metrics: tableau qui contient tous les opérateurs de runtime Cosmos DB qui ont été exécutés pour répondre à la requête.metrics: An array that contains each of the Cosmos DB runtime operators that were executed to fulfill the query. Cette liste est triée par ordre d’exécution.This list is sorted in order of execution.
  • Opérateurs de runtime Cosmos DB : représente chacun des composants de l’opération Gremlin entière.Cosmos DB runtime operators: Represents each of the components of the entire Gremlin operation. Cette liste est triée par ordre d’exécution.This list is sorted in order of execution. Chaque objet contient les propriétés suivantes :Each object contains the following properties:

    • name: nom de l’opérateur.name: Name of the operator. Il s’agit du type d’étape qui a été évaluée et exécutée.This is the type of step that was evaluated and executed. Pour en savoir plus, consultez le tableau ci-dessous.Read more in the table below.
    • time: durée, en millisecondes, nécessaire à l’exécution d’un opérateur donné.time: Amount of time, in milliseconds, that a given operator took.
    • annotations: contient des informations supplémentaires propres à l’opérateur exécuté.annotations: Contains additional information, specific to the operator that was executed.
    • annotations.percentTime: pourcentage de la durée totale consacré à l’exécution de l’opérateur en question.annotations.percentTime: Percentage of the total time that it took to execute the specific operator.
    • counts: nombre d’objets qui ont été retournés à partir de la couche de stockage par cet opérateur.counts: Number of objects that were returned from the storage layer by this operator. Ce nombre est contenu dans la valeur scalaire counts.resultCount.This is contained in the counts.resultCount scalar value within.
    • storeOps: représente une opération de stockage qui peut couvrir une ou plusieurs partitions.storeOps: Represents a storage operation that can span one or multiple partitions.
    • storeOps.fanoutFactor: représente le nombre de partitions sollicitées par cette opération de stockage spécifique.storeOps.fanoutFactor: Represents the number of partitions that this specific storage operation accessed.
    • storeOps.count: représente le nombre de résultats retournés par cette opération de stockage.storeOps.count: Represents the number of results that this storage operation returned.
    • storeOps.size: représente la taille en octets du résultat d’une opération de stockage donnée.storeOps.size: Represents the size in bytes of the result of a given storage operation.
Opérateur de runtime Gremlin Cosmos DBCosmos DB Gremlin Runtime Operator DescriptionDescription
GetVertices Cette étape obtient un ensemble d’objets à prédicat à partir de la couche de persistance.This step obtains a predicated set of objects from the persistence layer.
GetEdges Cette étape obtient les bords adjacents à un ensemble de vertex.This step obtains the edges that are adjacent to a set of vertices. Cette étape peut entraîner une ou plusieurs opérations de stockage.This step can result in one or many storage operations.
GetNeighborVertices Cette étape obtient les vertex connectés à un ensemble de bords.This step obtains the vertices that are connected to a set of edges. Les bords contiennent les clés de partitions et les ID de leurs vertex source et cible.The edges contain the partition keys and ID's of both their source and target vertices.
Coalesce Cette étape prend en compte l’évaluation de deux opérations chaque fois que l’étape Gremlin coalesce() est exécutée.This step accounts for the evaluation of two operations whenever the coalesce() Gremlin step is executed.
CartesianProductOperator Cette étape calcule un produit cartésien de deux jeux de données.This step computes a cartesian product between two datasets. Elle est généralement exécutée chaque fois que les prédicats to() ou from() sont utilisés.Usually executed whenever the predicates to() or from() are used.
ConstantSourceOperator Cette étape calcule une expression pour produire une valeur constante comme résultat.This step computes an expression to produce a constant value as a result.
ProjectOperator Cette étape prépare et sérialise une réponse à l’aide du résultat des opérations précédentes.This step prepares and serializes a response using the result of preceding operations.
ProjectAggregation Cette étape prépare et sérialise une réponse pour une opération d’agrégation.This step prepares and serializes a response for an aggregate operation.

Notes

Cette liste continuera à être mise à jour au fur et à mesure de l’ajout de nouveaux opérateurs.This list will continue to be updated as new operators are added.

Exemples d’analyse d’une réponse de profil d’exécutionExamples on how to analyze an execution profile response

Voici quelques exemples d’optimisations courantes qui peuvent être détectées à l’aide de la réponse de profil d’exécution :The following are examples of common optimizations that can be spotted using the Execution Profile response:

  • Requête de distribution ramifiée aveugle.Blind fan-out query.
  • Requête non filtrée.Unfiltered query.

Modèles de requête de distribution ramifiée aveugleBlind fan-out query patterns

Considérez la réponse de profil d’exécution suivante provenant d’un graphe partitionné :Assume the following execution profile response from a partitioned graph:

[
  {
    "gremlin": "g.V('tt0093640').executionProfile()",
    "totalTime": 46,
    "metrics": [
      {
        "name": "GetVertices",
        "time": 46,
        "annotations": {
          "percentTime": 100
        },
        "counts": {
          "resultCount": 1
        },
        "storeOps": [
          {
            "fanoutFactor": 5,
            "count": 1,
            "size": 589,
            "time": 75.61
          }
        ]
      },
      {
        "name": "ProjectOperator",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 1
        }
      }
    ]
  }
]

Nous pouvons en tirer les conclusions suivantes :The following conclusions can be made from it:

  • La requête est une recherche d’ID unique, puisque l’instruction Gremlin suit le modèle g.V('id').The query is a single ID lookup, since the Gremlin statement follows the pattern g.V('id').
  • À en juger par la métrique time, la latence de cette requête semble être élevée, car elle est supérieure à 10 ms pour une seule opération de lecture de point.Judging from the time metric, the latency of this query seems to be high since it's more than 10ms for a single point-read operation.
  • Si nous examinons l’objet storeOps, nous constatons que fanoutFactor est égal à 5, ce qui signifie que cinq partitions ont été sollicitées par cette opération.If we look into the storeOps object, we can see that the fanoutFactor is 5, which means that 5 partitions were accessed by this operation.

En conclusion de cette analyse, nous pouvons dire que la première requête accède à plus de partitions que nécessaire.As a conclusion of this analysis, we can determine that the first query is accessing more partitions than necessary. Ce problème peut être résolu en spécifiant la clé de partitionnement dans la requête en tant que prédicat.This can be addressed by specifying the partitioning key in the query as a predicate. Cela permettra de réduire la latence et le coût par requête.This will lead to less latency and less cost per query. Explorez plus en détail le partitionnement de graphe.Learn more about graph partitioning. g.V('tt0093640').has('partitionKey', 't1001') serait une requête plus optimale.A more optimal query would be g.V('tt0093640').has('partitionKey', 't1001').

Modèles de requête non filtréeUnfiltered query patterns

Comparez les deux réponses de profil d’exécution suivantes.Compare the following two execution profile responses. Pour rester simple, ces exemples utilisent un seul graphe partitionné.For simplicity, these examples use a single partitioned graph.

Cette première requête récupère tous les sommets avec l’étiquette tweet, puis obtient leurs sommets voisins :This first query retrieves all vertices with the label tweet and then obtains their neighboring vertices:

[
  {
    "gremlin": "g.V().hasLabel('tweet').out().executionProfile()",
    "totalTime": 42,
    "metrics": [
      {
        "name": "GetVertices",
        "time": 31,
        "annotations": {
          "percentTime": 73.81
        },
        "counts": {
          "resultCount": 30
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 13,
            "size": 6819,
            "time": 1.02
          }
        ]
      },
      {
        "name": "GetEdges",
        "time": 6,
        "annotations": {
          "percentTime": 14.29
        },
        "counts": {
          "resultCount": 18
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 20,
            "size": 7950,
            "time": 1.98
          }
        ]
      },
      {
        "name": "GetNeighborVertices",
        "time": 5,
        "annotations": {
          "percentTime": 11.9
        },
        "counts": {
          "resultCount": 20
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 4,
            "size": 1070,
            "time": 1.19
          }
        ]
      },
      {
        "name": "ProjectOperator",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 20
        }
      }
    ]
  }
]

Notez le profil de la même requête, mais désormais avec un filtre supplémentaire, has('lang', 'en'), avant d’explorer les sommets adjacents :Notice the profile of the same query, but now with an additional filter, has('lang', 'en'), before exploring the adjacent vertices:

[
  {
    "gremlin": "g.V().hasLabel('tweet').has('lang', 'en').out().executionProfile()",
    "totalTime": 14,
    "metrics": [
      {
        "name": "GetVertices",
        "time": 14,
        "annotations": {
          "percentTime": 58.33
        },
        "counts": {
          "resultCount": 11
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 11,
            "size": 4807,
            "time": 1.27
          }
        ]
      },
      {
        "name": "GetEdges",
        "time": 5,
        "annotations": {
          "percentTime": 20.83
        },
        "counts": {
          "resultCount": 18
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 18,
            "size": 7159,
            "time": 1.7
          }
        ]
      },
      {
        "name": "GetNeighborVertices",
        "time": 5,
        "annotations": {
          "percentTime": 20.83
        },
        "counts": {
          "resultCount": 18
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 4,
            "size": 1070,
            "time": 1.01
          }
        ]
      },
      {
        "name": "ProjectOperator",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 18
        }
      }
    ]
  }
]

Ces deux requêtes atteignent le même résultat, mais la première nécessite davantage d’unités de requête car elle doit itérer un plus grand jeu de données initial avant d’interroger les éléments adjacents.These two queries reached the same result, however, the first one will require more Request Units since it needed to iterate a larger initial dataset before querying the adjacent items. Nous pouvons voir des indicateurs de ce comportement quand nous comparons les paramètres suivants des deux réponses :We can see indicators of this behavior when comparing the following parameters from both responses:

  • La valeur metrics[0].time est plus élevée dans la première réponse, ce qui indique que cette étape a duré plus longtemps.The metrics[0].time value is higher in the first response, which indicates that this single step took longer to resolve.
  • La valeur metrics[0].counts.resultsCount est également plus élevée dans la première réponse, ce qui indique que le jeu de données de travail initial était plus volumineux.The metrics[0].counts.resultsCount value is higher as well in the first response, which indicates that the initial working dataset was larger.

Étapes suivantesNext steps