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

VAN TOEPASSING OP: Gremlin

Dit artikel bevat een overzicht van het gebruik van de stap uitvoeringsprofiel voor Azure Cosmos DB voor Gremlin-grafiekdatabases. 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, voegt u de executionProfile() functieaanroep toe aan het einde van uw Gremlin-query. Uw Gremlin-query wordt uitgevoerd en het resultaat van de bewerking retourneert een JSON-antwoordobject met het queryuitvoeringsprofiel.

Bijvoorbeeld:

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

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

Nadat de executionProfile() stap is aangeroepen, is het antwoord een JSON-object met daarin de uitgevoerde Gremlin-stap, de totale tijd die deze heeft geduurd en een matrix van de Cosmos DB-runtimeoperators waarin de instructie heeft geresulteerd.

Notitie

Deze implementatie voor uitvoeringsprofiel is niet gedefinieerd in de Apache Tinkerpop-specificatie. Het is specifiek voor azure Cosmos DB voor de implementatie van Gremlin.

Voorbeeld van antwoord

Hier volgt een voorbeeld van een aantekening van de uitvoer die wordt geretourneerd:

Notitie

Dit voorbeeld is voorzien van opmerkingen die de algemene structuur van het antwoord uitleggen. 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 addV stappen of addE, die resulteren in het maken en doorvoeren van de wijzigingen die zijn opgegeven in de query. Als gevolg hiervan worden de aanvraageenheden die door de Gremlin-query worden gegenereerd, ook in rekening gebracht.

Antwoordobjecten voor uitvoeringsprofielen

Het antwoord van een executionProfile()-functie 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-runtimeoperators bevat die zijn uitgevoerd om de query uit te voeren. 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: naam van de operator. Dit is het type stap dat is geëvalueerd en uitgevoerd. Lees meer in de onderstaande tabel.
    • time: De hoeveelheid tijd, in milliseconden, die een bepaalde operator heeft geduurd.
    • 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 binnen.
    • storeOps: Vertegenwoordigt een opslagbewerking die een of meer partities kan omvatten.
    • storeOps.fanoutFactor: Geeft het aantal partities weer waartoe deze specifieke opslagbewerking toegang heeft.
    • storeOps.count: Geeft het aantal resultaten aan dat deze opslagbewerking heeft geretourneerd.
    • storeOps.size: Geeft de grootte in bytes aan van het resultaat van een bepaalde opslagbewerking.
Cosmos DB Gremlin Runtime Operator Description
GetVertices Met deze stap wordt een geprediceerde set objecten opgehaald uit de persistentielaag.
GetEdges Met deze stap worden de randen verkregen die grenzen aan een set hoekpunten. Deze stap kan resulteren in een of meer opslagbewerkingen.
GetNeighborVertices Met deze stap worden de hoekpunten verkregen die zijn verbonden met een set randen. De randen bevatten de partitiesleutels en id's van zowel de bron- als doelpunten.
Coalesce Deze stap houdt rekening met de evaluatie van twee bewerkingen wanneer de coalesce() Gremlin-stap wordt uitgevoerd.
CartesianProductOperator Met deze stap wordt een cartesisch product tussen twee gegevenssets berekend. Meestal uitgevoerd wanneer de predicaten to() of from() worden gebruikt.
ConstantSourceOperator In deze stap wordt een expressie berekend om als resultaat een constante waarde te produceren.
ProjectOperator In deze stap wordt een antwoord voorbereid en geserialiseerd op basis van het resultaat van voorgaande bewerkingen.
ProjectAggregation Met deze stap wordt een antwoord voor een statistische bewerking voorbereid en geserialiseerd.

Notitie

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

Voorbeelden van het analyseren van een antwoord op een uitvoeringsprofiel

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

  • Blinde uitwaaierquery.
  • Niet-gefilterde query.

Blinde uitwaaiingsquerypatronen

Ga uit van het volgende uitvoeringsprofielantwoord van een gepartitioneerde grafiek:

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

Hieruit kunnen de volgende conclusies worden getrokken:

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

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

Niet-gefilterde querypatronen

Vergelijk de volgende twee uitvoeringsprofielreacties. Voor het gemak gebruiken deze voorbeelden één gepartitioneerde grafiek.

Met deze eerste query worden alle hoekpunten met het label tweet opgehaald en worden vervolgens de aangrenzende hoekpunten 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 hoekpunten 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 hebben hetzelfde resultaat bereikt, maar voor de eerste query zijn meer aanvraageenheden nodig, omdat er een grotere initiële gegevensset moet worden herhaald voordat er een query op de aangrenzende items wordt uitgevoerd. We kunnen indicatoren van dit gedrag zien bij het vergelijken van de volgende parameters uit beide antwoorden:

  • De metrics[0].time waarde is hoger in het eerste antwoord, wat aangeeft dat het oplossen van deze stap langer duurde.
  • De metrics[0].counts.resultsCount waarde is ook hoger in het eerste antwoord, wat aangeeft dat de eerste werkende gegevensset groter was.

Volgende stappen