rgraphum 0.0.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/.gitignore +26 -0
  2. data/GLOSSARIES.md +108 -0
  3. data/GREMLIN.md +1398 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +136 -0
  7. data/Rakefile +16 -0
  8. data/bin/.irbrc +41 -0
  9. data/bin/rgraphum_console +61 -0
  10. data/bin/rgraphum_runner +57 -0
  11. data/examples/ba_model/make.rb +19 -0
  12. data/examples/ba_model/make_dummy_twitter_rt_data.rb +0 -0
  13. data/examples/basic/check_modularity.rb +27 -0
  14. data/examples/basic/make_graph.rb +12 -0
  15. data/examples/parser/dot.rb +28 -0
  16. data/examples/sis_model/lifegame.rb +161 -0
  17. data/graph_struct.jpg +0 -0
  18. data/lib/rgraphum/analyzer/linear_regression.rb +31 -0
  19. data/lib/rgraphum/analyzer/meme_tracker.rb +296 -0
  20. data/lib/rgraphum/analyzer/twitter/rt_at_mark.rb +45 -0
  21. data/lib/rgraphum/analyzer.rb +8 -0
  22. data/lib/rgraphum/cluster.rb +67 -0
  23. data/lib/rgraphum/communities.rb +65 -0
  24. data/lib/rgraphum/community.rb +86 -0
  25. data/lib/rgraphum/cosine_similarity_matrix.rb +40 -0
  26. data/lib/rgraphum/edge.rb +194 -0
  27. data/lib/rgraphum/edges.rb +161 -0
  28. data/lib/rgraphum/ext/cosine_similarity_matrix.rb +79 -0
  29. data/lib/rgraphum/ext/linear_regression.rb +22 -0
  30. data/lib/rgraphum/ext/tf_idf.rb +52 -0
  31. data/lib/rgraphum/graph/gremlin.rb +193 -0
  32. data/lib/rgraphum/graph/math/clustering_coefficient.rb +53 -0
  33. data/lib/rgraphum/graph/math/community_detection.rb +141 -0
  34. data/lib/rgraphum/graph/math/degree_distribution.rb +50 -0
  35. data/lib/rgraphum/graph/math/dijkstra.rb +331 -0
  36. data/lib/rgraphum/graph/math.rb +45 -0
  37. data/lib/rgraphum/graph.rb +267 -0
  38. data/lib/rgraphum/importer.rb +97 -0
  39. data/lib/rgraphum/marshal.rb +26 -0
  40. data/lib/rgraphum/motifs.rb +8 -0
  41. data/lib/rgraphum/parsers/flare.rb +42 -0
  42. data/lib/rgraphum/parsers/gephi.rb +193 -0
  43. data/lib/rgraphum/parsers/graphviz.rb +78 -0
  44. data/lib/rgraphum/parsers/miserables.rb +54 -0
  45. data/lib/rgraphum/parsers.rb +32 -0
  46. data/lib/rgraphum/path.rb +37 -0
  47. data/lib/rgraphum/query.rb +130 -0
  48. data/lib/rgraphum/rgraphum_array.rb +159 -0
  49. data/lib/rgraphum/rgraphum_array_dividers.rb +43 -0
  50. data/lib/rgraphum/rgraphum_random.rb +5 -0
  51. data/lib/rgraphum/simulator/ba_model.rb +140 -0
  52. data/lib/rgraphum/simulator/sir_model.rb +178 -0
  53. data/lib/rgraphum/simulator/sis_model.rb +158 -0
  54. data/lib/rgraphum/simulator.rb +29 -0
  55. data/lib/rgraphum/statistic/power_law.rb +9 -0
  56. data/lib/rgraphum/t.rb +12 -0
  57. data/lib/rgraphum/tf_idf.rb +27 -0
  58. data/lib/rgraphum/version.rb +3 -0
  59. data/lib/rgraphum/vertex.rb +354 -0
  60. data/lib/rgraphum/vertices.rb +97 -0
  61. data/lib/rgraphum.rb +38 -0
  62. data/performance/add-vertices-edges.rb +20 -0
  63. data/performance/add-vertices.rb +12 -0
  64. data/performance/build-graph.rb +19 -0
  65. data/performance/delete-graph.rb +24 -0
  66. data/performance/delete-vertices.rb +25 -0
  67. data/performance/refer-graph.rb +23 -0
  68. data/rgraphum.gemspec +30 -0
  69. data/test/lib/rgraphum/analyzer/linear_regression_test.rb +20 -0
  70. data/test/lib/rgraphum/analyzer/meme_tracker_test.rb +383 -0
  71. data/test/lib/rgraphum/analyzer/twitter/rt_at_mark_test.rb +120 -0
  72. data/test/lib/rgraphum/array_test.rb +95 -0
  73. data/test/lib/rgraphum/bubble_test.rb +7 -0
  74. data/test/lib/rgraphum/communities_test.rb +53 -0
  75. data/test/lib/rgraphum/cosine_similarity_test.rb +18 -0
  76. data/test/lib/rgraphum/edge_test.rb +89 -0
  77. data/test/lib/rgraphum/edges_test.rb +178 -0
  78. data/test/lib/rgraphum/graph_builder_test.rb +64 -0
  79. data/test/lib/rgraphum/graph_dup_test.rb +199 -0
  80. data/test/lib/rgraphum/graph_plus_test.rb +80 -0
  81. data/test/lib/rgraphum/graph_test.rb +512 -0
  82. data/test/lib/rgraphum/gremlin_test.rb +145 -0
  83. data/test/lib/rgraphum/importers/idg_json_edges.json +20 -0
  84. data/test/lib/rgraphum/importers/idg_json_test.rb +207 -0
  85. data/test/lib/rgraphum/importers/idg_json_vertices.json +46 -0
  86. data/test/lib/rgraphum/math/average_distance_matrix_test.rb +142 -0
  87. data/test/lib/rgraphum/math/clustering_coefficient_test.rb +219 -0
  88. data/test/lib/rgraphum/math/community_test.rb +78 -0
  89. data/test/lib/rgraphum/math/degree_distribution_test.rb +40 -0
  90. data/test/lib/rgraphum/math/dijkstra_test.rb +146 -0
  91. data/test/lib/rgraphum/math/modularity_test.rb +154 -0
  92. data/test/lib/rgraphum/math/quick_average_distance_matrix_test.rb +84 -0
  93. data/test/lib/rgraphum/path_test.rb +44 -0
  94. data/test/lib/rgraphum/query/enumerable_test.rb +42 -0
  95. data/test/lib/rgraphum/query/where_operators_test.rb +75 -0
  96. data/test/lib/rgraphum/query/where_test.rb +59 -0
  97. data/test/lib/rgraphum/simulator/ba_model_test.rb +75 -0
  98. data/test/lib/rgraphum/simulator/sir_model_test.rb +513 -0
  99. data/test/lib/rgraphum/simulator/sis_model_test.rb +478 -0
  100. data/test/lib/rgraphum/simulator_test.rb +22 -0
  101. data/test/lib/rgraphum/tf_idf_test.rb +30 -0
  102. data/test/lib/rgraphum/vertex_test.rb +50 -0
  103. data/test/lib/rgraphum/vertices_test.rb +180 -0
  104. data/test/test_helper.rb +98 -0
  105. data/tmp/.gitkeep +0 -0
  106. metadata +254 -0
