Skip to content

Commit 61d5b07

Browse files
committedJan 29, 2025
Added updates on latest changes around nulls
1 parent 1288b9e commit 61d5b07

File tree

2 files changed

+138
-5
lines changed

2 files changed

+138
-5
lines changed
 

‎book/Section-Beyond-Basic-Queries.adoc

+133
Original file line numberDiff line numberDiff line change
@@ -5404,6 +5404,139 @@ the results of your queries as JSON. Remember that if you do save an entire grap
54045404
JSON, unless you specify otherwise, the default format is GraphSON 3.0 with
54055405
embedded types.
54065406

5407+
5408+
[[nulls]]
5409+
Using null in Gremlin
5410+
~~~~~~~~~~~~~~~~~~~~~
5411+
5412+
Gremlin does allow null values to move through a traversal. Whether or not nulls are
5413+
meaningful to you with Gremlin tends to depend on the graph database that you are
5414+
using and whether or not it supports storing null values. If the graph does not
5415+
support that capability, then you won't encounter a null in your traversal pipeline
5416+
or your results unless you introduce the null value yourself. You might do that by
5417+
way of a side-effect or some other Gremlin step that allows you to supply a value to
5418+
the stream. The following examples demonstrate a few ways that you might choose to
5419+
do this:
5420+
5421+
[source,groovy]
5422+
----
5423+
g.inject(null)
5424+
5425+
null
5426+
5427+
g.V().limit(10).coalesce(has('elev',gt(3000)), constant(null)).fold()
5428+
5429+
[null,v[2305],null,null,null,null,v[2300],null,v[2308],v[2307]]
5430+
----
5431+
5432+
The prior examples don't showcase any particular common use case and unless the graph
5433+
itself supports storing null values there is little foundation for injecting them in
5434+
this fashion. For graphs that do support storing null, such as TinkerGraph, you can
5435+
treat nulls in much the same manner that you do other values in Gremlin.
5436+
5437+
NOTE: TinkerGraph is not configured to support null storage by default. You must
5438+
provide set the 'gremlin.tinkergraph.allowNullPropertyValues' to true in its
5439+
configuration to enable it.
5440+
5441+
Before we look too closely at how null is used in a graph that supports it, let's
5442+
first take a look at what happens with null for graphs that do not. In particular,
5443+
we should look at the 'property' step.
5444+
5445+
[source,groovy]
5446+
----
5447+
g.addV('airport').property('code',null)
5448+
5449+
v[41223]
5450+
5451+
g.V().has('code',null)
5452+
5453+
// no result
5454+
5455+
g.V().hasNot('code')
5456+
5457+
v[41223]
5458+
----
5459+
5460+
NOTE: For better portability, prefer 'drop' when removing properties.
5461+
5462+
In the prior example, Gremlin semantics expect that calls to 'property' with a null
5463+
value assignment will result in the step being ignored if the property does not exist
5464+
or removed if it does. The following demonstrates the latter:
5465+
5466+
[source,groovy]
5467+
----
5468+
g.addV('airport').property('code','XYZ')
5469+
5470+
v[41224]
5471+
5472+
g.V(41224).property('code',null)
5473+
5474+
v[41224]
5475+
5476+
g.V().hasNot('code')
5477+
5478+
v[41224]
5479+
----
5480+
5481+
Now that we've looked at graphs that don't support null, let's look at how Gremlin
5482+
behaves for those that do:
5483+
5484+
[source,groovy]
5485+
----
5486+
g.addV('airport').property('code',null)
5487+
5488+
v[41228]
5489+
5490+
g.V().has('code',null)
5491+
5492+
v[41228]
5493+
5494+
g.V().has('code',within('IAD',null)).values('code')
5495+
5496+
null
5497+
IAD
5498+
----
5499+
5500+
As you can see in the prior example, the null value is being stored in and retrieved
5501+
from the graph. By electing to use this feature, you now have the additional burden
5502+
of accounting for null in your query. Gremlin steps tend to behave in null-safe ways
5503+
as shown in the the following examples:
5504+
5505+
[source,groovy]
5506+
----
5507+
g.V().has('code',within('IAD',null)).values('code').substring(0,1).fold()
5508+
5509+
[null,I]
5510+
5511+
g.V().has('code',within('IAD',null)).values('code').length().fold()
5512+
5513+
[null,3]
5514+
5515+
g.V().has('code',within('IAD',null)).values('code').groupCount()
5516+
5517+
[null:1,IAD:1]
5518+
5519+
g.V().has('code',within('IAD',null)).values('code').order()
5520+
5521+
null
5522+
IAD
5523+
5524+
g.V().has('code',within('IAD',null)).values('code').order().by(desc)
5525+
5526+
IAD
5527+
null
5528+
----
5529+
5530+
The choice to use null is often made for you as many graphs do not support storing
5531+
nulls at which point injecting them yourself into your queries doesn't tend to
5532+
provide much added value. In addition, when the graph you are using does support it,
5533+
you should take care in the choice to use it because it will reduce the portability
5534+
of your application by limiting your graph choices as you will have to find another
5535+
that also supports the feature. On the flip side, if you choose a graph that does not
5536+
support null values and use the 'property('key',null)' syntax to remove properties,
5537+
then keep in mind that this syntax will behave quite differently if you switch to a
5538+
graph that suddenly supports storing nulls!
5539+
54075540
[[traversal-strategies]]
54085541
Understanding TraversalStrategies
54095542
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

‎book/Section-Moving-Beyond.adoc

+5-5
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,8 @@ Checking to see if a query returned a result
643643
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
644644

645645
It is often important to know if a query returned a result before trying to reference
646-
it to avoid those pesky Java Null Pointer Exceptions. Without worrying about Java for
647-
a second consider the query below purely from a Gremlin point of view.
646+
it to avoid those pesky Java 'NoSuchElementException' errors. Without worrying about
647+
Java for a second consider the query below purely from a Gremlin point of view.
648648

649649
[source,groovy]
650650
----
@@ -669,8 +669,8 @@ Long result =
669669
----
670670

671671
On the surface, this looks fine. However, were we to execute this code we would get a
672-
Null Pointer Exception as when we try to call 'next' there is no result to process as
673-
there is no edge between Austin and Sydney and hence no distance value to process.
672+
'NoSuchElementException' as when we try to call 'next' there is no result to process
673+
as there is no edge between Austin and Sydney and hence no distance value to process.
674674

675675
NOTE: The source code in this section comes from the 'GraphSearch2.java' sample
676676
located at https://github.com/krlawrence/graph/tree/main/sample-code/java.
@@ -717,7 +717,7 @@ Integer d = (Integer)
717717
If the route exists the distance will be found and returned, otherwise a value of
718718
'"-1"' will be returned. This is really using the same concept as the 'toList'
719719
example except in this case we generate the list using the 'fold' step within the
720-
query itself. The 'unfold' will return a result if the list is not null, otherwise
720+
query itself. The 'unfold' will return a result if the list is not empty, otherwise
721721
the constant value will be returned as 'coalesce' returns the first to yield a
722722
result.
723723

0 commit comments

Comments
 (0)