Steps O-T

Updated at:

option

  • Feature: (Modifier) Specifies the conditions for a branch query.

  • Note: This step must be used with branch().

optional

  • Feature: (Branch) Returns the traversal result if the sub-traversal produces a result. Otherwise, it returns the input object.

// Returns the "knows" relationships or the information of people who have no friends.
g("thinkerpop").V("1;2;4;6").hasLabel("person").optional(outE("knows"))
==> {"label":"knows","pk":"1","sk":"4","weight":1.0}
==> {"label":"knows","pk":"1","sk":"2","weight":0.5}
==> {"label":"person","age":32,"name":"josh","pk":"4"}
==> {"label":"person","age":27,"name":"vadas","pk":"2"}
==> {"label":"person","age":35,"name":"peter","pk":"6"}

or

  • Feature: (Filter) Returns the input if at least one sub-traversal produces a result.

// Finds people who are 27 years old or have at least two friends.
g("thinkerpop").V("1;2;4;6").hasLabel("person").or(outE("knows").count().is(P.gte(2)),filter("age=27"))
==> {"label":"person","age":29,"name":"marko","pk":"1"}
==> {"label":"person","age":27,"name":"vadas","pk":"2"}

order

  • Feature: (Map) Sorts the results.

  • Note:

    • You can use the by() modifier to specify the sorting criteria and order: ascending (incr), descending (decr), or random (shuffle).

      • By default, results are sorted by their values. You can specify a field value or a sub-traversal as the sorting rule.

      • The default order is ascending.

      • You can use multiple by() steps to specify multiple sorting rules.

    • This step implicitly inserts a barrier().

// Sorts by pk in ascending order. If pks are the same, sorts by sk in descending order.
g("thinkerpop").E("1;2;3;4;5;6").hasLabel("created").order().by("pk").by("sk",Order.decr)
==> {"label":"created","pk":"1","sk":"3","weight":0.4}
==> {"label":"created","pk":"4","sk":"5","weight":1.0}
==> {"label":"created","pk":"4","sk":"3","weight":0.4}
==> {"label":"created","pk":"6","sk":"3","weight":0.2}

// Sorts by the number of "knows" relationships in descending order.
g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").order().by(outE("knows").count(),Order.decr)
==> {"label":"person","age":29,"name":"marko","pk":"1"}
==> {"label":"person","age":32,"name":"josh","pk":"4"}
==> {"label":"person","age":27,"name":"vadas","pk":"2"}
==> {"label":"person","age":35,"name":"peter","pk":"6"}

// Randomly sorts the ages.
g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").values("age").order().by(Order.shuffle)
==> 32
==> 35
==> 29
==> 27

out

  • Feature: (Entity) Traverses from a vertex to an adjacent vertex.

  • Note:

    • This step only supports graph access mode.

      • You can use a parameter to specify the label of the edge to traverse.

      • If you do not specify a parameter, all adjacent edges are traversed by default.

    • This step is broken down into outE().limit(50).inV(). This means a limit of 50 is applied to the outgoing edges. If this is insufficient for your requirements, use the outE().limit(300).inV() pattern.

      For system protection, the number of outgoing edges cannot exceed 50,000.

    • out().out() is optimized and broken down into outE().limit(50).outE().limit(50).inV().

      • This saves one vertex access.

      • The skey value of the edge from the first outE() is the pkey value for the edge in the second outE().

      • This optimization does not take effect if path() exists in the subsequent traversal.

g("thinkerpop").V("1").hasLabel("person").out("knows")
==> {"label":"person","age":32,"name":"josh","pk":"4"}
==> {"label":"person","age":27,"name":"vadas","pk":"2"}

g("thinkerpop").V("1").hasLabel("person").out()
==> {"label":"software","lang":"java","name":"lop","pk":"3"}
==> {"label":"person","age":32,"name":"josh","pk":"4"}
==> {"label":"person","age":27,"name":"vadas","pk":"2"}

outE

  • Feature: (Entity) Traverses from a vertex to an adjacent edge.

  • Note:

    • Graph access mode: You can use a parameter to specify the label of the edge to traverse.

      • If you do not specify a parameter, all adjacent edges are traversed by default.

