0
# Query Execution
1
2
Cypher query execution system providing result handling, parameter binding, execution plan analysis, and performance monitoring with support for both transactional and auto-commit query patterns.
3
4
## Capabilities
5
6
### Result Interface
7
8
Interface for handling query results with iteration, statistics access, and resource management.
9
10
```java { .api }
11
/**
12
* Iterable query result set with resource management
13
*/
14
public interface Result extends AutoCloseable {
15
16
/**
17
* Check if there are more results available
18
* @return true if more results exist, false otherwise
19
*/
20
boolean hasNext();
21
22
/**
23
* Get the next result record
24
* @return Map containing column names and values
25
* @throws NoSuchElementException if no more results
26
*/
27
Map<String, Object> next();
28
29
/**
30
* Process each remaining result with a consumer function
31
* @param action Consumer function to process each result record
32
*/
33
void forEachRemaining(Consumer<Map<String, Object>> action);
34
35
/**
36
* Get the column names in the result set
37
* @return List of column names
38
*/
39
List<String> columns();
40
41
/**
42
* Get query execution statistics
43
* @return Statistics about the query execution
44
*/
45
QueryStatistics getQueryStatistics();
46
47
/**
48
* Get the execution plan description
49
* @return Execution plan details for query optimization analysis
50
*/
51
ExecutionPlanDescription getExecutionPlanDescription();
52
53
/**
54
* Get notifications about query execution
55
* @return List of notifications (warnings, performance hints, etc.)
56
*/
57
Iterable<Notification> getNotifications();
58
59
/**
60
* Convert all results to a list of maps
61
* @return List containing all result records
62
*/
63
List<Map<String, Object>> list();
64
65
/**
66
* Transform results using a function
67
* @param mapper Function to transform each result record
68
* @return Stream of transformed results
69
*/
70
<T> Stream<T> stream(Function<Map<String, Object>, T> mapper);
71
72
/**
73
* Extract a specific column as a typed iterator
74
* @param column Column name to extract
75
* @return ResourceIterator of column values
76
*/
77
<T> ResourceIterator<T> columnAs(String column);
78
79
/**
80
* Convert the entire result to a string representation
81
* @return String representation of all results
82
*/
83
String resultAsString();
84
85
/**
86
* Write the result as a string to a PrintWriter
87
* @param writer PrintWriter to write results to
88
*/
89
void writeAsStringTo(PrintWriter writer);
90
91
/**
92
* Remove operation (explicitly unsupported)
93
* @throws UnsupportedOperationException always
94
*/
95
default void remove() {
96
throw new UnsupportedOperationException("Remove not supported on query results");
97
}
98
99
/**
100
* Close the result set and free associated resources
101
*/
102
@Override
103
void close();
104
}
105
```
106
107
**Usage Examples:**
108
109
```java
110
import org.neo4j.graphdb.Result;
111
import org.neo4j.graphdb.QueryStatistics;
112
import java.util.Map;
113
import java.util.List;
114
115
try (Transaction tx = graphDb.beginTx()) {
116
// Basic query execution and result processing
117
String query = "MATCH (p:Person)-[r:FRIENDS]->(f:Person) " +
118
"RETURN p.name as person, f.name as friend, r.since as since";
119
120
try (Result result = tx.execute(query)) {
121
// Check column names
122
System.out.println("Columns: " + result.columns());
123
124
// Process results one by one
125
while (result.hasNext()) {
126
Map<String, Object> row = result.next();
127
System.out.println(row.get("person") + " is friends with " +
128
row.get("friend") + " since " + row.get("since"));
129
}
130
131
// Get query statistics
132
QueryStatistics stats = result.getQueryStatistics();
133
System.out.println("Nodes created: " + stats.getNodesCreated());
134
System.out.println("Relationships created: " + stats.getRelationshipsCreated());
135
}
136
137
tx.commit();
138
}
139
140
// Using forEachRemaining for functional processing
141
try (Transaction tx = graphDb.beginTx()) {
142
try (Result result = tx.execute("MATCH (p:Person) RETURN p.name, p.age")) {
143
result.forEachRemaining(row -> {
144
System.out.println("Person: " + row.get("p.name") +
145
", Age: " + row.get("p.age"));
146
});
147
}
148
tx.commit();
149
}
150
151
// Convert to list for further processing
152
try (Transaction tx = graphDb.beginTx()) {
153
try (Result result = tx.execute("MATCH (p:Person) RETURN p.name as name")) {
154
List<Map<String, Object>> allResults = result.list();
155
List<String> names = allResults.stream()
156
.map(row -> (String) row.get("name"))
157
.collect(Collectors.toList());
158
}
159
tx.commit();
160
}
161
```
162
163
### Result Transformer
164
165
Interface for transforming query results in a callback pattern with proper resource management.
166
167
```java { .api }
168
/**
169
* Transform query results in a callback pattern
170
*/
171
@FunctionalInterface
172
public interface ResultTransformer<T> {
173
174
/**
175
* Transform the query result
176
* @param result Query result to transform
177
* @return Transformed result
178
* @throws Exception if transformation fails
179
*/
180
T apply(Result result) throws Exception;
181
}
182
```
183
184
**Usage Examples:**
185
186
```java
187
import org.neo4j.graphdb.ResultTransformer;
188
import java.util.ArrayList;
189
import java.util.List;
190
191
// Extract specific data from query results
192
List<String> personNames = graphDb.executeTransactionally(
193
"MATCH (p:Person) RETURN p.name as name",
194
Map.of(),
195
result -> {
196
List<String> names = new ArrayList<>();
197
result.forEachRemaining(row -> names.add((String) row.get("name")));
198
return names;
199
}
200
);
201
202
// Calculate aggregations
203
Double averageAge = graphDb.executeTransactionally(
204
"MATCH (p:Person) RETURN p.age as age",
205
Map.of(),
206
result -> {
207
List<Integer> ages = new ArrayList<>();
208
result.forEachRemaining(row -> {
209
Integer age = (Integer) row.get("age");
210
if (age != null) ages.add(age);
211
});
212
return ages.stream().mapToInt(Integer::intValue).average().orElse(0.0);
213
}
214
);
215
216
// Complex data transformation
217
Map<String, List<String>> friendships = graphDb.executeTransactionally(
218
"MATCH (p:Person)-[:FRIENDS]->(f:Person) RETURN p.name as person, f.name as friend",
219
Map.of(),
220
result -> {
221
Map<String, List<String>> friendMap = new HashMap<>();
222
result.forEachRemaining(row -> {
223
String person = (String) row.get("person");
224
String friend = (String) row.get("friend");
225
friendMap.computeIfAbsent(person, k -> new ArrayList<>()).add(friend);
226
});
227
return friendMap;
228
}
229
);
230
```
231
232
### Query Statistics
233
234
Interface providing detailed information about query execution and database changes.
235
236
```java { .api }
237
/**
238
* Statistics about query execution and database changes
239
*/
240
public interface QueryStatistics {
241
242
/**
243
* Get the number of nodes created by the query
244
* @return Number of nodes created
245
*/
246
int getNodesCreated();
247
248
/**
249
* Get the number of nodes deleted by the query
250
* @return Number of nodes deleted
251
*/
252
int getNodesDeleted();
253
254
/**
255
* Get the number of relationships created by the query
256
* @return Number of relationships created
257
*/
258
int getRelationshipsCreated();
259
260
/**
261
* Get the number of relationships deleted by the query
262
* @return Number of relationships deleted
263
*/
264
int getRelationshipsDeleted();
265
266
/**
267
* Get the number of properties set by the query
268
* @return Number of properties set
269
*/
270
int getPropertiesSet();
271
272
/**
273
* Get the number of labels added by the query
274
* @return Number of labels added
275
*/
276
int getLabelsAdded();
277
278
/**
279
* Get the number of labels removed by the query
280
* @return Number of labels removed
281
*/
282
int getLabelsRemoved();
283
284
/**
285
* Get the number of indexes added by the query
286
* @return Number of indexes added
287
*/
288
int getIndexesAdded();
289
290
/**
291
* Get the number of indexes removed by the query
292
* @return Number of indexes removed
293
*/
294
int getIndexesRemoved();
295
296
/**
297
* Get the number of constraints added by the query
298
* @return Number of constraints added
299
*/
300
int getConstraintsAdded();
301
302
/**
303
* Get the number of constraints removed by the query
304
* @return Number of constraints removed
305
*/
306
int getConstraintsRemoved();
307
308
/**
309
* Check if the query contained any updates
310
* @return true if any database changes were made
311
*/
312
boolean containsUpdates();
313
314
/**
315
* Check if the query contained system updates
316
* @return true if system-level changes were made
317
*/
318
boolean containsSystemUpdates();
319
}
320
```
321
322
### Execution Plan Description
323
324
Interface for accessing query execution plan information for performance analysis and optimization.
325
326
```java { .api }
327
/**
328
* Access to query execution plan information
329
*/
330
public interface ExecutionPlanDescription {
331
332
/**
333
* Get the name of this execution step
334
* @return Step name (e.g., "NodeByLabelScan", "Expand")
335
*/
336
String getName();
337
338
/**
339
* Get the children of this execution step
340
* @return List of child execution steps
341
*/
342
List<ExecutionPlanDescription> getChildren();
343
344
/**
345
* Get the arguments for this execution step
346
* @return Map of argument names to values
347
*/
348
Map<String, Object> getArguments();
349
350
/**
351
* Get identifiers introduced by this step
352
* @return Set of identifier names
353
*/
354
Set<String> getIdentifiers();
355
356
/**
357
* Check if this execution plan has profile information
358
* @return true if profiling data is available
359
*/
360
boolean hasProfilerStatistics();
361
362
/**
363
* Get profiler statistics for this step
364
* @return Profiler statistics, or null if not available
365
*/
366
ProfilerStatistics getProfilerStatistics();
367
}
368
```
369
370
### Profiler Statistics
371
372
Interface for accessing detailed execution statistics when query profiling is enabled.
373
374
```java { .api }
375
/**
376
* Detailed execution statistics for query profiling
377
*/
378
public interface ProfilerStatistics {
379
380
/**
381
* Get the number of rows produced by this step
382
* @return Number of rows
383
*/
384
long getRows();
385
386
/**
387
* Get the number of database hits for this step
388
* @return Number of database hits
389
*/
390
long getDbHits();
391
392
/**
393
* Get the page cache hits for this step
394
* @return Number of page cache hits
395
*/
396
long getPageCacheHits();
397
398
/**
399
* Get the page cache misses for this step
400
* @return Number of page cache misses
401
*/
402
long getPageCacheMisses();
403
404
/**
405
* Get the time spent in this step
406
* @return Time in milliseconds
407
*/
408
long getTime();
409
}
410
```
411
412
### Notification System
413
414
Interface for query execution notifications including warnings and performance hints.
415
416
```java { .api }
417
/**
418
* Notification about query execution
419
*/
420
public interface Notification {
421
422
/**
423
* Get the notification code
424
* @return Notification code
425
*/
426
String getCode();
427
428
/**
429
* Get the notification title
430
* @return Notification title
431
*/
432
String getTitle();
433
434
/**
435
* Get the notification description
436
* @return Detailed description
437
*/
438
String getDescription();
439
440
/**
441
* Get the severity level of this notification
442
* @return Severity level (WARNING, INFORMATION)
443
*/
444
NotificationSeverity getSeverity();
445
446
/**
447
* Get the position in the query where this notification applies
448
* @return Input position, or null if not applicable
449
*/
450
InputPosition getPosition();
451
}
452
453
/**
454
* Severity levels for notifications
455
*/
456
public enum NotificationSeverity {
457
WARNING,
458
INFORMATION
459
}
460
```
461
462
**Advanced Usage Examples:**
463
464
```java
465
// Query with execution plan analysis
466
try (Transaction tx = graphDb.beginTx()) {
467
String query = "PROFILE MATCH (p:Person)-[:FRIENDS]->(f:Person) " +
468
"WHERE p.age > 25 RETURN p.name, f.name";
469
470
try (Result result = tx.execute(query)) {
471
// Process results
472
result.forEachRemaining(row -> {
473
System.out.println(row.get("p.name") + " -> " + row.get("f.name"));
474
});
475
476
// Analyze execution plan
477
ExecutionPlanDescription plan = result.getExecutionPlanDescription();
478
printExecutionPlan(plan, 0);
479
480
// Check for notifications
481
for (Notification notification : result.getNotifications()) {
482
System.out.println("Notification: " + notification.getTitle());
483
System.out.println("Description: " + notification.getDescription());
484
}
485
}
486
487
tx.commit();
488
}
489
490
// Helper method to print execution plan
491
private void printExecutionPlan(ExecutionPlanDescription plan, int indent) {
492
String indentStr = " ".repeat(indent);
493
System.out.println(indentStr + plan.getName());
494
495
if (plan.hasProfilerStatistics()) {
496
ProfilerStatistics stats = plan.getProfilerStatistics();
497
System.out.println(indentStr + " Rows: " + stats.getRows());
498
System.out.println(indentStr + " DB Hits: " + stats.getDbHits());
499
System.out.println(indentStr + " Time: " + stats.getTime() + "ms");
500
}
501
502
for (ExecutionPlanDescription child : plan.getChildren()) {
503
printExecutionPlan(child, indent + 1);
504
}
505
}
506
507
// Parameterized queries with error handling
508
try (Transaction tx = graphDb.beginTx()) {
509
String query = "MATCH (p:Person {name: $name}) " +
510
"CREATE (p)-[:LIVES_IN]->(:City {name: $city}) " +
511
"RETURN p.name as person, $city as city";
512
513
Map<String, Object> parameters = Map.of(
514
"name", "Alice",
515
"city", "New York"
516
);
517
518
try (Result result = tx.execute(query, parameters)) {
519
if (result.hasNext()) {
520
Map<String, Object> row = result.next();
521
System.out.println(row.get("person") + " lives in " + row.get("city"));
522
}
523
524
QueryStatistics stats = result.getQueryStatistics();
525
if (stats.containsUpdates()) {
526
System.out.println("Created " + stats.getRelationshipsCreated() + " relationships");
527
System.out.println("Created " + stats.getNodesCreated() + " nodes");
528
}
529
}
530
531
tx.commit();
532
} catch (Exception e) {
533
System.err.println("Query execution failed: " + e.getMessage());
534
}
535
```