When working with graph databases using Apache TinkerPop Gremlin, one of the most common tasks is filtering vertices and edges based on specific property values. Whether you are analyzing social networks, transportation networks, or any complex graph structure, the ability to efficiently test values and ranges is crucial.
Gremlin provides a rich set of predicates that allow you to compare numbers, strings, or even sets of values. These predicates can be used in steps like has(), where(), or is(), letting you focus your queries on just the nodes and edges that matter.
For example, you might want to:
· Find cities with more than 5 lakes.
· Identify all routes that avoid certain cities.
· Query nodes whose IDs fall within a specific range.
· Filter properties that match a set of allowed or disallowed values.
These tasks can be handled efficiently with predicates such as:
|
Predicate |
Purpose |
|
eq |
Equal to a value |
|
neq |
Not equal to a value |
|
gt |
Greater than |
|
gte |
Greater than or equal |
|
lt |
Less than |
|
lte |
less than or equal |
|
inside |
Within bounds (exclusive) |
|
outside |
Outside bounds (exclusive) |
|
between |
Lower bound inclusive, upper bound exclusive |
|
within |
Matches one or more specified values (list or range) |
|
without |
Excludes one or more specified values (list or range) |
These predicates provide flexibility in querying graphs, whether you are working with numeric properties (like salaries, age, discounts etc.,) or strings (like city names or airport codes).
Why Range and Value Testing Matters?
Efficient range and value testing lets you:
· Filter large graphs quickly: You avoid processing unnecessary nodes.
· Perform complex queries: Combine within and without to include or exclude specific values.
· Write cleaner queries: Predicates like inside, outside, or between make your intent explicit.
· Compare numbers and strings seamlessly: You can handle both numeric and textual data in your graph without switching approaches.
1. Student Enrollment Graph
Let’s model a school graph where students can enroll for classes.
Step 1: Create Graph traversal instance.
graph = TinkerGraph.open() g = graph.traversal()
Step 2: Create Vertices.
// Students g.addV('student').property('name','Alice').property('age',14).property('grade',9) g.addV('student').property('name','Bob').property('age',15).property('grade',10) g.addV('student').property('name','Carol').property('age',13).property('grade',8) g.addV('student').property('name','David').property('age',14).property('grade',9) g.addV('student').property('name','Eve').property('age',12).property('grade',7) // Classes g.addV('class').property('subject','Math').property('maxStudents',30) g.addV('class').property('subject','Science').property('maxStudents',25) g.addV('class').property('subject','History').property('maxStudents',20) g.addV('class').property('subject','Art').property('maxStudents',15)
Step 3: Connect Students to Classes
// Alice enrolled in Math and Science g.V().has('student','name','Alice').as('s'). V().has('class','subject','Math').addE('enrolled_in').from('s') g.V().has('student','name','Alice').as('s'). V().has('class','subject','Science').addE('enrolled_in').from('s') // Bob enrolled in Math and History g.V().has('student','name','Bob').as('s'). V().has('class','subject','Math').addE('enrolled_in').from('s') g.V().has('student','name','Bob').as('s'). V().has('class','subject','History').addE('enrolled_in').from('s') // Carol enrolled in Science g.V().has('student','name','Carol').as('s'). V().has('class','subject','Science').addE('enrolled_in').from('s') // David enrolled in Art and History g.V().has('student','name','David').as('s'). V().has('class','subject','Art').addE('enrolled_in').from('s') g.V().has('student','name','David').as('s'). V().has('class','subject','History').addE('enrolled_in').from('s') // Eve enrolled in Art only g.V().has('student','name','Eve').as('s'). V().has('class','subject','Art').addE('enrolled_in').from('s')
Let’s print the Graph and confirm the same.
gremlin> g.V().valueMap(true) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]] ==>[id:16,label:student,grade:[7],name:[Eve],age:[12]] ==>[id:4,label:student,grade:[10],name:[Bob],age:[15]] ==>[id:20,label:class,subject:[Math],maxStudents:[30]] ==>[id:23,label:class,subject:[Science],maxStudents:[25]] ==>[id:8,label:student,grade:[8],name:[Carol],age:[13]] ==>[id:26,label:class,subject:[History],maxStudents:[20]] ==>[id:12,label:student,grade:[9],name:[David],age:[14]] ==>[id:29,label:class,subject:[Art],maxStudents:[15]] gremlin> gremlin> g.E().valueMap(true) ==>[id:32,label:enrolled_in] ==>[id:33,label:enrolled_in] ==>[id:34,label:enrolled_in] ==>[id:35,label:enrolled_in] ==>[id:36,label:enrolled_in] ==>[id:37,label:enrolled_in] ==>[id:38,label:enrolled_in] ==>[id:39,label:enrolled_in]
2. Introducing Predicates
2.1 eq: Equal To
Matches values that are exactly equal.
Example 1: Students who are exactly 14 years old.
g.V(). hasLabel('student'). has('age', eq(14)). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('age', eq(14)). ......3> valueMap(true) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]] ==>[id:12,label:student,grade:[9],name:[David],age:[14]]
You can even use "has('age', 14)", eq is optional in simple has() comparisons.
g.V(). hasLabel('student'). has('age', 14). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('age', 14). ......3> valueMap(true) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]] ==>[id:12,label:student,grade:[9],name:[David],age:[14]]
Example 2: Get all the students named Alice.
g.V(). hasLabel('student'). has('name', eq('Alice')). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('name', eq('Alice')). ......3> valueMap(true) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]]
2.2 neq: Not Equal To
Matches values not equal to the given value.
Example 1: Students not in grade 9
g.V(). hasLabel('student'). has('grade', neq(9)). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('grade', neq(9)). ......3> valueMap(true) ==>[id:16,label:student,grade:[7],name:[Eve],age:[12]] ==>[id:4,label:student,grade:[10],name:[Bob],age:[15]] ==>[id:8,label:student,grade:[8],name:[Carol],age:[13]]
Example 2: Students not named Bob
g.V(). hasLabel('student'). has('name', neq('Bob')). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('name', neq('Bob')). ......3> valueMap(true) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]] ==>[id:16,label:student,grade:[7],name:[Eve],age:[12]] ==>[id:8,label:student,grade:[8],name:[Carol],age:[13]] ==>[id:12,label:student,grade:[9],name:[David],age:[14]]
2.3 gt: Greater Than
Example: Students older than 14.
g.V(). hasLabel('student'). has('age', gt(14)). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('age', gt(14)). ......3> valueMap(true) ==>[id:4,label:student,grade:[10],name:[Bob],age:[15]]
2.4 gte: Greater Than or Equal
Example: Students Greater than or equal to 14
g.V(). hasLabel('student'). has('age', gte(14)). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('age', gte(14)). ......3> valueMap(true) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]] ==>[id:4,label:student,grade:[10],name:[Bob],age:[15]] ==>[id:12,label:student,grade:[9],name:[David],age:[14]]
2.5 lt: Less Than
Example: Students age less than 14.
g.V(). hasLabel('student'). has('age', lt(14)). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('age', lt(14)). ......3> valueMap(true) ==>[id:16,label:student,grade:[7],name:[Eve],age:[12]] ==>[id:8,label:student,grade:[8],name:[Carol],age:[13]]
2.6 lte: Less Than or Equal
Example: Students age less than or equal 14.
g.V(). hasLabel('student'). has('age', lte(14)). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('age', lte(14)). ......3> valueMap(true) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]] ==>[id:16,label:student,grade:[7],name:[Eve],age:[12]] ==>[id:8,label:student,grade:[8],name:[Carol],age:[13]] ==>[id:12,label:student,grade:[9],name:[David],age:[14]]
2.7 inside(lower, upper)
Value is strictly between bounds. Both bounds are excluded (lower < value < upper).
Example: Students aged between 12 and 15 (exclusive).
g.V(). hasLabel('student'). has('age', inside(12, 15)). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('age', inside(12, 15)). ......3> valueMap(true) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]] ==>[id:8,label:student,grade:[8],name:[Carol],age:[13]] ==>[id:12,label:student,grade:[9],name:[David],age:[14]]
2.8 outside(lower, upper)
Value is less than lower OR greater than upper, bounds excluded (value < lower OR value > upper).
Example: Students younger than 13 or older than 14:
g.V(). hasLabel('student'). has('age', outside(13, 14)). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('age', outside(13, 14)). ......3> valueMap(true) ==>[id:16,label:student,grade:[7],name:[Eve],age:[12]] ==>[id:4,label:student,grade:[10],name:[Bob],age:[15]]
2.9 between(lower, upper)
Lower bound inclusive and upper bound exclusive (lower ≤ value < upper).
Example: Students aged 12, 13, or 14:
g.V(). hasLabel('student'). has('age', between(12, 15)). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('age', between(12, 15)). ......3> valueMap(true) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]] ==>[id:16,label:student,grade:[7],name:[Eve],age:[12]] ==>[id:8,label:student,grade:[8],name:[Carol],age:[13]] ==>[id:12,label:student,grade:[9],name:[David],age:[14]]
2.10 within(...)
'within' predicate matches any one of the provided values. It can take:
· Explicit values
· A range
· A list
Example 1: Explicit values
Students in grades 8, 9, or 10.
g.V(). hasLabel('student'). has('grade', within(8, 9, 10)). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('grade', within(8, 9, 10)). ......3> valueMap(true) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]] ==>[id:4,label:student,grade:[10],name:[Bob],age:[15]] ==>[id:8,label:student,grade:[8],name:[Carol],age:[13]] ==>[id:12,label:student,grade:[9],name:[David],age:[14]]
Example 2: Range syntax
g.V(). hasLabel('student'). has('grade', within(8..10)). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('grade', within(8..10)). ......3> valueMap(true) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]] ==>[id:4,label:student,grade:[10],name:[Bob],age:[15]] ==>[id:8,label:student,grade:[8],name:[Carol],age:[13]] ==>[id:12,label:student,grade:[9],name:[David],age:[14]]
Example 3: String search
Classes that are Math or Science:
g.V(). hasLabel('class'). has('subject',within('Math','Science')). valueMap(true)
gremlin> g.V(). ......1> hasLabel('class'). ......2> has('subject',within('Math','Science')). ......3> valueMap(true) ==>[id:20,label:class,subject:[Math],maxStudents:[30]] ==>[id:23,label:class,subject:[Science],maxStudents:[25]]
Example 4: Using list notation
g.V(). hasLabel('student'). has('grade', within([8, 9, 10])). valueMap(true)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('grade', within([8, 9, 10])). ......3> valueMap(true) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]] ==>[id:4,label:student,grade:[10],name:[Bob],age:[15]] ==>[id:8,label:student,grade:[8],name:[Carol],age:[13]] ==>[id:12,label:student,grade:[9],name:[David],age:[14]]
2.11 without(...)
It is just opposite of within, must NOT match any provided value.
Example 1: Students NOT in grades 7 or 8.
g.V(). hasLabel('student'). has('grade',without(7,8)). valueMap(). with(WithOptions.tokens)
gremlin> g.V(). ......1> hasLabel('student'). ......2> has('grade',without(7,8)). ......3> valueMap(). ......4> with(WithOptions.tokens) ==>[id:0,label:student,grade:[9],name:[Alice],age:[14]] ==>[id:4,label:student,grade:[10],name:[Bob],age:[15]] ==>[id:12,label:student,grade:[9],name:[David],age:[14]]
Example 2: Classes that are NOT Art.
g.V(). hasLabel('class'). has('subject',without('Art')). valueMap(). with(WithOptions.tokens)
gremlin> g.V(). ......1> hasLabel('class'). ......2> has('subject',without('Art')). ......3> valueMap(). ......4> with(WithOptions.tokens) ==>[id:20,label:class,subject:[Math],maxStudents:[30]] ==>[id:23,label:class,subject:[Science],maxStudents:[25]] ==>[id:26,label:class,subject:[History],maxStudents:[20]]
In summary, understanding value and range testing predicates is fundamental to writing clean, efficient, and expressive Gremlin traversals.
In this post, we explored how predicates like:
· eq, neq: exact matching
· gt, gte, lt, lte: numeric comparisons
· inside, outside, between: mathematical range control
· within, without: multi-value inclusion and exclusion
these predicates allow you to precisely filter vertices and edges based on property values.
No comments:
Post a Comment