// By default, the pkey of the input vertex is used as the traversal field.
g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").outE("knows")
==> {"label":"knows","pk":"1","sk":"4","weight":1.0}
==> {"label":"knows","pk":"1","sk":"2","weight":0.5}

g("thinkerpop").V("1").hasLabel("person").outE("knows","created")
==> {"label":"created","pk":"1","sk":"3","weight":0.4}
==> {"label":"knows","pk":"1","sk":"4","weight":1.0}
==> {"label":"knows","pk":"1","sk":"2","weight":0.5}

P

  • Feature: (Function) Describes comparison logic.

  • Format

Type

Name

Description

Example

Basic

P.eq

Equal to

P.eq(25)

P.neq

Not equal to

P.neq(25)

P.gt

Greater than

P.gt(25)

P.gte

Greater than or equal to

P.gte(25)

P.lt

Less than

P.lt(25)

P.lte

Less than or equal to

P.lte(25)

P.inside

Within the range: (a, b)

P.inside(25, 32)

P.outside

Outside the range: (-inf, a) U (b, inf)

P.outside(25, 32)

P.between

Between: [a, b)

P.between(25, 32)

P.within

Within the set

P.within(25, 32, 33, 35)

P.without

Not within the set

P.without(25, 32, 33, 35)

Combined

and

And

P.gt(25) and P.lt(30)

or

Or

P.eq(25) or P.eq(30)

negate

Reverse

P.eq(25).negate()

  • Note

    • Only number and string types are supported.

    • Applies to filter steps such as is() and has().

    • Differences between P and expressions

      • P: Applies to scenarios with one parameter. The parameter does not need a name.

      • Expression: Applies to scenarios with multiple parameters. The parameters must have names.

      • Their features partially overlap. Use the one that best suits your scenario.

// Finds people who are 27 years old or have at least two friends.
g("thinkerpop").V("1;2;4;6").hasLabel("person").or(outE("knows").count().is(P.gte(2)),values("age").is(P.eq(27)))
==> {"label":"person","age":29,"name":"marko","pk":"1"}
==> {"label":"person","age":27,"name":"vadas","pk":"2"}
// This is equivalent to:
// The first sub-traversal of or() has no name, so you can only use P. The second parameter is age, so you can use an expression with filter instead.
g("thinkerpop").V("1;2;4;6").hasLabel("person").or(outE("knows").count().is(P.gte(2)),filter("age=27"))

path

  • Feature (Map): Returns the traversal path.

  • Note

    • path() only shows the result of each step. To include edge information in the path when using out(), you must explicitly use outE().inV().

    • You can use the by() modifier to specify the fields to record in the path.

    • You can use the PathRecordStrategy policy to customize the type of information that this step records in the path.

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").out().out().values("name").path()
==> {"value":[{"label":"person","age":29,"name":"marko","pk":"1"},{"label":"person","age":32,"name":"josh","pk":"4"},{"label":"software","lang":"java","name":"lop","pk":"3"},"lop"],"labels":[[],[],[],[]]}
==> {"value":[{"label":"person","age":29,"name":"marko","pk":"1"},{"label":"person","age":32,"name":"josh","pk":"4"},{"label":"software","lang":"java","name":"ripple","pk":"5"},"ripple"],"labels":[[],[],[],[]]}

// Explicitly call outE().inV() to show edge information.
g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").outE().inV().outE().inV().values("name").path()
==> {"value":[{"label":"person","age":29,"name":"marko","pk":"1"},{"label":"knows","pk":"1","sk":"4","weight":1.0},{"label":"person","age":32,"name":"josh","pk":"4"},{"label":"created","pk":"4","sk":"3","weight":0.4},{"label":"software","lang":"java","name":"lop","pk":"3"},"lop"],"labels":[[],[],[],[],[],[]]}
==> {"value":[{"label":"person","age":29,"name":"marko","pk":"1"},{"label":"knows","pk":"1","sk":"4","weight":1.0},{"label":"person","age":32,"name":"josh","pk":"4"},{"label":"created","pk":"4","sk":"5","weight":1.0},{"label":"software","lang":"java","name":"ripple","pk":"5"},"ripple"],"labels":[[],[],[],[],[],[]]}

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").out().out().path().by("name")
==> {"value":["marko","josh","lop"],"labels":[[],[],[]]}
==> {"value":["marko","josh","ripple"],"labels":[[],[],[]]}

