De stap met het uitvoeringsprofiel gebruiken om de Gremlin-query's te evalueren

VAN TOEPASSING OP: Gremlin-API

Dit artikel bevat een overzicht van het gebruik van de stap met het uitvoeringsprofiel voor grafiekdatabases van Azure Cosmos DB Gremlin API. Deze stap biedt relevante informatie voor het oplossen van problemen en het optimaliseren van query's, en is compatibel met Gremlin-query's die kunnen worden uitgevoerd voor een Cosmos DB Gremlin API-account.

Als u deze stap wilt gebruiken, kunt u gewoon de functie-aanroep toevoegen executionProfile() aan het einde van uw Gremlin-query. Uw Gremlin-query wordt uitgevoerd en het resultaat van de bewerking retourneert een JSON-antwoordobject met het uitvoeringsprofiel van de query.

Bijvoorbeeld:

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

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

Na het aanroepen van de stap is het antwoord een JSON-object dat de uitgevoerde Gremlin-stap bevat, de totale tijd die deze heeft nodig en een matrix van de Cosmos DB-runtimeoperators waar de instructie toe heeft executionProfile() geleid.

Notitie

Deze implementatie voor uitvoeringsprofiel is niet gedefinieerd in de Apache Tinkerpop-specificatie. Dit is specifiek voor Azure Cosmos DB implementatie van de Gremlin-API.

Voorbeeld van een antwoord

Hier volgt een voorbeeld met aantekeningen van de uitvoer die wordt geretourneerd:

Notitie

In dit voorbeeld worden opmerkingen geplaatst waarin de algemene structuur van het antwoord wordt uitgelegd. Een daadwerkelijk executionProfile-antwoord bevat geen opmerkingen.

[
  {
    // 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
        }
      }
    ]
  }
]

Notitie

Met de stap executionProfile wordt de Gremlin-query uitgevoerd. Dit omvat de stappen of , wat resulteert in het maken en de wijzigingen die addV zijn opgegeven in de query worden addE doorgevoerd. Als gevolg hiervan worden ook de aanvraageenheden in rekening gebracht die worden gegenereerd door de Gremlin-query.

Antwoordobjecten voor uitvoeringsprofiel

Het antwoord van een functie executionProfile() levert een hiërarchie van JSON-objecten op met de volgende structuur:

  • Gremlin-bewerkingsobject: vertegenwoordigt de hele Gremlin-bewerking die is uitgevoerd. Bevat de volgende eigenschappen.

    • gremlin: De expliciete Gremlin-instructie die is uitgevoerd.
    • totalTime: de tijd, in milliseconden, waarin de uitvoering van de stap is uitgevoerd.
    • metrics: Een matrix die elk van de Cosmos DB runtime-operators bevat die zijn uitgevoerd om aan de query te voldoen. Deze lijst wordt gesorteerd op volgorde van uitvoering.
  • Cosmos DB runtimeoperators: Vertegenwoordigt elk van de onderdelen van de hele Gremlin-bewerking. Deze lijst wordt gesorteerd op volgorde van uitvoering. Elk object bevat de volgende eigenschappen:

    • name: De naam van de operator. Dit is het type stap dat is geëvalueerd en uitgevoerd. Meer informatie vindt u in de onderstaande tabel.
    • time: de hoeveelheid tijd, in milliseconden, die een bepaalde operator heeft gehad.
    • annotations: Bevat aanvullende informatie, specifiek voor de operator die is uitgevoerd.
    • annotations.percentTime: Percentage van de totale tijd die nodig was om de specifieke operator uit te voeren.
    • counts: Het aantal objecten dat door deze operator is geretourneerd vanuit de opslaglaag. Dit is opgenomen in de counts.resultCount scalaire waarde in .
    • storeOps: Vertegenwoordigt een opslagbewerking die een of meer partities kan omspannen.
    • storeOps.fanoutFactor: Vertegenwoordigt het aantal partities dat door deze specifieke opslagbewerking is gebruikt.
    • storeOps.count: Vertegenwoordigt het aantal resultaten dat door deze opslagbewerking is geretourneerd.
    • storeOps.size: Vertegenwoordigt de grootte in bytes van het resultaat van een bepaalde opslagbewerking.
