Skip to content

Commit

Permalink
go
Browse files Browse the repository at this point in the history
  • Loading branch information
stefano-ottolenghi committed Sep 9, 2024
1 parent 739d2c2 commit 12de8bc
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 29 deletions.
94 changes: 85 additions & 9 deletions go-manual/modules/ROOT/pages/result-summary.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,21 @@ For more information and examples, see link:{neo4j-docs-base-uri}/cypher-manual/

== Notifications

The method `ResultSummary.Notifications()` returns a list of link:{neo4j-docs-base-uri}/status-codes/current/notifications[notifications coming from the server], if any were raised by the execution of the query.
These include recommendations for performance improvements, warnings about the usage of deprecated features, and other hints about sub-optimal usage of Neo4j.
Each notification comes as a link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j#Notification[`Notification`] object.
After executing a query, the server can return link:{neo4j-docs-base-uri}/status-codes/current/notifications[notifications] alongside the query result.
Notifications contain recommendations for performance improvements, warnings about the usage of deprecated features, and other hints about sub-optimal usage of Neo4j.

[TIP]
For driver and server version >= 5.23, two forms of notifications are available (_Neo4j status codes_ and _GQL status codes_).
For earlier versions, only _Neo4j status codes_ are available. +
GQL status codes are planned to supersede Neo4j status codes.

.An unbounded shortest path raises a performance notification
[.tabbed-example]
=====
[.include-with-neo4j-status-code]
======
The method `Summary.Notifications()` returns a list of link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j#Notification[`Notification`] objects.

