agent-docs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/plans/OPTIMISE.md +379 -0
- package/.cursor/plans/VERSIONING.md +207 -0
- package/.cursor/rules/IMPORTANT.mdc +97 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +13 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
- package/.github/dependabot.yml +38 -0
- package/.github/pull_request_template.md +10 -0
- package/.github/workflows/format.yml +35 -0
- package/CODE_OF_CONDUCT.md +64 -0
- package/CONTRIBUTING.md +52 -0
- package/LICENSE.md +20 -0
- package/PLAN.md +707 -0
- package/README.md +133 -0
- package/SECURITY.md +21 -0
- package/docs/APEXANNOTATIONS.md +472 -0
- package/docs/APEXDOC.md +198 -0
- package/docs/CML.md +877 -0
- package/docs/CODEANALYZER.md +435 -0
- package/docs/CONTEXTDEFINITIONS.md +617 -0
- package/docs/ESLINT.md +827 -0
- package/docs/ESLINTJSDOC.md +520 -0
- package/docs/FIELDSERVICE.md +4452 -0
- package/docs/GRAPHBINARY.md +208 -0
- package/docs/GRAPHENGINE.md +616 -0
- package/docs/GRAPHML.md +337 -0
- package/docs/GRAPHSON.md +302 -0
- package/docs/GREMLIN.md +490 -0
- package/docs/GRYO.md +232 -0
- package/docs/HUSKY.md +106 -0
- package/docs/JEST.md +387 -0
- package/docs/JORJE.md +537 -0
- package/docs/JSDOC.md +621 -0
- package/docs/PMD.md +910 -0
- package/docs/PNPM.md +409 -0
- package/docs/PRETTIER.md +716 -0
- package/docs/PRETTIERAPEX.md +874 -0
- package/docs/REVENUETRANSACTIONMANAGEMENT.md +887 -0
- package/docs/TINKERPOP.md +252 -0
- package/docs/VITEST.md +706 -0
- package/docs/VSCODE.md +231 -0
- package/docs/XPATH31.md +213 -0
- package/package.json +32 -0
- package/postinstall.mjs +51 -0
- package/prettier.config.js +18 -0
package/docs/GREMLIN.md
ADDED
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
````markdown
|
|
2
|
+
# Gremlin Query Language Reference
|
|
3
|
+
|
|
4
|
+
> **Version**: 1.0.0
|
|
5
|
+
|
|
6
|
+
Functional graph traversal lang. Apache TinkerPop/SFGE. Multi-lang
|
|
7
|
+
(Java/Groovy/Python/JS/.NET). OLTP/OLAP.
|
|
8
|
+
|
|
9
|
+
**Related:** GRAPHENGINE.md, TINKERPOP.md, GRAPHML.md, GRAPHSON.md, GRYO.md,
|
|
10
|
+
GRAPHBINARY.md, CODEANALYZER.md
|
|
11
|
+
|
|
12
|
+
**Variants:** Gremlin-Java (core), -Groovy (console), -Python, -JavaScript,
|
|
13
|
+
-.NET. Syntax parity.
|
|
14
|
+
|
|
15
|
+
**Note:** Devs don't write Gremlin directly—SFGE handles graph ops internally
|
|
16
|
+
via TinkerPop.
|
|
17
|
+
|
|
18
|
+
## Core Concepts
|
|
19
|
+
|
|
20
|
+
- **Traversal**: Graph movement V→V via E. Step chain=query. Lazy (exec on
|
|
21
|
+
terminal)
|
|
22
|
+
- **Steps**: Transform traversers: `out()`,`has()`,`where()`. Atomic, composable
|
|
23
|
+
- **Traversers**: Objects moving through graph. Carry data/state. Fork/merge.
|
|
24
|
+
Track path/side-effects
|
|
25
|
+
- **Path**: V/E sequence visited. Get via `path()`
|
|
26
|
+
- **GraphTraversal**: Step chain. Extends `Traversal<S,E>`. Method chaining.
|
|
27
|
+
Immutable
|
|
28
|
+
- **Side-Effects**: Stored values: `aggregate()`,`store()`. Get via `cap()`
|
|
29
|
+
- **Stream Nature**: Traversals=data streams. Steps transform stream
|
|
30
|
+
|
|
31
|
+
## Anatomy
|
|
32
|
+
|
|
33
|
+
Ref: TinkerPop 3.8.0 Anatomy Tutorial
|
|
34
|
+
|
|
35
|
+
```groovy
|
|
36
|
+
g.V().has('person','name',within('marko','josh')).outE().groupCount().by(label()).next()
|
|
37
|
+
```
|
|
38
|
+
````
|
|
39
|
+
|
|
40
|
+
Components:
|
|
41
|
+
|
|
42
|
+
1. **GraphTraversalSource** (`g`) - Spawns traversals
|
|
43
|
+
2. **GraphTraversal** (`has()`,`outE()`,`groupCount()`) - Chained steps
|
|
44
|
+
3. **Step Modulators** (`by()`) - Modify step behavior
|
|
45
|
+
4. **Anonymous Traversals** (`label()`) - Unbound traversals as args
|
|
46
|
+
5. **Terminal Steps** (`next()`) - Return results, not traversals
|
|
47
|
+
6. **Expressions** (`within()`) - Helper classes/enums
|
|
48
|
+
|
|
49
|
+
### GraphTraversalSource
|
|
50
|
+
|
|
51
|
+
Start point. Var `g` convention.
|
|
52
|
+
|
|
53
|
+
```groovy
|
|
54
|
+
graph = TinkerGraph.open()
|
|
55
|
+
g = graph.traversal()
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Config (prefixed "with"):
|
|
59
|
+
|
|
60
|
+
```groovy
|
|
61
|
+
g.withStrategies(SubgraphStrategy.build().vertices(hasLabel('person')).create()).V()
|
|
62
|
+
g.withSack(1.0f).V().sack()
|
|
63
|
+
g.withComputer().V().pageRank()
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Methods:
|
|
67
|
+
`V(id)`,`E(id)`,`addV(label)`,`addE(label)`,`withStrategies()`,`withoutStrategies()`,`withSideEffect()`,`withBindings()`,`withSack()`,`withComputer()`,`getGraph()`,`clone()`
|
|
68
|
+
|
|
69
|
+
Traversal interface:
|
|
70
|
+
`hasNext()`,`next()`,`tryNext()`,`toList()`,`toSet()`,`toBulkSet()`,`iterate()`,`explain()`,`profile()`,`cap()`,`as()`,`by()`,`isExhausted()`,`close()`
|
|
71
|
+
|
|
72
|
+
### GraphTraversal
|
|
73
|
+
|
|
74
|
+
From start steps. Returns `GraphTraversal` (fluent). Output→Input:
|
|
75
|
+
|
|
76
|
+
```groovy
|
|
77
|
+
g.V() // →Vertex
|
|
78
|
+
.has('person','name',within('marko','josh')) // V→V (filter)
|
|
79
|
+
.outE() // V→E
|
|
80
|
+
.groupCount().by(label()) // E→Map
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Step Modulators
|
|
84
|
+
|
|
85
|
+
Modify prev step: `by()` (grouping/ordering/transform), `as()` (label ref),
|
|
86
|
+
`option()` (branches for `choose()`/`mergeV()`/`mergeE()`)
|
|
87
|
+
|
|
88
|
+
### Anonymous Traversals
|
|
89
|
+
|
|
90
|
+
Unbound from `__` class (typically static import):
|
|
91
|
+
|
|
92
|
+
```groovy
|
|
93
|
+
by(label()) // = by(__.label())
|
|
94
|
+
where(out('knows'))
|
|
95
|
+
coalesce(out(), in())
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Terminal Steps
|
|
99
|
+
|
|
100
|
+
Execute, return results (not `GraphTraversal`): `next()` (throws if none),
|
|
101
|
+
`hasNext()` (bool), `tryNext()` (Optional), `toList()`/`toSet()` (collect),
|
|
102
|
+
`iterate()` (side-effects only)
|
|
103
|
+
|
|
104
|
+
### Result Iteration
|
|
105
|
+
|
|
106
|
+
```groovy
|
|
107
|
+
g.V().hasLabel('person').forEachRemaining { v -> println(v.value('name')) }
|
|
108
|
+
def t = g.V().hasLabel('person'); while (t.hasNext()) { processVertex(t.next()) }
|
|
109
|
+
def vertices = g.V().hasLabel('person').toList()
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Best: `forEachRemaining()` streaming, `toList()` batch, check `hasNext()`/use
|
|
113
|
+
`tryNext()`, close traversals, prefer streaming large sets.
|
|
114
|
+
|
|
115
|
+
### Expressions
|
|
116
|
+
|
|
117
|
+
**P (Predicates):**
|
|
118
|
+
`eq()`,`neq()`,`lt()`,`lte()`,`gt()`,`gte()`,`between()`,`inside()`,`outside()`,`within()`,`without()`
|
|
119
|
+
**T (Tokens):** `T.id`,`T.label` **Order:** `Order.asc`,`Order.desc` **Merge:**
|
|
120
|
+
`Merge.onCreate`,`Merge.onMatch`
|
|
121
|
+
|
|
122
|
+
## Step Reference
|
|
123
|
+
|
|
124
|
+
**Navigation:**
|
|
125
|
+
`V(id)`,`E(id)`,`out(label)`,`in(label)`,`both(label)`,`outE(label)`,`inE(label)`,`bothE(label)`,`outV()`,`inV()`,`bothV()`
|
|
126
|
+
|
|
127
|
+
**Filtering:**
|
|
128
|
+
`has(key,value)`,`has(key)`,`has(key,predicate)`,`hasLabel(label)`,`hasId(id)`,`where(predicate)`,`filter(predicate)`,`and(...)`,`or(...)`,`not(step)`,`simplePath()`,`cyclicPath()`
|
|
129
|
+
|
|
130
|
+
**Value Extraction:**
|
|
131
|
+
`values(key)`,`valueMap()`,`elementMap()`,`properties()`,`id()`,`label()`
|
|
132
|
+
|
|
133
|
+
**Modification:**
|
|
134
|
+
`addV(label)`,`addE(label)`,`property(key,value)`,`drop()`,`mergeV()`,`mergeE()`
|
|
135
|
+
|
|
136
|
+
**Path/Collection:**
|
|
137
|
+
`path()`,`simplePath()`,`cyclicPath()`,`limit(n)`,`range(start,end)`,`count()`,`dedup()`,`order()`,`group()`,`groupCount()`,`fold()`,`unfold()`,`subgraph(key)`
|
|
138
|
+
|
|
139
|
+
**Control Flow:**
|
|
140
|
+
`repeat(step)`,`until(cond)`,`emit(cond)`,`times(n)`,`loops()`,`coalesce(...)`,`optional(step)`,`union(...)`,`choose(pred,true,false)`,`match(...)`,`branch(step)`
|
|
141
|
+
|
|
142
|
+
**Side Effects:**
|
|
143
|
+
`sideEffect(step)`,`store(key)`,`aggregate(key)`,`cap(key)`,`inject(...)`
|
|
144
|
+
|
|
145
|
+
**Terminal:** `next()`,`toList()`,`toSet()`,`iterate()`
|
|
146
|
+
|
|
147
|
+
**Transformation:**
|
|
148
|
+
`map(step)`,`flatMap(step)`,`project(...)`,`select(...)`,`constant(value)`
|
|
149
|
+
|
|
150
|
+
**Aggregation:**
|
|
151
|
+
`count()`,`sum()`,`mean()`,`max()`,`min()`,`group()`,`groupCount()`
|
|
152
|
+
|
|
153
|
+
**String:**
|
|
154
|
+
`concat()`,`split()`,`substring()`,`toLower()`,`toUpper()`,`trim()`,`replace()`,`format()`
|
|
155
|
+
**Date:** `asDate()`,`dateAdd()`,`dateDiff()` **Type:**
|
|
156
|
+
`asString()`,`asNumber()`,`asBool()`
|
|
157
|
+
|
|
158
|
+
## Advanced Semantics
|
|
159
|
+
|
|
160
|
+
### Null Values (3.5.0+)
|
|
161
|
+
|
|
162
|
+
`null` preserved as traverser (not filtered):
|
|
163
|
+
|
|
164
|
+
```groovy
|
|
165
|
+
g.V().coalesce(values('age'), constant(null)) // →29,27,null,32,null,35
|
|
166
|
+
g.V().coalesce(values('age'), constant(null))
|
|
167
|
+
.choose(is(null), constant('nulled'), constant('not nulled'))
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### constant() vs inject()
|
|
171
|
+
|
|
172
|
+
| `constant()` | `inject()` |
|
|
173
|
+
| ---------------------------------- | ------------------------------ |
|
|
174
|
+
| Map step—transforms each traverser | Start step—inserts into stream |
|
|
175
|
+
| Called per traverser | Called once mid-traversal |
|
|
176
|
+
|
|
177
|
+
```groovy
|
|
178
|
+
g.V().has('person','name',within('josh','marko')).constant('c') // →c,c
|
|
179
|
+
g.V().has('person','name','marko').inject('i') // →i,v[1]
|
|
180
|
+
g.inject(1,2,3).constant('person').addV() // 3 vertices, all 'person'
|
|
181
|
+
g.inject(1,2,3).inject('person').addV() // 4 vertices, mixed labels
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### fold()/unfold()
|
|
185
|
+
|
|
186
|
+
`fold()`: stream→List; `unfold()`: List→stream
|
|
187
|
+
|
|
188
|
+
**Critical in `by()` modulators** (only calls `next()` once):
|
|
189
|
+
|
|
190
|
+
```groovy
|
|
191
|
+
// Without fold: first only
|
|
192
|
+
g.V().has('person','name','marko').project('name','knows')
|
|
193
|
+
.by('name').by(out('knows').values('name')) // →[name:marko,knows:vadas]
|
|
194
|
+
|
|
195
|
+
// With fold: all
|
|
196
|
+
g.V().has('person','name','marko').project('name','knows')
|
|
197
|
+
.by('name').by(out('knows').values('name').fold()) // →[name:marko,knows:[vadas,josh]]
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Static vs Dynamic Maps
|
|
201
|
+
|
|
202
|
+
```groovy
|
|
203
|
+
// Static: shared instance
|
|
204
|
+
g.inject(0).project('x').by(constant([y:0]))
|
|
205
|
+
// Dynamic: new per traverser
|
|
206
|
+
g.inject(0).project('x').by(constant(0).project('y').by(constant(0)))
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Maps as Keys
|
|
210
|
+
|
|
211
|
+
Some langs don't support map dict keys. Solutions: convert to lists, string
|
|
212
|
+
keys, flatten structure.
|
|
213
|
+
|
|
214
|
+
## Stream Patterns
|
|
215
|
+
|
|
216
|
+
Traversers flow through pipeline. Transform/filter/split/merge. Lazy eval.
|
|
217
|
+
|
|
218
|
+
Iterator types:
|
|
219
|
+
`Iterator<Vertex>`,`Iterator<Edge>`,`Iterator<Object>`,`Iterator<Path>`,`Iterator<Map>`
|
|
220
|
+
|
|
221
|
+
```groovy
|
|
222
|
+
// Filter-Transform-Collect
|
|
223
|
+
g.V().has('country','US').values('code').order().limit(10).toList()
|
|
224
|
+
// Branch-Process-Merge
|
|
225
|
+
g.V().has('code','AUS').choose(values('type'),
|
|
226
|
+
option('airport', out('route')),
|
|
227
|
+
option('country', in('contains')))
|
|
228
|
+
// Aggregate-Process
|
|
229
|
+
g.V().has('code','AUS').aggregate('visited').out('route')
|
|
230
|
+
.where(without('visited')).values('code')
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Best: filter early, appropriate terminals, avoid unnecessary steps, handle
|
|
234
|
+
empty, limit large.
|
|
235
|
+
|
|
236
|
+
## Examples
|
|
237
|
+
|
|
238
|
+
```groovy
|
|
239
|
+
// Basic
|
|
240
|
+
g.V(); g.V(1); g.V().hasLabel('airport')
|
|
241
|
+
g.V().has('code','AUS').out(); g.V().has('code','AUS').values('name')
|
|
242
|
+
g.V().has('code','AUS').elementMap()
|
|
243
|
+
|
|
244
|
+
// Filter/Project
|
|
245
|
+
g.V().has('country','US').has('type','airport')
|
|
246
|
+
g.V().where(out().count().is(gt(10)))
|
|
247
|
+
g.V().hasLabel('airport').project('code','name','city').by('code').by('name').by('city')
|
|
248
|
+
|
|
249
|
+
// Pattern Match
|
|
250
|
+
g.V().has('code','AUS').match(
|
|
251
|
+
__.as('a').out('route').as('b'),
|
|
252
|
+
__.as('b').out('route').as('c')).select('a','b','c')
|
|
253
|
+
|
|
254
|
+
// Aggregation
|
|
255
|
+
g.V().count()
|
|
256
|
+
g.V().hasLabel('airport').groupCount().by('country')
|
|
257
|
+
g.V().hasLabel('airport').order().by('code',Order.asc)
|
|
258
|
+
|
|
259
|
+
// Mutations
|
|
260
|
+
g.addV('airport').property('code','XYZ').next()
|
|
261
|
+
g.V().has('code','AUS').addE('route').to(__.V().has('code','DFW')).next()
|
|
262
|
+
g.V().has('code','XYZ').drop().iterate()
|
|
263
|
+
g.mergeV().has('airport','code','XYZ')
|
|
264
|
+
.option(Merge.onCreate, __.property('name','New'))
|
|
265
|
+
.option(Merge.onMatch, __.property('name','Existing')).next()
|
|
266
|
+
|
|
267
|
+
// Recursive
|
|
268
|
+
g.V().has('code','AUS').repeat(out('route')).until(has('code','DFW')).path()
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Supernodes
|
|
272
|
+
|
|
273
|
+
High-degree vertices→perf issues. Mitigate:
|
|
274
|
+
|
|
275
|
+
```groovy
|
|
276
|
+
g.V().has('code','ATL').out('route').limit(10)
|
|
277
|
+
g.V().has('code','ATL').outE('route').has('distance',lt(1000)).inV()
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Semantics
|
|
281
|
+
|
|
282
|
+
**Numeric promotion:** int→long→double (auto) **Type ops:** equality (same val),
|
|
283
|
+
comparability (<,>,<=,>=), orderability (sort), equivalence (equal/comparable)
|
|
284
|
+
**Step semantics:** domain (input), range (output), modulation capability
|
|
285
|
+
**Categories:** Navigation, Filtering, Transformation, Side-Effect, Barrier,
|
|
286
|
+
Control Flow, String, Date, Type Conversion, Collection
|
|
287
|
+
|
|
288
|
+
## Version Updates
|
|
289
|
+
|
|
290
|
+
### 3.5/3.6
|
|
291
|
+
|
|
292
|
+
New: `mergeV()`,`mergeE()`,`elementMap()` Deprecated:
|
|
293
|
+
`Order.incr`/`Order.decr`→`Order.asc`/`Order.desc` Enhanced drivers, GraphBinary
|
|
294
|
+
|
|
295
|
+
### 3.8.0
|
|
296
|
+
|
|
297
|
+
Enhanced semantics, Gremlin MCP Server, perf improvements, 4.0.0 prep. Check
|
|
298
|
+
release notes.
|
|
299
|
+
|
|
300
|
+
## Recipes
|
|
301
|
+
|
|
302
|
+
Ref: TinkerPop 3.8.0 Recipes
|
|
303
|
+
|
|
304
|
+
```groovy
|
|
305
|
+
// Between Vertices
|
|
306
|
+
g.V(1).bothE().where(otherV().hasId(2))
|
|
307
|
+
g.V(v1).outE().where(inV().is(v2))
|
|
308
|
+
|
|
309
|
+
// Centrality
|
|
310
|
+
g.V().project('vertex','degree').by(id()).by(bothE().count())
|
|
311
|
+
|
|
312
|
+
// Collections
|
|
313
|
+
g.V().hasLabel('person').fold()
|
|
314
|
+
g.V().hasLabel('person').aggregate('people').cap('people')
|
|
315
|
+
|
|
316
|
+
// Cycle Detection
|
|
317
|
+
g.V().as('start').repeat(out().simplePath()).until(cyclicPath()).path()
|
|
318
|
+
.where(unfold().is(select('start')))
|
|
319
|
+
|
|
320
|
+
// Get or Create (coalesce pattern)
|
|
321
|
+
// fold()→list, unfold() returns existing if non-empty, else addV()
|
|
322
|
+
g.V().has('name','Alice').fold()
|
|
323
|
+
.coalesce(unfold(), addV('person').property('name','Alice'))
|
|
324
|
+
|
|
325
|
+
// Pagination
|
|
326
|
+
g.V().hasLabel('person').order().by('name').range(10,20)
|
|
327
|
+
|
|
328
|
+
// Shortest Path
|
|
329
|
+
g.V().has('code','AUS').repeat(out('route').simplePath())
|
|
330
|
+
.until(has('code','DFW')).limit(1).path()
|
|
331
|
+
|
|
332
|
+
// Looping
|
|
333
|
+
g.V().has('code','AUS').repeat(out('route')).times(5).dedup() // fixed depth
|
|
334
|
+
g.V().has('code','AUS').repeat(out('route').simplePath()).until(has('code','DFW')).path() // conditional
|
|
335
|
+
g.V().has('code','AUS').repeat(out('route').simplePath()).emit().times(3)
|
|
336
|
+
.project('vertex','depth').by('code').by(loops()) // emit at levels
|
|
337
|
+
|
|
338
|
+
// times(0) Semantics
|
|
339
|
+
repeat(...).times(0) // do/while: exec once
|
|
340
|
+
times(0).repeat(...) // while/do: skip
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Anti-Patterns
|
|
344
|
+
|
|
345
|
+
- Long traversals→break smaller
|
|
346
|
+
- Unspecified labels→always `hasLabel()`
|
|
347
|
+
- Unnecessary steps→remove non-contributing
|
|
348
|
+
- `has()` without label→use `has(label,key,value)`
|
|
349
|
+
|
|
350
|
+
## SQL→Gremlin
|
|
351
|
+
|
|
352
|
+
| SQL | Gremlin |
|
|
353
|
+
| -------- | -------------------------------------- |
|
|
354
|
+
| SELECT | `values()`,`valueMap()`,`elementMap()` |
|
|
355
|
+
| FROM | `V()`,`E()` |
|
|
356
|
+
| WHERE | `has()`,`where()`,`filter()` |
|
|
357
|
+
| JOIN | `out()`,`in()`,`both()` |
|
|
358
|
+
| GROUP BY | `group()`,`groupCount()` |
|
|
359
|
+
| ORDER BY | `order()` |
|
|
360
|
+
| LIMIT | `limit()` |
|
|
361
|
+
| COUNT | `count()` |
|
|
362
|
+
| DISTINCT | `dedup()` |
|
|
363
|
+
| INSERT | `addV()`,`addE()` |
|
|
364
|
+
| UPDATE | `property()` |
|
|
365
|
+
| DELETE | `drop()` |
|
|
366
|
+
|
|
367
|
+
```sql
|
|
368
|
+
SELECT name,age FROM persons WHERE age>25 ORDER BY name LIMIT 10;
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
```groovy
|
|
372
|
+
g.V().hasLabel('person').has('age',gt(25)).order().by('name').limit(10).values('name','age')
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Remote Connections
|
|
376
|
+
|
|
377
|
+
```java
|
|
378
|
+
// Java
|
|
379
|
+
Cluster cluster = Cluster.build().addContactPoint("localhost").port(8182)
|
|
380
|
+
.credentials("user","pass").create();
|
|
381
|
+
GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
```python
|
|
385
|
+
# Python
|
|
386
|
+
from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
|
|
387
|
+
from gremlin_python.process.anonymous_traversal import traversal
|
|
388
|
+
g = traversal().withRemote(DriverRemoteConnection('ws://localhost:8182/gremlin','g'))
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Config: connection pooling, serialization (GraphSON/GraphBinary), timeouts,
|
|
392
|
+
sessions.
|
|
393
|
+
|
|
394
|
+
## Profiling/Optimization
|
|
395
|
+
|
|
396
|
+
```groovy
|
|
397
|
+
g.V().has('code','AUS').out('route').explain() // exec plan
|
|
398
|
+
g.V().has('code','AUS').out('route').profile() // metrics: duration, count, %
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Optimize: filter early, use indexes, limit breadth, use `sample()` random, avoid
|
|
402
|
+
unnecessary steps.
|
|
403
|
+
|
|
404
|
+
## Indexing
|
|
405
|
+
|
|
406
|
+
Types: Composite (multi-prop), Mixed (single prop, flexible) Best: index
|
|
407
|
+
frequent props, composite for common combos, avoid over-indexing, verify
|
|
408
|
+
`explain()`.
|
|
409
|
+
|
|
410
|
+
## Pattern Matching
|
|
411
|
+
|
|
412
|
+
```groovy
|
|
413
|
+
g.V().has('code','AUS').match(
|
|
414
|
+
__.as('a').out('route').as('b'),
|
|
415
|
+
__.as('b').out('route').as('c'),
|
|
416
|
+
__.as('c').has('code','DFW')
|
|
417
|
+
).select('a','b','c')
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Recommendations
|
|
421
|
+
|
|
422
|
+
```groovy
|
|
423
|
+
// Collaborative: users who liked same items
|
|
424
|
+
g.V().has('user','name','Alice').as('alice')
|
|
425
|
+
.out('rated').has('rating',gte(4)).inV().as('likedMovie')
|
|
426
|
+
.in('rated').has('rating',gte(4)).where(neq('alice'))
|
|
427
|
+
.out('rated').has('rating',gte(4)).inV()
|
|
428
|
+
.where(neq('likedMovie'))
|
|
429
|
+
.groupCount().order(local).by(values,Order.desc).limit(local,10)
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Recursive Traversals
|
|
433
|
+
|
|
434
|
+
```groovy
|
|
435
|
+
g.V().has('code','AUS').repeat(out('route')).times(3).dedup() // fixed
|
|
436
|
+
g.V().has('code','AUS').repeat(out('route').simplePath()).until(has('code','DFW')).path() // until
|
|
437
|
+
g.V().has('code','AUS').repeat(out('route')).emit().times(3).dedup() // emit during
|
|
438
|
+
// Avoid cycles
|
|
439
|
+
g.V().has('code','AUS').repeat(out('route').simplePath()).until(has('code','DFW')).path()
|
|
440
|
+
// With side-effects
|
|
441
|
+
g.V().has('code','AUS').aggregate('visited')
|
|
442
|
+
.repeat(out('route').where(without('visited')).aggregate('visited'))
|
|
443
|
+
.until(has('code','DFW')).path()
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
## Path Object
|
|
447
|
+
|
|
448
|
+
```groovy
|
|
449
|
+
g.V().has('code','AUS').out('route').out('route').path().by('code') // basic
|
|
450
|
+
g.V().has('code','AUS').as('start').out('route').as('first').path().from('start').by('code') // labeled
|
|
451
|
+
g.V().has('code','AUS').outE('route').as('edge').inV().path().by('code').by('distance') // with edges
|
|
452
|
+
g.V().has('code','AUS').repeat(out('route').simplePath()).until(has('code','DFW'))
|
|
453
|
+
.path().where(count(local).is(lt(5))) // filter by length
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## Testing/Debugging
|
|
457
|
+
|
|
458
|
+
```groovy
|
|
459
|
+
g.V().has('code','AUS').path().by(elementMap()) // inspect
|
|
460
|
+
def aus = g.V().has('code','AUS').next() // break complex
|
|
461
|
+
def routes = g.V(aus).out('route').toList()
|
|
462
|
+
g.V().has('code','AUS').out('route').profile() // profile
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
## Security
|
|
466
|
+
|
|
467
|
+
- Credentials auth
|
|
468
|
+
- SSL/TLS
|
|
469
|
+
- RBAC at app level
|
|
470
|
+
- Parameter binding (not string concat)
|
|
471
|
+
- Validate/sanitize input
|
|
472
|
+
- Config timeouts/resource limits
|
|
473
|
+
|
|
474
|
+
## Resources
|
|
475
|
+
|
|
476
|
+
Stephen Mallette Gremlin Snippets:
|
|
477
|
+
|
|
478
|
+
- 1: null handling
|
|
479
|
+
- 2: constant() vs inject()
|
|
480
|
+
- 3: fold()/unfold()
|
|
481
|
+
- 4: static/dynamic maps
|
|
482
|
+
- 5: maps as keys
|
|
483
|
+
- 6: edge direction grouping
|
|
484
|
+
- 20: constant() vs inject() with addV()
|
|
485
|
+
- 21: times(0) semantics
|
|
486
|
+
- 22: TinkerPop 3.8.0
|
|
487
|
+
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
```
|