PathRecordStrategy

  • Feature: (Policy) Customizes the type of information that path() records.

  • Format: Classifies information into the following three types:

  • This policy is an extension developed by IGraph.

    • PathRecord.vertex: Vertex

    • PathRecord.edge: Edge

    • PathRecord.map: Map type

  • Note:

    • By default, all types of information are recorded.

    • This policy must be used with withStrategies().

    • This policy helps reduce the amount of data transferred.

// By default, all types of information are recorded.
g("thinkerpop").V("4").hasLabel("person").outE().inV().path()
==> {"value":[{"label":"person","age":32,"name":"josh","pk":"4"},{"label":"created","pk":"4","sk":"3","weight":0.4},{"label":"software","lang":"java","name":"lop","pk":"3"}],"labels":[[],[],[]]}
==> {"value":[{"label":"person","age":32,"name":"josh","pk":"4"},{"label":"created","pk":"4","sk":"5","weight":1.0},{"label":"software","lang":"java","name":"ripple","pk":"5"}],"labels":[[],[],[]]}

// Records only vertex information.
g("thinkerpop").V("4").withStrategies(PathRecordStrategy(PathRecord.vertex)).hasLabel("person").outE().inV().path()
==> {"value":[{"label":"person","age":32,"name":"josh","pk":"4"},{"label":"software","lang":"java","name":"lop","pk":"3"}],"labels":[[],[]]},
==> {"value":[{"label":"person","age":32,"name":"josh","pk":"4"},{"label":"software","lang":"java","name":"ripple","pk":"5"}],"labels":[[],[]]}

// Records only edge information.
g("thinkerpop").V("4").withStrategies(PathRecordStrategy(PathRecord.edge)).hasLabel("person").outE().inV().path()
==> {"value":[{"label":"created","pk":"4","sk":"3","weight":0.4}],"labels":[[]]}
==> {"value":[{"label":"created","pk":"4","sk":"5","weight":1.0}],"labels":[[]]}

project

  • Feature: (Map) Maps input objects to a map<string, object>.

  • Note: You can use the by() modifier to specify the value for the mapping.

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").project("a","b").by(outE("knows").count()).by("age").order().by(select("b"))
==> {"\"a\"":0,"\"b\"":27}
==> {"\"a\"":2,"\"b\"":29}
==> {"\"a\"":0,"\"b\"":32}
==> {"\"a\"":0,"\"b\"":35}

// The number of items created and the number of friends known by each person.
g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").project("created","knows").by(outE("created").count()).by(outE("knows").count())
==> {"\"created\"":1,"\"knows\"":2}
==> {"\"created\"":2,"\"knows\"":0}
==> {"\"created\"":0,"\"knows\"":0}
==> {"\"created\"":1,"\"knows\"":0}

properties

  • Feature: (Map) Returns field names and field values.

  • Note:

    • You can specify which properties to return. By default, all properties are returned.

    • values() returns field values.

g("thinkerpop").V("1;2").hasLabel("person").properties()
==> {"age":29}
==> {"name":"marko"}
==> {"pk":"1"}
==> {"age":27}
==> {"name":"vadas"}
==> {"pk":"2"}

g("thinkerpop").V("1;2").hasLabel("person").properties("name","age")
==> {"age":29}
==> {"name":"marko"}
==> {"age":27}
==> {"name":"vadas"}

propertyMap

  • Feature: (Map) Returns a map of field names and field values.

  • Note: You can specify which properties to return. By default, all properties are returned.

g("thinkerpop").V("1;2").hasLabel("person").propertyMap()
==> {"\"age\"":{"age":29},"\"name\"":{"name":"marko"},"\"pk\"":{"pk":"1"}}
==> {"\"age\"":{"age":27},"\"name\"":{"name":"vadas"},"\"pk\"":{"pk":"2"}}