[source, go, role=nocollapse]
----
result, _ := neo4j.ExecuteQuery(ctx, driver, `
Expand All @@ -184,16 +194,79 @@ Category: PERFORMANCE
*/
----

======
[.include-with-GQL-status-code]
======

The method `Summary.GqlStatusObjects()` returns a list of link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j#GqlStatusObject[`GqlStatusObject`]s, which are GQL-compliant status objects.

Some (but not all) `GqlStatusObjects` are notifications, whereas some report an _outcome_ status: `00000` for "success", `02000` for "no data", and `00001` for "omitted result".
`Summary.GqlStatusObjects()` always contains at least one entry, containing the outcome status.

[source, go, role=nocollapse]
----
result, _ := neo4j.ExecuteQuery(ctx, driver, `
MATCH p=shortestPath((:Person {name: 'Alice'})-[*]->(:Person {name: 'Bob'}))
RETURN p
`, nil,
neo4j.EagerResultTransformer,
neo4j.ExecuteQueryWithDatabase("neo4j"))
for _, status := range result.Summary.GqlStatusObjects() {
fmt.Println("GQLSTATUS:", status.GqlStatus())
fmt.Println("Description:", status.StatusDescription())
// Not all statuses are notifications.
fmt.Println("Is notification:", status.IsNotification())
// Notification and thus vendor-specific fields.
// These fields are only meaningful for notifications.
if status.IsNotification() == true {
fmt.Println("Position (offset, line, column):", status.Position().Offset(), status.Position().Line(), status.Position().Column())
fmt.Println("Classification:", status.Classification())
fmt.Println("Unparsed classification:", status.RawClassification())
fmt.Println("Severity:", status.Severity())
fmt.Println("Unparsed severity:", status.RawSeverity())
}
// Any raw extra information provided by the server
fmt.Println("Diagnostic record:", status.DiagnosticRecord())
fmt.Println(strings.Repeat("=", 80))
}
/*
GQLSTATUS: 02000
Description: note: no data
Is notification: false
Diagnostic record: map[CURRENT_SCHEMA:/ OPERATION: OPERATION_CODE:0]
================================================================================
GQLSTATUS: 03N91
Description: info: unbounded variable length pattern. The provided pattern `(:Person {name: 'Alice'})-[*]->(:Person {name: 'Bob'})` is unbounded. Shortest path with an unbounded pattern may result in long execution times. Use an upper limit (e.g. `[*..5]`) on the number of node hops in your pattern.
Is notification: true
Position (offset, line, column): 26 2 26
Classification: PERFORMANCE
Unparsed classification: PERFORMANCE
Severity: INFORMATION
Unparsed severity: INFORMATION
Diagnostic record: map[CURRENT_SCHEMA:/ OPERATION: OPERATION_CODE:0 _classification:PERFORMANCE _position:map[column:26 line:2 offset:26] _severity:INFORMATION _status_parameters:map[pat:(:Person {name: 'Alice'})-[*]->(:Person {name: 'Bob'})]]
================================================================================
*/
----

======
=====


[role=label--new-5.7]
=== Filter notifications

By default, the server analyses each query for all categories and severity of notifications.
Starting from version 5.7, you can use the parameters `NotificationsMinSeverity` and/or `NotificationsDisabledCategories` to restrict the severity or category of notifications that you are interested into.
You may disable notifications altogether by setting the minimum severity to `OFF`.
You can use those parameters either when creating a driver instance, or when creating a session.

Starting from version 5.7, you can use the parameters `NotificationsMinSeverity` and/or `NotificationsDisabledCategories`/`NotificationsDisabledClassifications` to restrict the severity and/or category/classification of notifications that you are interested into.
There is a slight performance gain in restricting the amount of notifications the server is allowed to raise.

The severity filter applies to both Neo4j and GQL notifications, whereas the category filter applies to Neo4j notifications only, and the classification filter applies to GQL notifications only.
You can use any of those parameters either when creating a driver instance, or when creating a session.

You may disable notifications altogether by setting the minimum severity to `OFF`.

.Allow only `Warning` notifications, but not of `Hint` or `Generic` category
[source, go]
----
Expand All @@ -207,15 +280,18 @@ driverNot, _ := neo4j.NewDriverWithContext(
dbUri,
neo4j.BasicAuth(dbUser, dbPassword, ""),
func (conf *config.Config) {
conf.NotificationsDisabledCategories = notifications.DisableCategories(notifications.Hint, notifications.Generic)
conf.NotificationsDisabledCategories = notifications.DisableCategories(notifications.Hint, notifications.Generic) // applies to Neo4j status codes only
conf.NotificationsDisabledClassifications = notifications.DisableClassifications(notifications.Hint, notifications.Generic) // applies to GQL status codes only
conf.NotificationsMinSeverity = notifications.WarningLevel
})
// At session level
sessionNot := driver.NewSession(ctx, neo4j.SessionConfig{
NotificationsMinSeverity: notifications.WarningLevel,
NotificationsDisabledCategories: notifications.DisableCategories(notifications.Hint, notifications.Generic),
NotificationsDisabledCategories: notifications.DisableCategories(notifications.Hint, notifications.Generic), // applies to Neo4j status codes only
NotificationsDisabledClassifications: notifications.DisableClassifications(notifications.Hint, notifications.Generic), // applies to GQL status codes only
DatabaseName: "neo4j", // always provide the database name
})
----

42 changes: 22 additions & 20 deletions python-manual/modules/ROOT/pages/result-summary.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,13 @@ records, summary, keys = driver.execute_query("""
----

======
[.include-with-GQLSTATUS-status-code]
[.include-with-GQL-status-code]
======

The property `ResultSummary.gql_status_objects` contains a sequence of link:{neo4j-docs-base-uri}/api/python-driver/current/api.html#GqlStatusObject[`GqlStatusObject`]s, which are GQL-compliant status objects.

Some (but not all) `GqlStatusObjects` are notifications, whereas some report an _outcome_ status: `00000` for "success", `02000` for "no data", and `00001` for "omitted result".
`ResultSummary.gql_status_objects` always contains at least one entry, containing the outcome status.

[source, python, role=nocollapse]
----
Expand All @@ -186,41 +187,42 @@ records, summary, keys = driver.execute_query("""
)
for status in summary.gql_status_objects:
print("GQLSTATUS:", status.gql_status)
print("description:", status.status_description)
print("is notification:", status.is_notification)
print("Description:", status.status_description)
# Not all statuses are notifications.
print("Is notification:", status.is_notification)
# Notification and thus vendor-specific fields.
# These fields are only meaningful for notifications.
if status.is_notification:
# The position in the query that caused the notification.
print("position:", status.position)
print("Position:", status.position)
# The notification's classification is counterpart to `neo4j.NotificationCategory`.
# However, the term `category` has a different meaning in the context of GQL.
print("classification:", status.classification)
print("unparsed classification:", status.raw_classification)
print("Classification:", status.classification)
print("Unparsed classification:", status.raw_classification)
print("severity:", status.severity)
print("unparsed severity:", status.raw_severity)
print("Severity:", status.severity)
print("Unparsed severity:", status.raw_severity)
# Any raw extra information provided by the DBMS:
print("diagnostic record:", status.diagnostic_record)
print("Diagnostic record:", status.diagnostic_record)
print("=" * 80)
"""
GQLSTATUS: 02000
description: note: no data
is notification: False
diagnostic record: {'OPERATION': '', 'OPERATION_CODE': '0', 'CURRENT_SCHEMA': '/'}
Description: note: no data
Is notification: False
Diagnostic record: {'OPERATION': '', 'OPERATION_CODE': '0', 'CURRENT_SCHEMA': '/'}
================================================================================
GQLSTATUS: 03N91
description: info: unbounded variable length pattern. The provided pattern `(:Person {name: 'Alice'})-[*]->(:Person {name: 'Bob'})` is unbounded. Shortest path with an unbounded pattern may result in long execution times. Use an upper limit (e.g. `[*..5]`) on the number of node hops in your pattern.
is notification: True
position: line: 1, column: 22, offset: 21
classification: NotificationClassification.PERFORMANCE
unparsed classification: PERFORMANCE
severity: NotificationSeverity.INFORMATION
unparsed severity: INFORMATION
diagnostic record: {'_classification': 'PERFORMANCE', '_status_parameters': {'pat': "(:Person {name: 'Alice'})-[*]->(:Person {name: 'Bob'})"}, '_severity': 'INFORMATION', '_position': {'offset': 21, 'line': 1, 'column': 22}, 'OPERATION': '', 'OPERATION_CODE': '0', 'CURRENT_SCHEMA': '/'}
Description: info: unbounded variable length pattern. The provided pattern `(:Person {name: 'Alice'})-[*]->(:Person {name: 'Bob'})` is unbounded. Shortest path with an unbounded pattern may result in long execution times. Use an upper limit (e.g. `[*..5]`) on the number of node hops in your pattern.
Is notification: True
Position: line: 1, column: 22, offset: 21
Classification: NotificationClassification.PERFORMANCE
Unparsed classification: PERFORMANCE
Severity: NotificationSeverity.INFORMATION
Unparsed severity: INFORMATION
Diagnostic record: {'_classification': 'PERFORMANCE', '_status_parameters': {'pat': "(:Person {name: 'Alice'})-[*]->(:Person {name: 'Bob'})"}, '_severity': 'INFORMATION', '_position': {'offset': 21, 'line': 1, 'column': 22}, 'OPERATION': '', 'OPERATION_CODE': '0', 'CURRENT_SCHEMA': '/'}
================================================================================
"""
----
Expand Down

0 comments on commit 12de8bc

Please sign in to comment.