Cosmos DB Gremlin Runtime Operator Description
GetVertices Deze stap verkrijgt een vooraf geprediceerde set objecten van de persistentielaag.
GetEdges Met deze stap verkrijgt u de randen die naast een set hoek punten liggen. Deze stap kan resulteren in een of meer opslagbewerkingen.
GetNeighborVertices Deze stap verkrijgt de hoek punten die zijn verbonden met een set randen. De randen bevatten de partitiesleutels en id's van zowel hun bron- als doelverticen.
Coalesce Deze stap is verantwoordelijk voor de evaluatie van twee bewerkingen wanneer de coalesce() Gremlin-stap wordt uitgevoerd.
CartesianProductOperator In deze stap wordt een cartesisch product berekend tussen twee gegevenssets. Wordt meestal uitgevoerd wanneer de predicaten to() of from() worden gebruikt.
ConstantSourceOperator Met deze stap wordt een expressie berekend om als resultaat een constante waarde te produceren.
ProjectOperator Met deze stap wordt een antwoord voorbereid en geser serialiseert met behulp van het resultaat van voorgaande bewerkingen.
ProjectAggregation In deze stap wordt een antwoord voorbereid en geser serialiseert voor een aggregatiebewerking.

Notitie

Deze lijst wordt nog steeds bijgewerkt als er nieuwe operators worden toegevoegd.

Voorbeelden van het analyseren van een antwoord op een uitvoeringsprofiel

Hier volgen enkele voorbeelden van algemene optimalisaties die kunnen worden gezien met behulp van het antwoord uitvoeringsprofiel:

  • Fan-out-query voor blinden.
  • Niet-gefilterde query.

Fan-out querypatronen voor blinden

Stel dat de volgende uitvoeringsprofielreactie van een gepartitiesde grafiek is:

[
  {
    "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
        }
      }
    ]
  }
]

Hier kunnen de volgende conclusies uit worden getrokken:

  • De query is een zoekopdracht met één id, omdat de Gremlin-instructie het patroon g.V('id') volgt.
  • Afgezien van de metrische gegevens lijkt de latentie van deze query hoog te zijn, omdat deze meer dan 10 ms is voor een bewerking met één time punt-lezen.
  • Als we naar het object kijken, kunnen we zien dat de is, wat betekent dat er vijf partities zijn storeOps fanoutFactor gebruikt door deze 5 bewerking.

Als conclusie van deze analyse kunnen we vaststellen dat de eerste query meer partities gebruikt dan nodig is. Dit kan worden verholpen door de partitioneringssleutel in de query op te geven als een predicaat. Dit leidt tot minder latentie en lagere kosten per query. Meer informatie over het partitioneren van grafen. Een optimale query zou g.V('tt0093640').has('partitionKey', 't1001') zijn.

Niet-gefilterde querypatronen

Vergelijk de volgende twee uitvoerprofielreacties. Voor het gemak gebruiken deze voorbeelden één gepart partitioneerde grafiek.

Met deze eerste query worden alleticen met het label opgehaald en vervolgens de tweet aangrenzendeticen opgehaald:

[
  {
    "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
        }
      }
    ]
  }
]

Let op het profiel van dezelfde query, maar nu met een extra filter, has('lang', 'en') , voordat u de aangrenzende vertices verkent:

[
  {
    "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
        }
      }
    ]
  }
]

Deze twee query's bereikten hetzelfde resultaat, maar voor de eerste query zijn meer aanvraageenheden nodig, omdat er een grotere initiële gegevensset moet worden uitgevoerd voordat de aangrenzende items worden opgevraagd. We kunnen indicatoren van dit gedrag zien bij het vergelijken van de volgende parameters uit beide antwoorden:

  • De waarde is hoger in het eerste antwoord, wat aangeeft dat het langer duurde om deze metrics[0].time ene stap op te lossen.
  • De waarde is ook hoger in het eerste antwoord, wat aangeeft dat de oorspronkelijke metrics[0].counts.resultsCount werkende gegevensset groter was.

Volgende stappen