g("thinkerpop").V("1;2").hasLabel("person").propertyMap("name","age")
==> {"\"age\"":{"age":29},"\"name\"":{"name":"marko"}}
==> {"\"age\"":{"age":27},"\"name\"":{"name":"vadas"}}

PushDownStrategy

  • Feature: (Policy) Pushes down side effect retrieval to the storage layer for execution.

  • Note: In compute-intensive scenarios, pushing down side effect retrieval to the storage layer reduces data transfer.

  • This policy is an IGraph extension.

// The maximum product of each person's age and the ages of others.
g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").aggregate("x").by("age").V("1;2;3;4;5;6").hasLabel("person").values("age").as("y").local(select("x").unfold().math("_ * y").max())
==> 1015
==> 1120
==> 945
==> 1225

// Pushes down the logic for calculating the maximum value to be executed immediately after getting y. This reduces the duration for which y needs to be stored.
g("thinkerpop").withStrategies(PushDownStrategy("x")).V("1;2;3;4;5;6").hasLabel("person").aggregate("x").by("age").V("1;2;3;4;5;6").hasLabel("person").values("age").as("y").local(select("x").unfold().math("_ * y").max())
==> 1015
==> 1120
==> 945
==> 1225

range

  • Function: Truncates the results.

  • Format: range(low,high). low is of the uint32 type, and high is of the int64 type. We recommend that high be less than 50,000.

  • Note: If high is -1, all results from low onward are returned. Otherwise, high must be greater than low.

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").order().by("pk").range(1,2)
==> {"label":"person","age":27,"name":"vadas","pk":"2"}

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").order().by("pk").range(1,-1)
==> {"label":"person","age":27,"name":"vadas","pk":"2"}
==> {"label":"person","age":32,"name":"josh","pk":"4"}
==> {"label":"person","age":35,"name":"peter","pk":"6"}

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").order().by("pk").range(1,0)
==> {"ErrorCode":20040,"ErrorDescription":"gremlin 'range(global)' step invalid (low(1) > high(0) in 'range')"}

repeat

  • Feature: (Branch) Loops through a traversal.

  • Note:

    • You can use this step with other steps, such as times() and until(), to specify the loop termination condition.

    • You can use this step with emit() to record the intermediate results of the loop.

    • For system protection, do not run inefficient queries. For example, do not run an unlimited loop on a graph that contains cycles.

    • For system protection, specify a limit() for each traversal within the loop. Each degree is limited to 50,000 results.

# Traverses out twice and gets the traversal path.
g("thinkerpop").V("1").hasLabel("person").repeat(out()).times(2).path().by("name")
==> {"value":["marko","josh","lop"],"labels":[[],[],[]]}
==> {"value":["marko","josh","ripple"],"labels":[[],[],[]]}

# Do not run until() on a graph with cycles.
# Starts from the specified node and performs a breadth-first search until the "ripple" node is found.
g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").until(has("name","ripple")).repeat(out()).path().by("name")
==> {"value":["marko","josh","ripple"],"labels":[[],[],[]]}
==> {"value":["josh","ripple"],"labels":[[],[]]}

# emit() - Traverses two degrees and outputs the intermediate paths.
g("thinkerpop").V("1").hasLabel("person").repeat(out()).times(2).emit().path().by("name")
==> {"value":["marko","lop"],"labels":[[],[]]}
==> {"value":["marko","josh"],"labels":[[],[]]}
==> {"value":["marko","vadas"],"labels":[[],[]]}
==> {"value":["marko","josh","lop"],"labels":[[],[],[]]}
==> {"value":["marko","josh","ripple"],"labels":[[],[],[]]}

# emit() - Traverses two degrees and outputs the intermediate paths. This includes the path before the repeat starts.
g("thinkerpop").V("1").hasLabel("person").emit().repeat(out()).times(2).path().by("name")
==>[marko]
==> {"value":["marko"],"labels":[[]]}
==> {"value":["marko","lop"],"labels":[[],[]]}
==> {"value":["marko","josh"],"labels":[[],[]]}
==> {"value":["marko","josh","lop"],"labels":[[],[],[]]}
==> {"value":["marko","josh","ripple"],"labels":[[],[],[]]}
==> {"value":["marko","vadas"],"labels":[[],[]]}