data/GREMLIN.md ADDED
@@ -0,0 +1,1398 @@
1
+ # Gremlin
2
+
3
+
4
+ ## Transform
5
+
6
+ Transform steps take an object and emit a transformation of it.
7
+
8
+ ### _
9
+
10
+ Identity turns an arbitrary object into a "pipeline".
11
+
12
+ gremlin> x = [1,2,3]
13
+ ==>1
14
+ ==>2
15
+ ==>3
16
+ gremlin> x._().transform{it+1}
17
+ ==>2
18
+ ==>3
19
+ ==>4
20
+ gremlin> x = g.E.has('weight', T.gt, 0.5f).toList()
21
+ ==>e[10][4-created->5]
22
+ ==>e[8][1-knows->4]
23
+ gremlin> x.inV
24
+ ==>[StartPipe, InPipe]
25
+ ==>[StartPipe, InPipe]
26
+ gremlin> x._().inV
27
+ ==>v[5]
28
+ ==>v[4]
29
+
30
+ ### both
31
+
32
+ Get both adjacent vertices of the vertex, the in and the out.
33
+
34
+ gremlin> v = g.v(4)
35
+ ==>v[4]
36
+ gremlin> v.both
37
+ ==>v[1]
38
+ ==>v[5]
39
+ ==>v[3]
40
+ gremlin> v.both('knows')
41
+ ==>v[1]
42
+ gremlin> v.both('knows', 'created')
43
+ ==>v[1]
44
+ ==>v[5]
45
+ ==>v[3]
46
+
47
+ ### bothE
48
+
49
+ Get both incoming and outgoing edges of the vertex.
50
+
51
+ gremlin> v = g.v(4)
52
+ ==>v[4]
53
+ gremlin> v.bothE
54
+ ==>e[8][1-knows->4]
55
+ ==>e[10][4-created->5]
56
+ ==>e[11][4-created->3]
57
+ gremlin> v.bothE('knows')
58
+ ==>e[8][1-knows->4]
59
+ gremlin> v.bothE('knows', 'created')
60
+ ==>e[8][1-knows->4]
61
+ ==>e[10][4-created->5]
62
+ ==>e[11][4-created->3]
63
+
64
+ ### bothV
65
+
66
+ Get both incoming and outgoing vertices of the edge.
67
+
68
+ gremlin> e = g.e(12)
69
+ ==>e[12][6-created->3]
70
+ gremlin> e.outV
71
+ ==>v[6]
72
+ gremlin> e.inV
73
+ ==>v[3]
74
+ gremlin> e.bothV
75
+ ==>v[6]
76
+ ==>v[3]
77
+
78
+ ### cap
79
+
80
+ Gets the side-effect of the pipe prior. In other words, it emits the value of the previous step and not the values that flow through it.
81
+
82
+ gremlin> g.V('lang', 'java').in('created').name.groupCount
83
+ ==>marko
84
+ ==>josh
85
+ ==>peter
86
+ ==>josh
87
+ gremlin> g.V('lang', 'java').in('created').name.groupCount.cap
88
+ ==>{marko=1, peter=1, josh=2}
89
+
90
+ ### E
91
+
92
+ The edge iterator for the graph. Utilize this to iterate through all the edges in the graph. Use with care on large graphs.
93
+
94
+ gremlin> g.E
95
+ ==>e[10][4-created->5]
96
+ ==>e[7][1-knows->2]
97
+ ==>e[9][1-created->3]
98
+ ==>e[8][1-knows->4]
99
+ ==>e[11][4-created->3]
100
+ ==>e[12][6-created->3]
101
+ gremlin> g.E.weight
102
+ ==>1.0
103
+ ==>0.5
104
+ ==>0.4
105
+ ==>1.0
106
+ ==>0.4
107
+ ==>0.2
108
+
109
+ ### gather
110
+
111
+ Collect all objects up to that step and process the gathered list with the provided closure.
112
+
113
+ gremlin> g.v(1).out
114
+ ==>v[2]
115
+ ==>v[4]
116
+ ==>v[3]
117
+ gremlin> g.v(1).out.gather
118
+ ==>[v[2], v[4], v[3]]
119
+ gremlin> g.v(1).out.gather{it.size()}
120
+ ==>3
121
+
122
+ See Also: scatter
123
+
124
+ ### id
125
+
126
+ Gets the unique identifier of the element.
127
+
128
+ gremlin> v = g.V("name", "marko").next()
129
+ ==>v[1]
130
+ gremlin> v.id
131
+ ==>1
132
+ gremlin> g.v(1).id
133
+ ==>1
134
+
135
+ ### in
136
+
137
+ Gets the adjacent vertices to the vertex.
138
+
139
+ gremlin> v = g.v(4)
140
+ ==>v[4]
141
+ gremlin> v.inE.outV
142
+ ==>v[1]
143
+ gremlin> v.in
144
+ ==>v[1]
145
+ gremlin> v = g.v(3)
146
+ ==>v[3]
147
+ gremlin> v.in("created")
148
+ ==>v[1]
149
+ ==>v[4]
150
+ ==>v[6]
151
+ gremlin> v.inE("created").outV
152
+ ==>v[1]
153
+ ==>v[4]
154
+ ==>v[6]
155
+
156
+ ### inE
157
+
158
+ Gets the incoming edges of the vertex.
159
+
160
+ gremlin> v = g.v(4)
161
+ ==>v[4]
162
+ gremlin> v.inE.outV
163
+ ==>v[1]
164
+ gremlin> v.in
165
+ ==>v[1]
166
+ gremlin> v = g.v(3)
167
+ ==>v[3]
168
+ gremlin> v.in("created")
169
+ ==>v[1]
170
+ ==>v[4]
171
+ ==>v[6]
172
+ gremlin> v.inE("created").outV
173
+ ==>v[1]
174
+ ==>v[4]
175
+ ==>v[6]
176
+
177
+ ### inV
178
+
179
+ Get both incoming head vertex of the edge.
180
+
181
+ gremlin> e = g.e(12)
182
+ ==>e[12][6-created->3]
183
+ gremlin> e.outV
184
+ ==>v[6]
185
+ gremlin> e.inV
186
+ ==>v[3]
187
+ gremlin> e.bothV
188
+ ==>v[6]
189
+ ==>v[3]
190
+
191
+ ### key
192
+
193
+ Get the property value of an element. The property value can be obtained by simply appending the name to the end of the element or by referencing it as a Groovy map element with square brackets.
194
+ For best performance, drop down to the Blueprints API and use getProperty(key).
195
+
196
+ gremlin> v = g.v(3)
197
+ ==>v[3]
198
+ gremlin> v.name
199
+ ==>lop
200
+ gremlin> v['name']
201
+ ==>lop
202
+ gremlin> x = 'name'
203
+ ==>name
204
+ gremlin> v[x]
205
+ ==>lop
206
+ gremlin> v.getProperty('name')
207
+ ==>lop
208
+
209
+ ### label
210
+
211
+ Gets the label of an edge.
212
+
213
+ gremlin> g.v(6).outE.label
214
+ ==>created
215
+ gremlin> g.v(1).outE.filter{it.label=='created'}
216
+ ==>e[9][1-created->3]
217
+
218
+ // a more efficient approach to use of label
219
+ gremlin> g.v(1).outE.has('label','created')
220
+ ==>e[9][1-created->3]
221
+
222
+ ### linkBoth[In/Out]
223
+
224
+ An element-centric mutation that takes every incoming vertex and creates an edge to the provided vertex. It can be used with both a Vertex object or a named step.
225
+
226
+ gremlin> marko = g.v(1)
227
+ ==>v[1]
228
+ gremlin> g.V.except([marko]).linkBoth('connected',marko)
229
+ ==>v[3]
230
+ ==>v[2]
231
+ ==>v[6]
232
+ ==>v[5]
233
+ ==>v[4]
234
+ gremlin> marko.outE('connected')
235
+ ==>e[2][1-connected->2]
236
+ ==>e[0][1-connected->3]
237
+ ==>e[6][1-connected->5]
238
+ ==>e[4][1-connected->6]
239
+ ==>e[14][1-connected->4]
240
+ gremlin> g.V.except([marko]).outE('connected')
241
+ ==>e[1][3-connected->1]
242
+ ==>e[3][2-connected->1]
243
+ ==>e[5][6-connected->1]
244
+ ==>e[13][5-connected->1]
245
+ ==>e[15][4-connected->1]
246
+ gremlin> g.v(1).as('x').out('created').in('created').except([g.v(1)]).linkBoth('cocreator','x')
247
+ ==>v[4]
248
+ ==>v[6]
249
+ gremlin> g.E.has('label','cocreator')
250
+ ==>e[3][6-cocreator->1]
251
+ ==>e[2][1-cocreator->6]
252
+ ==>e[1][4-cocreator->1]
253
+ ==>e[0][1-cocreator->4]
254
+
255
+ ### map
256
+
257
+ Gets the property map of the graph element.
258
+
259
+ gremlin> g.v(1).map
260
+ ==>{name=marko, age=29}
261
+ gremlin> g.v(1).map()
262
+ ==>name=marko
263
+ ==>age=29
264
+
265
+ ### memoize
266
+
267
+ Remembers a particular mapping from input to output. Long or expensive expressions with no side effects can use this step to remember a mapping, which helps reduce load when previously processed objects are passed into it.
268
+
269
+ For situations where memoization may consume large amounts of RAM, consider using an embedded key-value store like JDBM or some other persistent Map implementation.
270
+
271
+ gremlin> g.V.out.out.memoize(1).name
272
+ ==>ripple
273
+ ==>lop
274
+ gremlin> g.V.out.as('here').out.memoize('here').name
275
+ ==>ripple
276
+ ==>lop
277
+ gremlin> m = [:]
278
+ gremlin> g.V.out.out.memoize(1,m).name
279
+ ==>ripple
280
+ ==>lop
281
+
282
+ ### order
283
+
284
+ Order the items in the stream according to the closure if provided. If no closure is provided, then a default sort order is used.
285
+
286
+ gremlin> g.V.name.order
287
+ ==>josh
288
+ ==>lop
289
+ ==>marko
290
+ ==>peter
291
+ ==>ripple
292
+ ==>vadas
293
+ gremlin> g.V.name.order{it.b <=> it.a}
294
+ ==>vadas
295
+ ==>ripple
296
+ ==>peter
297
+ ==>marko
298
+ ==>lop
299
+ ==>josh
300
+ gremlin> g.V.order{it.b.name <=> it.a.name}.out('knows')
301
+ ==>v[2]
302
+ ==>v[4]
303
+
304
+ ### orderMap
305
+
306
+ For every incoming map, sort with supplied closure or T.decr or T.incr and emit keys.
307
+
308
+ gremlin> g.V.both.groupCount.cap.next()
309
+ ==>v[3]=3
310
+ ==>v[2]=1
311
+ ==>v[1]=3
312
+ ==>v[6]=1
313
+ ==>v[5]=1
314
+ ==>v[4]=3
315
+ gremlin> g.V.both.groupCount.cap.orderMap(T.decr)
316
+ ==>v[3]
317
+ ==>v[1]
318
+ ==>v[4]
319
+ ==>v[2]
320
+ ==>v[6]
321
+ ==>v[5]
322
+ gremlin> g.V.both.groupCount.cap.orderMap(T.decr)[0..1]
323
+ ==>v[3]
324
+ ==>v[1]
325
+ gremlin> g.V.both.groupCount.cap.orderMap(T.decr)[0..1].name
326
+ ==>lop
327
+ ==>marko
328
+
329
+ ### out
330
+
331
+ Gets the out adjacent vertices to the vertex.
332
+
333
+ gremlin> v = g.v(1)
334
+ ==>v[1]
335
+ gremlin> v.outE.inV
336
+ ==>v[2]
337
+ ==>v[4]
338
+ ==>v[3]
339
+ gremlin> v.out
340
+ ==>v[2]
341
+ ==>v[4]
342
+ ==>v[3]
343
+ gremlin> v.outE('knows').inV
344
+ ==>v[2]
345
+ ==>v[4]
346
+ gremlin> v.out('knows')
347
+ ==>v[2]
348
+ ==>v[4]
349
+
350
+ ### outE
351
+
352
+ Gets the outgoing edges to the vertex.
353
+
354
+ gremlin> v = g.v(1)
355
+ ==>v[1]
356
+ gremlin> v.outE.inV
357
+ ==>v[2]
358
+ ==>v[4]
359
+ ==>v[3]
360
+ gremlin> v.out
361
+ ==>v[2]
362
+ ==>v[4]
363
+ ==>v[3]
364
+ gremlin> v.outE('knows').inV
365
+ ==>v[2]
366
+ ==>v[4]
367
+ gremlin> v.out('knows')
368
+ ==>v[2]
369
+ ==>v[4]
370
+
371
+ ### outV
372
+
373
+ Get both outgoing tail vertex of the edge.
374
+
375
+ gremlin> e = g.e(12)
376
+ ==>e[12][6-created->3]
377
+ gremlin> e.outV
378
+ ==>v[6]
379
+ gremlin> e.inV
380
+ ==>v[3]
381
+ gremlin> e.bothV
382
+ ==>v[6]
383
+ ==>v[3]
384
+
385
+ ### path
386
+
387
+ Gets the path through the pipeline up to this point, where closures are post-processing for each object in the path. If the path step is provided closures then, in a round robin fashion, the closures are evaluated over each object of the path and that post-processed path is returned.
388
+
389
+ gremlin> g.v(1).out.path
390
+ ==>[v[1], v[2]]
391
+ ==>[v[1], v[4]]
392
+ ==>[v[1], v[3]]
393
+ gremlin> g.v(1).out.path{it.id}
394
+ ==>[1, 2]
395
+ ==>[1, 4]
396
+ ==>[1, 3]
397
+ gremlin> g.v(1).out.path{it.id}{it.name}
398
+ ==>[1, vadas]
399
+ ==>[1, josh]
400
+ ==>[1, lop]
401
+ gremlin> g.v(1).outE.inV.name.path
402
+ ==>[v[1], e[7][1-knows->2], v[2], vadas]
403
+ ==>[v[1], e[8][1-knows->4], v[4], josh]
404
+ ==>[v[1], e[9][1-created->3], v[3], lop]
405
+
406
+ ### scatter
407
+
408
+ Unroll all objects in the iterable at that step. Gather/Scatter is good for breadth-first traversals where the gather closure filters out unwanted elements at the current radius.
409
+
410
+ gremlin> g.v(1).out
411
+ ==>v[2]
412
+ ==>v[4]
413
+ ==>v[3]
414
+ gremlin> g.v(1).out.gather{it[1..2]}
415
+ ==>[v[4], v[3]]
416
+ gremlin> g.v(1).out.gather{it[1..2]}.scatter
417
+ ==>v[4]
418
+ ==>v[3]
419
+
420
+ See Also: gather
421
+
422
+ ### select
423
+
424
+ Select the named steps to emit after select with post-processing closures.
425
+
426
+ gremlin> g.v(1).as('x').out('knows').as('y').select
427
+ ==>[x:v[1], y:v[2]]
428
+ ==>[x:v[1], y:v[4]]
429
+ gremlin> g.v(1).as('x').out('knows').as('y').select(["y"])
430
+ ==>[y:v[2]]
431
+ ==>[y:v[4]]
432
+ gremlin> g.v(1).as('x').out('knows').as('y').select(["y"]){it.name}
433
+ ==>[y:vadas]
434
+ ==>[y:josh]
435
+ gremlin> g.v(1).as('x').out('knows').as('y').select{it.id}{it.name}
436
+ ==>[x:1, y:vadas]
437
+ ==>[x:1, y:josh]
438
+
439
+ ### shuffle
440
+
441
+ Collect all objects up to that step into a list and randomize their order.
442
+
443
+ gremlin> g.v(1).out.shuffle
444
+ ==>v[2]
445
+ ==>v[3]
446
+ ==>v[4]
447
+ gremlin> g.v(1).out.shuffle
448
+ ==>v[3]
449
+ ==>v[2]
450
+ ==>v[4]
451
+
452
+ See Also: random
453
+
454
+ ### transform
455
+
456
+ Transform emits the result of a closure.
457
+
458
+ gremlin> g.E.has('weight', T.gt, 0.5f).outV.age
459
+ ==>32
460
+ ==>29
461
+ gremlin> g.E.has('weight', T.gt, 0.5f).outV.age.transform{it+2}
462
+ ==>34
463
+ ==>31
464
+ gremlin> g.E.has('weight', T.gt, 0.5f).outV.transform{[it.id,it.age]}
465
+ ==>[4, 32]
466
+ ==>[1, 29]
467
+ gremlin> g.E.has('weight', T.gt, 0.5f).outV.transform{[id:it.id,age:it.age]}
468
+ ==>{id=4, age=32}
469
+ ==>{id=1, age=29}
470
+
471
+ ### V
472
+
473
+ The vertex iterator for the graph. Utilize this to iterate through all the vertices in the graph. Use with care on large graphs unless used in combination with a key index lookup.
474
+
475
+ gremlin> g.V
476
+ ==>v[3]
477
+ ==>v[2]
478
+ ==>v[1]
479
+ ==>v[6]
480
+ ==>v[5]
481
+ ==>v[4]
482
+ gremlin> g.V("name", "marko")
483
+ ==>v[1]
484
+ gremlin> g.V("name", "marko").name
485
+ ==>marko
486
+
487
+
488
+ ## Filter
489
+
490
+ Filter steps decide whether to allow an object to pass to the next step or not.
491
+
492
+ ### [i]
493
+
494
+ A index filter that emits the particular indexed object.
495
+
496
+ gremlin> g.V[0].name
497
+ ==>lop
498
+
499
+ ### [i..j]
500
+
501
+ A range filter that emits the objects within a range.
502
+
503
+ gremlin> g.V[0..2].name
504
+ ==>lop
505
+ ==>vadas
506
+ ==>marko
507
+ gremlin> g.V[0..<2].name
508
+ ==>lop
509
+ ==>vadas
510
+
511
+ ### and
512
+
513
+ Takes a collection of pipes and emits incoming objects that are true for all of the pipes.
514
+
515
+ gremlin> g.v(1).outE.and(_().has('weight', T.gt, 0.4f), _().has('weight', T.lt, 0.8f))
516
+ ==>e[7][1-knows->2]
517
+ gremlin> g.V.and(_().both("knows"), _().both("created"))
518
+ ==>v[1]
519
+ ==>v[4]
520
+
521
+ ### back
522
+
523
+ Go back to the results from n-steps ago or go back to the results of a named step.
524
+
525
+ gremlin> g.V.out('knows').has('age', T.gt, 30).back(2).age
526
+ ==>29
527
+ gremlin> g.V.as('x').outE('knows').inV.has('age', T.gt, 30).back('x').age
528
+ ==>29
529
+
530
+ ### dedup
531
+
532
+ Emit only incoming objects that have not been seen before with an optional closure being the object to check on.
533
+
534
+ gremlin> g.v(1).out.in
535
+ ==>v[1]
536
+ ==>v[1]
537
+ ==>v[1]
538
+ ==>v[4]
539
+ ==>v[6]
540
+ gremlin> g.v(1).out.in.dedup()
541
+ ==>v[1]
542
+ ==>v[4]
543
+ ==>v[6]
544
+
545
+ ### except
546
+
547
+ Emit everything to pass except what is in the supplied collection or in the results of a named step.
548
+
549
+ gremlin> x = [g.v(1), g.v(2), g.v(3)]
550
+ ==>v[1]
551
+ ==>v[2]
552
+ ==>v[3]
553
+ gremlin> g.V.except(x)
554
+ ==>v[6]
555
+ ==>v[5]
556
+ ==>v[4]
557
+ gremlin> x = []
558
+ gremlin> g.v(1).out.aggregate(x).out.except(x)
559
+ ==>v[5]
560
+ gremlin> g.V.has('age',T.lt,30).as('x').out('created').in('created').except('x')
561
+ ==>v[4]
562
+ ==>v[6]
563
+
564
+ See Also: retain
565
+
566
+ ### filter
567
+
568
+ Decide whether to allow an object to pass. Return true from the closure to allow an object to pass.
569
+
570
+ gremlin> g.V.filter{it.age > 29}.name
571
+ ==>peter
572
+ ==>josh
573
+
574
+ ### has
575
+
576
+ Allows an element if it has a particular property. Utilizes several options for comparisons through T:
577
+
578
+ T.gt - greater than
579
+ T.gte - greater than or equal to
580
+ T.eq - equal to
581
+ T.neq - not equal to
582
+ T.lte - less than or equal to
583
+ T.lt - less than
584
+
585
+ It is worth noting that the syntax of has is similar to g.V("name", "marko"), which has the difference of being a key index lookup and as such will perform faster. In contrast, this line, g.V.has("name", "marko"), will iterate over all vertices checking the name property of each vertex for a match and will be significantly slower than the key index approach.
586
+
587
+ gremlin> g.V.has("name", "marko").name
588
+ ==>marko
589
+ gremlin> g.v(1).outE.has("weight", T.gte, 0.5f).weight
590
+ ==>0.5
591
+ ==>1.0
592
+ gremlin> g.V.has("age", null).name
593
+ ==>lop
594
+ ==>ripple
595
+
596
+ See Also: hasNot
597
+
598
+ ### hasNot
599
+
600
+ Allows an element if it does not have a particular property. Utilizes several options for comparisons on through T:
601
+
602
+ T.gt - greater than
603
+ T.gte - greater than or equal to
604
+ T.eq - equal to
605
+ T.neq - not equal to
606
+ T.lte - less than or equal to
607
+ T.lt - less than
608
+
609
+ gremlin> g.v(1).outE.hasNot("weight", T.eq, 0.5f).weight
610
+ ==>1.0
611
+ ==>0.4
612
+ gremlin> g.V.hasNot("age", null).name
613
+ ==>vadas
614
+ ==>marko
615
+ ==>peter
616
+ ==>josh
617
+
618
+ ### interval
619
+
620
+ Allow elements to pass that have their property in the provided start and end interval.
621
+
622
+ gremlin> g.E.interval("weight", 0.3f, 0.9f).weight
623
+ ==>0.5
624
+ ==>0.4
625
+ ==>0.4
626
+
627
+ See Also: has
628
+
629
+ ### or
630
+
631
+ Takes a collection of pipes and emits incoming objects that are true for any of the pipes.
632
+
633
+ gremlin> g.v(1).outE.or(_().has('id', T.eq, "9"), _().has('weight', T.lt, 0.6f))
634
+ ==>e[7][1-knows->2]
635
+ ==>e[9][1-created->3]
636
+
637
+ ### random
638
+
639
+ Emits the incoming object if biased coin toss is heads.
640
+
641
+ gremlin> g.V.random(0.5)
642
+ ==>v[3]
643
+ ==>v[1]
644
+ ==>v[6]
645
+ gremlin> g.V.random(0.5)
646
+ ==>v[2]
647
+ ==>v[5]
648
+ ==>v[4]
649
+
650
+ ### retain
651
+
652
+ Allow everything to pass except what is not in the supplied collection or in the results of a named step.
653
+
654
+ gremlin> x = [g.v(1), g.v(2), g.v(3)]
655
+ ==>v[1]
656
+ ==>v[2]
657
+ ==>v[3]
658
+ gremlin> g.V.retain(x)
659
+ ==>v[3]
660
+ ==>v[2]
661
+ ==>v[1]
662
+ gremlin> x = []
663
+ gremlin> g.v(1).out.aggregate(x).out.retain(x)
664
+ ==>v[3]
665
+ gremlin> g.V.as('x').both.both.both.retain('x')
666
+ ==>v[3]
667
+ ==>v[3]
668
+ ==>v[1]
669
+ ==>v[1]
670
+ ==>v[4]
671
+ ==>v[4]
672
+
673
+ See Also: except
674
+
675
+ ### simplePath
676
+
677
+ Emit the object only if the current path has no repeated elements.
678
+
679
+ gremlin> g.v(1).out.in
680
+ ==>v[1]
681
+ ==>v[1]
682
+ ==>v[1]
683
+ ==>v[4]
684
+ ==>v[6]
685
+ gremlin> g.v(1).out.in.simplePath
686
+ ==>v[4]
687
+ ==>v[6]
688
+
689
+
690
+ ## Side Effect
691
+
692
+ Side Effect steps pass the object, but yield some kind of side effect while doing so.
693
+
694
+ ### aggregate
695
+
696
+ Emits input, but adds input in collection, where provided closure processes input prior to insertion (greedy). In being "greedy", 'aggregate' will exhaust all the items that come to it from previous steps before emitting the next element.
697
+
698
+ gremlin> x = []
699
+ gremlin> g.v(1).out.aggregate(x).next()
700
+ ==>v[2]
701
+ gremlin> x
702
+ ==>v[2]
703
+ ==>v[4]
704
+ ==>v[3]
705
+
706
+ See Also: store fill
707
+
708
+ ### as
709
+
710
+ Emits input, but names the previous step.
711
+
712
+ gremlin> g.V.out('knows').has('age', T.gt, 30).back(2).age
713
+ ==>29
714
+ gremlin> g.V.as('x').outE('knows').inV.has('age', T.gt, 30).back('x').age
715
+ ==>29
716
+
717
+ ### groupBy
718
+
719
+ Emits input, but groups input after processing it by provided key-closure and value-closure. It is also possible to supply an optional reduce-closure.
720
+
721
+ gremlin> g.V.groupBy{it}{it.out}.cap
722
+ ==>{v[3]=[], v[2]=[], v[1]=[v[2], v[4], v[3]], v[6]=[v[3]], v[5]=[], v[4]=[v[5], v[3]]}
723
+ gremlin> g.V.groupBy{it}{it.out}{it.size()}.cap
724
+ ==>{v[3]=0, v[2]=0, v[1]=3, v[6]=1, v[5]=0, v[4]=2}
725
+ gremlin> m = [:]
726
+ gremlin> g.V.groupBy(m){it}{it.out}.iterate();null;
727
+ ==>null
728
+ gremlin> m
729
+ ==>v[3]=[]
730
+ ==>v[2]=[]
731
+ ==>v[1]=[v[2], v[4], v[3]]
732
+ ==>v[6]=[v[3]]
733
+ ==>v[5]=[]
734
+ ==>v[4]=[v[5], v[3]]
735
+ gremlin> g.V.out.groupBy{it.name}{it.in}{it.unique().findAll{i -> i.age > 30}.name}.cap
736
+ ==>{lop=[josh, peter], ripple=[josh], josh=[], vadas=[]}
737
+
738
+ See Also: groupCount
739
+
740
+ ### groupCount
741
+
742
+ Emits input, but updates a map for each input, where closures provides generic map update.
743
+
744
+ gremlin> g.V.out.groupCount(m)
745
+ ==>v[2]
746
+ ==>v[4]
747
+ ==>v[3]
748
+ ==>v[3]
749
+ ==>v[5]
750
+ ==>v[3]
751
+ gremlin> m
752
+ ==>v[2]=1
753
+ ==>v[4]=1
754
+ ==>v[3]=3
755
+ ==>v[5]=1
756
+ gremlin> g.v(1).out.groupCount(m){it}{it.b+1.0}.out.groupCount(m){it}{it.b+0.5}
757
+ ==>v[5]
758
+ ==>v[3]
759
+ gremlin> m
760
+ ==>v[2]=1.0
761
+ ==>v[4]=1.0
762
+ ==>v[5]=0.5
763
+ ==>v[3]=1.5
764
+
765
+ See Also: groupBy
766
+
767
+ ### optional
768
+
769
+ Behaves similar to back except that it does not filter. It will go down a particular path and back up to where it left off. As such, its useful for yielding a sideeffect down a particular branch.
770
+
771
+ gremlin> g.V.out('knows').has('age', T.gt, 30).back(2)
772
+ ==>v[1]
773
+ gremlin> g.V.out('knows').has('age', T.gt, 30).optional(2)
774
+ ==>v[3]
775
+ ==>v[2]
776
+ ==>v[1]
777
+ ==>v[6]
778
+ ==>v[5]
779
+ ==>v[4]
780
+ gremlin> g.V.as('x').outE('knows').inV.has('age', T.gt, 30).back('x')
781
+ ==>v[1]
782
+ gremlin> g.V.as('x').outE('knows').inV.has('age', T.gt, 30).optional('x')
783
+ ==>v[3]
784
+ ==>v[2]
785
+ ==>v[1]
786
+ ==>v[6]
787
+ ==>v[5]
788
+ ==>v[4]
789
+
790
+ See Also: back
791
+
792
+ ### sideEffect
793
+
794
+ Emits input, but calls a side effect closure on each input.
795
+
796
+ gremlin> youngest = Integer.MAX_VALUE
797
+ ==>2147483647
798
+ gremlin> g.V.hasNot('age', null).sideEffect{youngest=youngest>it.age?it.age:youngest}
799
+ ==>v[2]
800
+ ==>v[1]
801
+ ==>v[6]
802
+ ==>v[4]
803
+ gremlin> youngest
804
+ ==>27
805
+
806
+ ### store
807
+
808
+ Emits input, but adds input to collection, where provided closure processes input prior to insertion (lazy). In being "lazy", 'store' will keep element as they are being requested.
809
+
810
+ gremlin> x = []
811
+ gremlin> g.v(1).out.store(x).next()
812
+ ==>v[2]
813
+ gremlin> x
814
+ ==>v[2]
815
+
816
+ See Also: aggregate fill
817
+
818
+ ### table
819
+
820
+ Emits input, but stores row of as values (constrained by column names if provided) in a table. Accepts an optional set of closures that are applied in round-robin fashion to each column of the table.
821
+
822
+ gremlin> t = new Table()
823
+ gremlin> g.V.name.as('name').back(1).age.as('age').table(t)
824
+ ==>null
825
+ ==>27
826
+ ==>29
827
+ ==>35
828
+ ==>null
829
+ ==>32
830
+ gremlin> t
831
+ ==>[name:lop, age:null]
832
+ ==>[name:vadas, age:27]
833
+ ==>[name:marko, age:29]
834
+ ==>[name:peter, age:35]
835
+ ==>[name:ripple, age:null]
836
+ ==>[name:josh, age:32]
837
+ gremlin> t = new Table()
838
+ gremlin> g.V.hasNot('age', null).name.as('name').back(1).age.as('age').table(t){it}{it>30 ? 'over thirty' : 'under thirty'}
839
+ ==>27
840
+ ==>29
841
+ ==>35
842
+ ==>32
843
+ gremlin> t
844
+ ==>[name:vadas, age:under thirty]
845
+ ==>[name:marko, age:under thirty]
846
+ ==>[name:peter, age:over thirty]
847
+ ==>[name:josh, age:over thirty]
848
+ gremlin> t.get(0,'name')
849
+ ==>vadas
850
+
851
+ ### tree
852
+
853
+ Emit input, but stores the tree formed by the traversal as a map. Accepts an optional set of closures to be applied in round-robin fashion over each level of the tree.
854
+
855
+ gremlin> g.v(1).out.out.tree.cap
856
+ ==>{v[1]={v[4]={v[3]={}, v[5]={}}}}
857
+ gremlin> g.v(1).out.out.tree{it.name}.cap
858
+ ==>{marko={josh={lop={}, ripple={}}}}
859
+ gremlin> g.v(1).out.out.tree{it.name}{"child1:" + it.name}{"child2:" + it.name}.cap
860
+ ==>{marko={child1:josh={child2:lop={}, child2:ripple={}}}}
861
+ gremlin> t = new Tree()
862
+ gremlin> g.v(1).out.out.tree(t){it.name}{"child1:" + it.name}{"child2:" + it.name}
863
+ ==>v[5]
864
+ ==>v[3]
865
+ gremlin> t.get('marko')
866
+ ==>child1:josh={child2:lop={}, child2:ripple={}}
867
+
868
+
869
+ ## Branch
870
+
871
+ Branch steps decide which step to take.
872
+
873
+ ### copySplit
874
+
875
+ Copies incoming object to internal pipes.
876
+
877
+ gremlin> g.v(1).out('knows').copySplit(_().out('created').name, _().age).fairMerge
878
+ ==>ripple
879
+ ==>27
880
+ ==>lop
881
+ ==>32
882
+ gremlin> g.v(1).out('knows').copySplit(_().out('created').name, _().age).exhaustMerge
883
+ ==>ripple
884
+ ==>lop
885
+ ==>27
886
+ ==>32
887
+
888
+ See Also: exhaustMerge fairMerge
889
+
890
+ ### exhaustMerge
891
+
892
+ Used in combination with a copySplit, merging the parallel traversals by exhaustively getting the objects of the first, then the second, etc.
893
+
894
+ gremlin> g.v(1).out('knows').copySplit(_().out('created').name, _().age).exhaustMerge
895
+ ==>ripple
896
+ ==>lop
897
+ ==>27
898
+ ==>32
899
+
900
+ See Also: copySplit fairMerge
901
+
902
+ ### fairMerge
903
+
904
+ Used in combination with a copySplit, merging the parallel traversals in a round-robin fashion.
905
+
906
+ gremlin> g.v(1).out('knows').copySplit(_().out('created').name, _().age).fairMerge
907
+ ==>ripple
908
+ ==>27
909
+ ==>lop
910
+ ==>32
911
+
912
+ See Also: copySplit exaustMerge
913
+
914
+ ### ifThenElse
915
+
916
+ Allows for if-then-else conditional logic.
917
+
918
+ gremlin> g.v(1).out.ifThenElse{it.name=='josh'}{it.age}{it.name}
919
+ ==>vadas
920
+ ==>32
921
+ ==>lop
922
+
923
+ ### loop
924
+
925
+ Loop over a particular set of steps in the pipeline. The first argument is either the number of steps back in the pipeline to go or a named step. The second argument is a while closure evaluating the current object. The it component of the loop step closure has three properties that are accessible. These properties can be used to reason about when to break out of the loop.
926
+
927
+ it.object: the current object of the traverser.
928
+ it.path: the current path of the traverser.
929
+ it.loops: the number of times the traverser has looped through the loop section.
930
+
931
+ The final argument is known as the "emit" closure. This boolean-based closure will determine wether the current object in the loop structure is emitted or not. As such, it is possible to emit intermediate objects, not simply those at the end of the loop.
932
+
933
+ gremlin> g.v(1).out.out
934
+ ==>v[5]
935
+ ==>v[3]
936
+ gremlin> g.v(1).out.loop(1){it.loops<3}
937
+ ==>v[5]
938
+ ==>v[3]
939
+ gremlin> g.v(1).out.loop(1){it.loops<3}{it.object.name=='josh'}
940
+ ==>v[4]
941
+
942
+
943
+ ## Methods
944
+
945
+ Methods represent functions that make it faster and easier to work with Blueprints and Pipes APIs. It is important to keep in mind that the full Java API and Groovy API are accessible from Gremlin.
946
+
947
+ ### Element.keys
948
+
949
+ Get the property keys of an element.
950
+
951
+ gremlin> g.v(1).keys()
952
+ ==>name
953
+ ==>age
954
+
955
+ ### Element.remove
956
+
957
+ Remove an element from the graph.
958
+
959
+ gremlin> g.E.weight
960
+ ==>1.0
961
+ ==>0.5
962
+ ==>0.4
963
+ ==>1.0
964
+ ==>0.4
965
+ ==>0.2
966
+ gremlin> g.E.has("weight",T.lt,0.5f).remove()
967
+ ==>null
968
+ gremlin> g.E.weight
969
+ ==>1.0
970
+ ==>0.5
971
+ ==>1.0
972
+
973
+ ### Element.values
974
+
975
+ Gets the property values of an element.
976
+
977
+ gremlin> g.v(1).values()
978
+ ==>marko
979
+ ==>29
980
+
981
+ ### Graph.addEdge
982
+
983
+ Adds an edge to the graph. Note that most graph implementations ignore the identifier supplied to addEdge.
984
+
985
+ gremlin> g = new TinkerGraph()
986
+ ==>tinkergraph[vertices:0 edges:0]
987
+ gremlin> v1 = g.addVertex(100)
988
+ ==>v[100]
989
+ gremlin> v2 = g.addVertex(200)
990
+ ==>v[200]
991
+ gremlin> g.addEdge(v1,v2,'friend')
992
+ ==>e[0][100-friend->200]
993
+ gremlin> g.addEdge(1000,v1,v2,'buddy')
994
+ ==>e[1000][100-buddy->200]
995
+ gremlin> g.addEdge(null,v1,v2,'pal',[weight:0.75f])
996
+ ==>e[1][100-pal->200]
997
+
998
+ ### Graph.addVertex
999
+
1000
+ Adds a vertex to the graph. Note that most graph implementations ignore the identifier supplied to addVertex.
1001
+
1002
+ gremlin> g = new TinkerGraph()
1003
+ ==>tinkergraph[vertices:0 edges:0]
1004
+ gremlin> g.addVertex()
1005
+ ==>v[0]
1006
+ gremlin> g.addVertex(100)
1007
+ ==>v[100]
1008
+ gremlin> g.addVertex(null,[name:"stephen"])
1009
+ ==>v[1]
1010
+
1011
+ ### Graph.e
1012
+
1013
+ Get an edge or set of edges by providing one or more edge identifiers. The identifiers must be the identifiers assigned by the underlying graph implementation.
1014
+
1015
+ gremlin> g.e(10)
1016
+ ==>e[10][4-created->5]
1017
+ gremlin> g.e(10,11,12)
1018
+ ==>e[10][4-created->5]
1019
+ ==>e[11][4-created->3]
1020
+ ==>e[12][6-created->3]
1021
+ gremlin> ids = [10,11,12]
1022
+ ==>10
1023
+ ==>11
1024
+ ==>12
1025
+ gremlin> g.e(ids.toArray())
1026
+ ==>e[10][4-created->5]
1027
+ ==>e[11][4-created->3]
1028
+ ==>e[12][6-created->3]
1029
+
1030
+ See Also: Graph.v
1031
+
1032
+ ### Graph.idx(String)
1033
+
1034
+ Get an manual index by its name.
1035
+
1036
+ gremlin> g.createIndex("my-index", Vertex.class)
1037
+ ==>index[my-index:Vertex]
1038
+ gremlin> myIdx = g.idx("my-index").put("name", "marko", g.v(1))
1039
+ ==>null
1040
+ gremlin> myIdx.getIndexName()
1041
+ ==>my-index
1042
+
1043
+ See Also: Index[Map.Entry]
1044
+
1045
+ ### Graph.load
1046
+
1047
+ Load a file from one of several standard formats such as GraphML, GML, or GraphSON.
1048
+
1049
+ gremlin> g = new TinkerGraph()
1050
+ ==>tinkergraph[vertices:0 edges:0]
1051
+ gremlin> g.loadGraphML('data/graph-example-1.xml')
1052
+ ==>null
1053
+ gremlin> g.V
1054
+ ==>v[3]
1055
+ ==>v[2]
1056
+ ==>v[1]
1057
+ ==>v[6]
1058
+ ==>v[5]
1059
+ ==>v[4]
1060
+
1061
+ See Also: Graph.save
1062
+
1063
+ ### Graph.removeEdge
1064
+
1065
+ Remove an edge.
1066
+
1067
+ gremlin> g = new TinkerGraph()
1068
+ ==>tinkergraph[vertices:0 edges:0]
1069
+ gremlin> v1 = g.addVertex()
1070
+ ==>v[100]
1071
+ gremlin> v2 = g.addVertex()
1072
+ ==>v[200]
1073
+ gremlin> g.addEdge(v1,v2,'friend')
1074
+ ==>e[0][100-friend->200]
1075
+ gremlin> g.removeEdge(g.e(0))
1076
+ ==>null
1077
+
1078
+ ### Graph.removeVertex
1079
+
1080
+ Remove a vertex.
1081
+
1082
+ gremlin> g.addVertex()
1083
+ ==>v[128]
1084
+ gremlin> g.removeVertex(g.v(128))
1085
+ ==>null
1086
+
1087
+ ### Graph.save
1088
+
1089
+ Save a graph to file given one of several standard formats such as GraphML, GML, or GraphSON.
1090
+
1091
+ gremlin> g.saveGraphML('data/graph.xml')
1092
+ ==>null
1093
+
1094
+ See Also: Graph.load
1095
+
1096
+ ### Graph.v
1097
+
1098
+ Get a vertex or set of vertices by providing one or more vertex identifiers. The identifiers must be the identifiers assigned by the underlying graph implementation.
1099
+
1100
+ gremlin> g.v(1)
1101
+ ==>v[1]
1102
+ gremlin> g.v(1,2,3)
1103
+ ==>v[1]
1104
+ ==>v[2]
1105
+ ==>v[3]
1106
+ gremlin> ids = [1,2,3]
1107
+ ==>1
1108
+ ==>2
1109
+ ==>3
1110
+ gremlin> g.v(ids.toArray())
1111
+ ==>v[1]
1112
+ ==>v[2]
1113
+ ==>v[3]
1114
+
1115
+ See Also: Graph.e
1116
+
1117
+ ### Index[Map.Entry]
1118
+
1119
+ Look up a value in an index.
1120
+
1121
+ gremlin> g.createIndex("my-index", Vertex.class)
1122
+ ==>index[my-index:Vertex]
1123
+ gremlin> g.idx("my-index").put("name", "marko", g.v(1))
1124
+ ==>null
1125
+ gremlin> g.idx("my-index")[[name:"marko"]]
1126
+ ==>v[1]
1127
+
1128
+ See Also: Graph.idx(String)
1129
+
1130
+ ### Pipe.fill
1131
+
1132
+ Takes all the results in the pipeline and puts them into the provided collection.
1133
+
1134
+ gremlin> m = []
1135
+ gremlin> g.v(1).out.fill(m)
1136
+ ==>v[2]
1137
+ ==>v[4]
1138
+ ==>v[3]
1139
+ gremlin> m
1140
+ ==>v[2]
1141
+ ==>v[4]
1142
+ ==>v[3]
1143
+
1144
+ See Also: aggregate store
1145
+
1146
+ ### Pipe.iterate
1147
+
1148
+ Calls Pipe.next for all objects in the pipe. This is an important notion to follow when considering the behavior of the Gremlin Console. The Gremlin Console iterates through the pipeline automatically and outputs the results. Outside of the Gremlin Console or if more than one statement is present on a single line of the Gremlin Console, iterating the pipe must be done manually. Read more about this topic in the Gremlin Wiki Troubleshooting Page.
1149
+
1150
+ There are some important things to note in the example below. Had the the first line of Gremlin been executed separately, as opposed to being placed on the same line separated by a semi-colon, the names of all the vertices would have changed because the Gremlin Console would have automatically iterated the pipe and processed the side-effects.
1151
+
1152
+ gremlin> g.V.sideEffect{it.name="same-again"};g.V.name
1153
+ ==>lop
1154
+ ==>vadas
1155
+ ==>marko
1156
+ ==>peter
1157
+ ==>ripple
1158
+ ==>josh
1159
+ gremlin> g.V.sideEffect{it.name="same"}.iterate();g.V.name
1160
+ ==>same
1161
+ ==>same
1162
+ ==>same
1163
+ ==>same
1164
+ ==>same
1165
+ ==>same
1166
+
1167
+ See Also: Pipe.next
1168
+
1169
+ ### Pipe.next
1170
+
1171
+ Gets the next object in the pipe or the next n objects. This is an important notion to follow when considering the behavior of the Gremlin Console. The Gremlin Console iterates through the pipeline automatically and outputs the results. Outside of the Gremlin Console or if more than one statement is present on a single line of the Gremlin Console, iterating the pipe must be done manually. Read more about this topic in the Gremlin Wiki Troubleshooting Page.
1172
+
1173
+ There are some important things to note in the example below. Had the the first line of Gremlin been executed separately, as opposed to being placed on the same line separated by a semi-colon, the name of the vertex would have changed because the Gremlin Console would have automatically iterated the pipe and processed the side-effect.
1174
+
1175
+ gremlin> g.v(1).sideEffect{it.name="same"};g.v(1).name
1176
+ ==>marko
1177
+ gremlin> g.v(1).sideEffect{it.name="same"}.next();g.v(1).name
1178
+ ==>same
1179
+ gremlin> g.V.sideEffect{it.name="same-again"}.next(3);g.V.name
1180
+ ==>same-again
1181
+ ==>same-again
1182
+ ==>same-again
1183
+ ==>peter
1184
+ ==>ripple
1185
+ ==>josh
1186
+
1187
+ See Also: Pipe.iterate
1188
+
1189
+
1190
+ ## Recipes
1191
+
1192
+ Recipes are common patterns that are seen in using Gremlin.
1193
+ Duplicate Edges
1194
+
1195
+ Strictly speaking, you cannot have duplicated egdes with the same id. This example finds edges with same outV/inV/label properties.
1196
+
1197
+ gremlin> g = TinkerGraphFactory.createTinkerGraph()
1198
+ ==>tinkergraph[vertices:6 edges:6]
1199
+ gremlin> g.v(1).outE('created')
1200
+ ==>e[9][1-created->3]
1201
+ gremlin> g.addEdge(null, g.v(1), g.v(3), "created", g.e(9).map()) // see note
1202
+ ==>e[0][1-created->3]
1203
+ gremlin> g.v(1).outE('created')
1204
+ ==>e[0][1-created->3]
1205
+ ==>e[9][1-created->3]
1206
+ gremlin> ElementHelper.haveEqualProperties(g.e(9), g.e(0))
1207
+ ==>true
1208
+ gremlin> e = g.e(9)
1209
+ ==>e[9][1-created->3]
1210
+ gremlin> e.outV.outE(e.label).filter{ElementHelper.haveEqualProperties(e,it)}.as('e').inV.filter{it==e.inV.next()}.back('e').except([e])
1211
+ ==>e[0][1-created->3]
1212
+
1213
+ ### Hiding Console Output
1214
+
1215
+ The Gremlin Console automatically iterates the pipe and outputs the results to the console. In some cases, this can lead to lots of screen output that isn't terribly useful. To suppress the output, consider the following:
1216
+
1217
+ gremlin> g.V.sideEffect{it.name='changed'}
1218
+ ==>v[3]
1219
+ ==>v[2]
1220
+ ==>v[1]
1221
+ ==>v[6]
1222
+ ==>v[5]
1223
+ ==>v[4]
1224
+ gremlin> g.V.sideEffect{it.name='changed-again'}.iterate()
1225
+ ==>null
1226
+ gremlin> g.V.name
1227
+ ==>changed-again
1228
+ ==>changed-again
1229
+ ==>changed-again
1230
+ ==>changed-again
1231
+ ==>changed-again
1232
+ ==>changed-again
1233
+ gremlin> t = g.v(1).out.tree.cap.next()
1234
+ ==>v[1]={v[3]={}, v[2]={}, v[4]={}}
1235
+ gremlin> t
1236
+ ==>v[1]={v[3]={}, v[2]={}, v[4]={}}
1237
+ gremlin> s = g.v(1).out.tree.cap.next();null
1238
+ ==>null
1239
+ gremlin> s
1240
+ ==>v[1]={v[3]={}, v[2]={}, v[4]={}}
1241
+
1242
+ See Also: Pipe.iterate Pipe.next
1243
+
1244
+ ### Paging Results
1245
+
1246
+ It is sometimes desireable to not return an entire results set. Results can be paged or limited as follows:
1247
+
1248
+ gremlin> g.V.has("age", T.gte, 25)
1249
+ ==>v[2]
1250
+ ==>v[1]
1251
+ ==>v[6]
1252
+ ==>v[4]
1253
+ gremlin> g.V.has("age", T.gte, 29)
1254
+ ==>v[1]
1255
+ ==>v[6]
1256
+ ==>v[4]
1257
+ gremlin> g.V.has("age", T.gte, 29)[0..1]
1258
+ ==>v[1]
1259
+ ==>v[6]
1260
+ gremlin> g.V.has("age", T.gte, 29)[0..<1]
1261
+ ==>v[1]
1262
+ gremlin> g.V.has("age", T.gte, 29)[1..2]
1263
+ ==>v[6]
1264
+ ==>v[4]
1265
+
1266
+ ### Reading From a File
1267
+
1268
+ Reading data from an edge file formatted as CSV is easy to do with Gremlin.
1269
+
1270
+ gremlin> g = new TinkerGraph()
1271
+ ==>tinkergraph[vertices:0 edges:0]
1272
+ gremlin> vs=[] as Set;new
1273
+ File("edges.txt").eachLine{l->p=l.split(",");vs<<p[0];vs<<p[1];}
1274
+ ==>1
1275
+ ==>2
1276
+ ==>3
1277
+ ==>4
1278
+ gremlin> vs.each{v->g.addVertex(v)}
1279
+ ==>1
1280
+ ==>2
1281
+ ==>3
1282
+ ==>4
1283
+ gremlin> new File("edges.txt").eachLine{l->p=l.split(",");g.addEdge(g.getVertex(p[0]),g.getVertex(p[1]),'friend')}
1284
+ gremlin> g.E
1285
+ ==>e[3][1-friend->4]
1286
+ ==>e[2][3-friend->4]
1287
+ ==>e[1][2-friend->3]
1288
+ ==>e[0][1-friend->2]
1289
+
1290
+ ### Sampling
1291
+
1292
+ It is sometimes useful to grab a random sample of the items in a collection. That can be done to some degree with the random step, but getting an explicit number of items is not supported using that step.
1293
+
1294
+ gremlin> g.v(1).out.shuffle
1295
+ ==>v[2]
1296
+ ==>v[3]
1297
+ ==>v[4]
1298
+ gremlin> g.v(1).out.shuffle
1299
+ ==>v[3]
1300
+ ==>v[2]
1301
+ ==>v[4]
1302
+ gremlin> g.v(1).out.random(0.5)
1303
+ ==>v[2]
1304
+ gremlin> g.v(1).out.random(0.5)
1305
+ ==>v[4]
1306
+ ==>v[3]
1307
+
1308
+ ### Shortest Path
1309
+
1310
+ Finding the shortest path between two vertices can be accomplished with a loop. The following example shows the shortest path between vertex 1 and vertex 5 and if such path cannot be found in five steps, break out of the computation.
1311
+
1312
+ gremlin> g.v(1).out.loop(1){it.object.id != "5" && it.loops < 6}.path
1313
+ ==>[v[1], v[4], v[5]]
1314
+
1315
+ In the event there are multiple paths to 5, all paths will be output and the shortest path will need to be selected. The following example adds some edges to the toy graph to demonstrate a path length distribution:
1316
+
1317
+ gremlin> g.addEdge(g.v(3), g.v(5), 'created')
1318
+ ==>e[0][3-created->5]
1319
+ gremlin> g.addEdge(g.v(1), g.v(5), 'created')
1320
+ ==>e[1][1-created->5]
1321
+ gremlin> g.v(1).out.loop(1){it.object.id!="5" && it.loops < 6}.path{it.name}
1322
+ ==>[marko, ripple]
1323
+ ==>[marko, josh, ripple]
1324
+ ==>[marko, lop, ripple]
1325
+ ==>[marko, josh, lop, ripple]
1326
+ gremlin> g.v(1).out.loop(1){it.object.id!="5" && it.loops < 6}.path{it.name}.groupBy{it.size()}{it}.cap.next()
1327
+ ==>2=[[marko, ripple]]
1328
+ ==>3=[[marko, josh, ripple], [marko, lop, ripple]]
1329
+ ==>4=[[marko, josh, lop, ripple]]
1330
+
1331
+ Starting with a new "toy" TinkerGraph, calculating the "cost" of the path (in this case utilizing the weight stored on the edges), can be accomplished with:
1332
+
1333
+ gremlin> g = TinkerGraphFactory.createTinkerGraph()
1334
+ ==>tinkergraph[vertices:6 edges:6]
1335
+ gremlin> g.v(1).outE.inV.loop(2){it.object.id!="3" && it.loops < 6}.path.transform{[it.findAll{it instanceof Edge}.sum{it.weight}, it]}
1336
+ ==>[0.4, [v[1], e[9][1-created->3], v[3]]]
1337
+ ==>[1.4000000059604645, [v[1], e[8][1-knows->4], v[4], e[11][4-created->3], v[3]]]
1338
+
1339
+ Evaluating a shortest path between two vertices in both directions (in and out edges) can be expensive. Consider this example:
1340
+
1341
+ gremlin> g = new TinkerGraph()
1342
+ ==>tinkergraph[vertices:0 edges:0]
1343
+ gremlin>
1344
+ gremlin> root = g.addVertex()
1345
+ ==>v[0]
1346
+ gremlin>
1347
+ gremlin> (1..10).each { outer ->
1348
+ gremlin> parent = root
1349
+ gremlin> (1..10).each { inner ->
1350
+ gremlin> child = g.addVertex()
1351
+ gremlin> g.addEdge(parent, child, 'to')
1352
+ gremlin> parent = child
1353
+ gremlin> }
1354
+ gremlin> }; null
1355
+ ==>null
1356
+
1357
+ Given the sample graph generated above, the following uses the same pattern shown above for finding the shortest path, but evaulates both incoming and outgoing edges (prior examples only evaluated outgoing edges).
1358
+
1359
+ gremlin> target = '99'; c = 0; root.both().sideEffect{c++}.loop(2){it.object.id != target && it.loops <= 10}.has('id',target).path().iterate(); c
1360
+ ==>557670
1361
+
1362
+ The above example shows that 557,670 vertices were touched in the above traversal. Adapting this traversal slightly to use the store/except pattern makes it far more efficient, touching only 100 vertices) as shown below:
1363
+
1364
+ gremlin> s = [root] as Set
1365
+ ==>v[0]
1366
+ gremlin> target = '99'; c = 0; root.both().except(s).store(s).sideEffect{c++}.loop(4){it.object.id != target && it.loops <= 10}.has('id',target).path().iterate(); c
1367
+ ==>100
1368
+
1369
+ ### Subgraphing
1370
+
1371
+ Extracting a portion of a graph out of another graph by side-effecting out graph elements to another graph. Using a TinkerGraph as the host for the subgraph is best (as memory allows), since TinkerGraph will preserve element identifiers after the extractions.
1372
+
1373
+ // the goal is to extract the "knows" subgraph
1374
+ gremlin> g.E.has('label','knows')
1375
+ ==>e[7][1-knows->2]
1376
+ ==>e[8][1-knows->4]
1377
+
1378
+ // this is the target subgraph
1379
+ gremlin> sg = new TinkerGraph()
1380
+ ==>tinkergraph[vertices:0 edges:0]
1381
+
1382
+ // define a "Get Or Create" function for vertices...use ElementHelper to copy properties
1383
+ gremlin> def goc(v,g){nv=g.getVertex(v.id);if(nv==null){nv=g.addVertex(v.id,ElementHelper.getProperties(v))};nv}
1384
+ ==>true
1385
+
1386
+ // generate the subgraph by side-effecting graph elements into new graph
1387
+ gremlin> g.E.has('label','knows').sideEffect{sg.addEdge(it.id,goc(it.outV.next(),sg),goc(it.inV.next(),sg),it.label,ElementHelper.getProperties(it))}.iterate()
1388
+ ==>null
1389
+ gremlin> sg.E
1390
+ ==>e[7][1-knows->2]
1391
+ ==>e[8][1-knows->4]
1392
+
1393
+ ### Writing To File
1394
+
1395
+ TinkerPop supports a number of different graph file formats, like GraphML, GML, and GraphSON, but sometimes a custom format or just a simple edge list is desireable. The following code shows how to open a file and side-effect out a comma-separated file of in and out vertices for each edge in the graph.
1396
+
1397
+ gremlin> new File("/tmp/edge-set.txt").withWriter{f -> g.E.sideEffect{f << "${it.outV.id.next()},${it.inV.id.next()}\r\n"}.iterate()}
1398
+ ==>null