sack

  • Feature: (Map) Returns the sack value of an entity.

  • Note: For more information about the initialization value, split rule, and merge rule for sack values, see withSack().

sample

  • Feature: (Filter) Samples the results.

  • Format: sample([Sample.upsampling,][Sample.duplicatable,]NUM)[by(field)]. NUM is of the uint32 type.

    • Sample.duplicatable specifies that duplicates are not removed. This allows the number of output objects to exceed the number of input objects. For example, for the input `a a b c`, sampling 3 with deduplication returns at most two `a`s. Without deduplication, it might return three `a`s.

    • Sample.upsampling enables upsampling. If the total number of input objects is less than the specified sample size, upsampling ensures that the specified number of results is returned, unless the input is empty. When upsampling is active, the `duplicatable` setting is ignored.

    • By default, results are deduplicated and not upsampled.

  • Note:

    • Random sampling is used by default.

    • You can use the by() modifier to use a field's value as the sampling weight. A higher weight increases the probability of being sampled.

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").outE("created").sample(Sample.upsampling,Sample.duplicatable,5).by("weight")
==> {"label":"created","pk":"1","sk":"3","weight":0.4}
==> {"label":"created","pk":"4","sk":"5","weight":1.0}
==> {"label":"created","pk":"4","sk":"5","weight":1.0}
==> {"label":"created","pk":"4","sk":"5","weight":1.0}
==> {"label":"created","pk":"6","sk":"3","weight":0.2}

select

  • Feature: (Map) Returns the value of a label that was marked by as().

  • Note:

    • When this step retrieves multiple label values, it returns a map<label, objects>.

    • You can use the by() modifier to specify a field of the label to retrieve.

    • This step can be used with Pop.first, Pop.last, and Pop.all. These select the first, last, or all occurrences of a label in the path, respectively.

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").as("x").select("x")
==> {"label":"person","age":29,"name":"marko","pk":"1"}
==> {"label":"person","age":32,"name":"josh","pk":"4"}
==> {"label":"person","age":27,"name":"vadas","pk":"2"}
==> {"label":"person","age":35,"name":"peter","pk":"6"}

// The filter step takes the labeled objects as input.
g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").as("x").filter("age>=32").select("x")
==> {"label":"person","age":32,"name":"josh","pk":"4"}
==> {"label":"person","age":35,"name":"peter","pk":"6"}

// A step can be associated with multiple labels using as().
// When select() gets multiple label values, it returns a map<label,objects>.
// select() is modified by by() to specify which field of the label to get.
g("thinkerpop").V("1;2").hasLabel("person").as("x","y","z").select("x","y","z").by("pk").by("name").by("age")
==> {"\"x\"":"1","\"y\"":"marko","\"z\"":29}
==> {"\"x\"":"2","\"y\"":"vadas","\"z\"":27}

// The value of the first occurrence of the label "a".
g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").as("a").repeat(out().as("a")).times(2).select(Pop.first,"a")
==> {"label":"person","age":29,"name":"marko","pk":"1"}
==> {"label":"person","age":29,"name":"marko","pk":"1"}

// The value of the last occurrence of the label "a".
g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").as("a").repeat(out().as("a")).times(2).select(Pop.last,"a")
==> {"label":"software","lang":"java","name":"lop","pk":"3"}
==> {"label":"software","lang":"java","name":"ripple","pk":"5"}

// All occurrences of the label "a". This is equivalent to select("a").
g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").as("a").repeat(out().as("a")).times(2).select(Pop.all,"a")
==> [{"label":"person","age":29,"name":"marko","pk":"1"},{"label":"person","age":32,"name":"josh","pk":"4"},{"label":"software","lang":"java","name":"lop","pk":"3"}]
==> [{"label":"person","age":29,"name":"marko","pk":"1"},{"label":"person","age":32,"name":"josh","pk":"4"},{"label":"software","lang":"java","name":"ripple","pk":"5"}]

simplePath

  • Feature: (Filter) Returns paths without cycles.

  • Note:

    • You can use the by() modifier to specify the fields to use for cycle detection.

    • cyclePath() returns paths with cycles.

g("thinkerpop").V("1").hasLabel("person").out().out().simplePath().path()
==> {"value":[{"label":"person","age":29,"name":"marko","pk":"1"},{"label":"person","age":32,"name":"josh","pk":"4"},{"label":"software","lang":"java","name":"lop","pk":"3"}],"labels":[[],[],[]]}
==> {"value":[{"label":"person","age":29,"name":"marko","pk":"1"},{"label":"person","age":32,"name":"josh","pk":"4"},{"label":"software","lang":"java","name":"ripple","pk":"5"}

g("thinkerpop").V("1").hasLabel("person").out().out().simplePath().path().by("name")
==> {"value":["marko","josh","lop"],"labels":[[],[],[]]}
==>{"value":["marko","josh","ripple"],"labels":[[],[],[]]}

store

  • Feature: (sideEffect) During a traversal, aggregates input objects into a list<object> and saves it in a sideEffect.

  • Note:

    • This step does not affect the input objects. The original objects are passed to the next step.

    • The list<object> generated by this step is read-only. You can retrieve its value at any point in the subsequent traversal using cap().

      • Note: Retrieving the value with select() is not recommended. This is because select() returns a list<object> for each entity, which results in multiple identical lists if there are multiple entities.

    • You can use the by() modifier to specify the field value for aggregation.

    • You can use aggregate() to perform blocking aggregation.

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").store("x").by("name")
==> {"label":"person","age":29,"name":"marko","pk":"1"}
==> {"label":"person","age":32,"name":"josh","pk":"4"}
==> {"label":"person","age":27,"name":"vadas","pk":"2"}
==> {"label":"person","age":35,"name":"peter","pk":"6"}

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").store("x").by("name").cap("x")
==> ["josh","marko","peter","vadas"]

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").store("x").by("name").filter("age>=32").cap("x")
==> ["josh","marko","peter","vadas"]

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").store("x").by("name").outE("knows").store("y").cap("x","y").dedup()
==> {"\"x\"":["josh","marko","peter","vadas"],"\"y\"":[{"label":"knows","pk":"1","sk":"2","weight":0.5},{"label":"knows","pk":"1","sk":"4","weight":1.0}]}

sum

  • Feature: (Map) Calculates the sum of the input objects.

  • Note:

    • This step only supports number-type inputs and does not support the bool type.

    • sum(Scope.local) supports iterator-type inputs. The elements in the iterator must be numbers and cannot be of the bool type.

    • This step implicitly inserts a barrier().

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").values("age").sum()
==> 123

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").values("age").fold().sum(Scope.local)
==> 123

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").aggregate("x").by("age").cap("x").sum(Scope.local)
==> 123

T

  • Feature: (Function) Extracts information from input elements.

  • Format

    • T.id: Returns the pkey field value of the entity.

    • T.label: Returns the label of the entity (the corresponding label in the graph).

    • T.key: Returns the field name of the element.

    • T.value: Returns the field value of the element.

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").has(T.id,P.eq("1"))
==> {"label":"person","age":29,"name":"marko","pk":"1"}

// After two traversals, there are no more "person" entities, only "software" entities.
g("thinkerpop").V("1").hasLabel("person").out().out().has(T.label,P.eq("person"))
==> Empty result

// Sorts by field name.
g("thinkerpop").V("1").hasLabel("person").properties().order().by(T.key)
==> {"age":29}
==> {"name":"marko"}
==> {"pk":"1"}

// Sorts by field value.
g("thinkerpop").V("1").hasLabel("person").properties().order().by(T.value)
==> {"age":29}
==> {"pk":"1"}
==> {"name":"marko"}

tail

  • Feature: (Filter) Truncates the results. Keeps the last NUM results.

  • Format: tail(NUM). NUM is of the uint32 type. We recommend that NUM is less than 50,000.

  • Note

    • limit() keeps the first NUM results.

    • This step implicitly inserts a barrier().

g("thinkerpop").V("1;2;3;4;5;6").hasLabel("person").tail(2)
==> {"label":"person","age":27,"name":"vadas","pk":"2"}
==> {"label":"person","age":35,"name":"peter","pk":"6"}

times

  • Feature: (Modifier) Specifies the number of times to loop a traversal.

  • Note: This step must be used with repeat().