Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New java manual #413

Merged
merged 42 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
114b791
connect
stefano-ottolenghi Dec 13, 2023
4762efe
first stab
stefano-ottolenghi Dec 18, 2023
7fa51a6
xref
stefano-ottolenghi Dec 18, 2023
6eaaa21
.
stefano-ottolenghi Dec 19, 2023
b73584a
bookmarks
stefano-ottolenghi Dec 20, 2023
9a92031
query advanced
stefano-ottolenghi Dec 22, 2023
35f297a
.
stefano-ottolenghi Dec 22, 2023
3c2ad27
performance
stefano-ottolenghi Dec 28, 2023
08ff2dc
review
stefano-ottolenghi Dec 28, 2023
c44b45d
connect adv
stefano-ottolenghi Dec 28, 2023
78d4580
Merge branch 'dev' into new-java
stefano-ottolenghi Dec 28, 2023
eeee1b4
.
stefano-ottolenghi Dec 29, 2023
c47e616
.
stefano-ottolenghi Dec 29, 2023
b02dc89
.
stefano-ottolenghi Dec 29, 2023
185913f
async + stuff
stefano-ottolenghi Jan 8, 2024
ddc4544
.
stefano-ottolenghi Jan 8, 2024
385492a
some types
stefano-ottolenghi Jan 9, 2024
1d0a77b
temporal
stefano-ottolenghi Jan 9, 2024
601bb35
.
stefano-ottolenghi Jan 11, 2024
f16a7b4
graph entities
stefano-ottolenghi Jan 12, 2024
eb70a00
.
stefano-ottolenghi Jan 12, 2024
ad14a7b
.
stefano-ottolenghi Jan 12, 2024
ec41c8b
examples rx
stefano-ottolenghi Feb 1, 2024
95d8f94
.
stefano-ottolenghi Feb 2, 2024
c9442b2
some rx
stefano-ottolenghi Feb 7, 2024
f635de7
all reactive
stefano-ottolenghi Feb 9, 2024
78e7a21
install, quickstart, example proj
stefano-ottolenghi Feb 9, 2024
3294cff
.
stefano-ottolenghi Feb 9, 2024
158dd88
review + animation
stefano-ottolenghi Feb 12, 2024
aa295d7
rm ui bundle
stefano-ottolenghi Feb 12, 2024
e346dce
fix examples
stefano-ottolenghi Feb 12, 2024
2bc151f
fix
stefano-ottolenghi Feb 12, 2024
e6015e8
fix examples
stefano-ottolenghi Feb 13, 2024
3ecef58
fix example
stefano-ottolenghi Feb 13, 2024
883417c
fixes
stefano-ottolenghi Feb 13, 2024
5a7a669
cleanup
stefano-ottolenghi Feb 13, 2024
d20f1ca
fix example
stefano-ottolenghi Feb 13, 2024
48f8722
fix example
stefano-ottolenghi Feb 13, 2024
98b4182
fixes + cleanup
stefano-ottolenghi Feb 15, 2024
2a4149d
ocsp stapling
stefano-ottolenghi Feb 15, 2024
4308a92
revert package-lock
stefano-ottolenghi Feb 15, 2024
871433d
remove animation
stefano-ottolenghi Feb 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions java-manual/antora.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ nav:
- modules/ROOT/content-nav.adoc
asciidoc:
attributes:
java-driver-version: '5.12.0' # the version of the api docs published at https://neo4j.com/docs/api/java-driver/
java-driver-apidoc-release: '5.0' # the github branch or release that contains examples included in docs
java-examples: https://raw.githubusercontent.com/neo4j/neo4j-java-driver/{java-driver-apidoc-release}/examples/src/main/java/org/neo4j/docs/driver
java-driver-version: '5.15' # the version of the api docs published at https://neo4j.com/docs/api/java-driver/
common-partial: 5@common-content:ROOT:partial$
common-image: 5@common-content:ROOT:image$
38 changes: 28 additions & 10 deletions java-manual/modules/ROOT/content-nav.adoc
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
* xref:index.adoc[]
* xref:get-started.adoc[]
* xref:client-applications.adoc[]
* xref:cypher-workflow.adoc[]
* xref:session-api.adoc[]
// ** xref:session-api/simple.adoc[Simple sessions]
// ** xref:session-api/asynchronous.adoc[Asynchronous sessions]
// ** xref:session-api/reactive.adoc[Reactive sessions]
// ** xref:session-api/configuration.adoc[Session configuration]
* xref:terminology.adoc[]
* xref:index.adoc[Quickstart]

* *Basic workflow*

* xref:install.adoc[Installation]
* xref:connect.adoc[Connect to the database]
* xref:query-simple.adoc[Query the database]

* *Advanced usage*

* xref:transactions.adoc[Run your own transactions]
* xref:result-summary.adoc[Explore the query execution summary]
* xref:bookmarks.adoc[Coordinate parallel transactions]
* xref:concurrency.adoc[Run concurrent transactions]
* xref:query-advanced.adoc[Further query mechanisms]
* xref:performance.adoc[Performance recommendations]

* *Reference*

* xref:connect-advanced.adoc[Advanced connection information]
* xref:data-types.adoc[Data types and mapping to Cypher types]
* link:https://neo4j.com/docs/api/java-driver/current/[API documentation, window=_blank]

* *GraphAcademy courses*

* link:https://graphacademy.neo4j.com/courses/modeling-fundamentals/?ref=docs-python[Graph Data Modeling Fundamentals]
* link:https://graphacademy.neo4j.com/courses/cypher-intermediate-queries/?ref=docs-python[Intermediate Cypher Queries]
* link:https://graphacademy.neo4j.com/courses/app-python/?ref=docs-python[Building Neo4j Applications with Python]
178 changes: 178 additions & 0 deletions java-manual/modules/ROOT/pages/bookmarks.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
= Coordinate parallel transactions

When working with a Neo4j cluster, <<causal_consistency>> is enforced by default in most cases, which guarantees that a query is able to read changes made by previous queries.
The same does not happen by default for multiple xref:transactions.adoc[transactions] running in parallel though.
In that case, you can use _bookmarks_ to have one transaction wait for the result of another to be propagated across the cluster before running its own work.
This is not a requirement, and *you should only use bookmarks if you _need_ casual consistency across different transactions*.

A _bookmark_ is a token that represents some state of the database.
By passing one or multiple bookmarks along with a query, the server will make sure that the query does not get executed before the represented state(s) have been established.


== Bookmarks with `.executableQuery()`

When xref:query-simple.adoc[querying the database with `.executableQuery()`], the driver manages bookmarks for you.
In this case, you have the guarantee that subsequent queries can read previous changes without taking further action.

[source, java]
----
driver.executableQuery("<QUERY 1>").execute()

// subsequent execute_query calls will be causally chained

driver.executableQuery("<QUERY 2>").execute() // can read result of <QUERY 1>
driver.executableQuery("<QUERY 3>").execute() // can read result of <QUERY 2>
----

To disable bookmark management and causal consistency, set `bookmark_manager_=None` in `.execute_query()` calls.

[source, java]
----
driver.executableQuery("<QUERY>")
.withConfig(QueryConfig.builder().withBookmarkManager(null).build())
.execute();
----


== Bookmarks within a single session

Bookmark management happens automatically for queries run within a single session, so that you can trust that queries inside one session are causally chained.

[source,python]
----
with driver.session() as session:
session.execute_write(lambda tx: tx.run("<QUERY 1>"))
session.execute_write(lambda tx: tx.run("<QUERY 2>")) # can read QUERY 1
session.execute_write(lambda tx: tx.run("<QUERY 3>")) # can read QUERY 1,2
----


== Bookmarks across multiple sessions

If your application uses multiple sessions, you may need to ensure that one session has completed all its transactions before another session is allowed to run its queries.

In the example below, `session_a` and `session_b` are allowed to run concurrently, while `session_c` waits until their results have been propagated.
This guarantees the `Person` nodes `session_c` wants to act on actually exist.

.Coordinate multiple sessions using bookmarks
[source,python]
----
from neo4j import GraphDatabase, Bookmarks


URI = "<URI for Neo4j database>"
AUTH = ("<Username>", "<Password>")

def main():
with GraphDatabase.driver(URI, auth=AUTH) as driver:
create_some_friends(driver)


def create_some_friends(driver):
saved_bookmarks = Bookmarks() # To collect the sessions' bookmarks

# Create the first person and employment relationship
with driver.session(database="neo4j") as session_a:
session_a.execute_write(create_person, "Alice")
session_a.execute_write(employ, "Alice", "Wayne Enterprises")
saved_bookmarks += session_a.last_bookmarks() # <1>

# Create the second person and employment relationship
with driver.session(database="neo4j") as session_b:
session_b.execute_write(create_person, "Bob")
session_b.execute_write(employ, "Bob", "LexCorp")
saved_bookmarks += session_b.last_bookmarks() # <1>

# Create a friendship between the two people created above
with driver.session(
database="neo4j", bookmarks=saved_bookmarks
) as session_c: # <2>
session_c.execute_write(create_friendship, "Alice", "Bob")
session_c.execute_read(print_friendships)


# Create a person node
def create_person(tx, name):
tx.run("MERGE (:Person {name: $name})", name=name)


# Create an employment relationship to a pre-existing company node
# This relies on the person first having been created.
def employ(tx, person_name, company_name):
tx.run("""
MATCH (person:Person {name: $person_name})
MATCH (company:Company {name: $company_name})
CREATE (person)-[:WORKS_FOR]->(company)
""", person_name=person_name, company_name=company_name
)


# Create a friendship between two people
def create_friendship(tx, name_a, name_b):
tx.run("""
MATCH (a:Person {name: $name_a})
MATCH (b:Person {name: $name_b})
MERGE (a)-[:KNOWS]->(b)
""", name_a=name_a, name_b=name_b
)


# Retrieve and display all friendships
def print_friendships(tx):
result = tx.run("MATCH (a)-[:KNOWS]->(b) RETURN a.name, b.name")
for record in result:
print("{} knows {}".format(record["a.name"], record["b.name"]))


if __name__ == "__main__":
main()
----

<1> Collect and combine bookmarks from different sessions using `Session.last_bookmarks()`, storing them in a `Bookmarks` object.
<2> Use them to initialize another session with the `bookmarks` parameter.

image:{common-image}/driver-passing-bookmarks.svg[]

[TIP]
The use of bookmarks can negatively impact performance, since all queries are forced to wait for the latest changes to be propagated across the cluster.
For simple use-cases, try to group queries within a single transaction, or within a single session.


== Mix `.execute_query()` and sessions

To ensure causal consistency among transactions executed partly with `.execute_query()` and partly with sessions, you can use the parameter `bookmark_manager` upon session creation, setting it to `driver.execute_query_bookmark_manager`.
Since that is the default bookmark manager for `.execute_query()` calls, this will ensure that all work is executed under the same bookmark manager and thus causally consistent.

[source, python]
----
driver.execute_query("<QUERY 1>")

with driver.session(
bookmark_manager=driver.execute_query_bookmark_manager
) as session:
# every query inside this session will be causally chained
# (i.e., can read what was written by <QUERY 1>)
session.execute_write(lambda tx: tx.run("<QUERY 2>"))

# subsequent execute_query calls will be causally chained
# (i.e., can read what was written by <QUERY 2>)
driver.execute_query("<QUERY 3>")
----


== Implement a custom `BookmarkManager`

The _bookmark manager_ is an interface used by the driver for keeping track of the bookmarks and keeping sessions automatically consistent.

You can subclass the link:{neo4j-docs-base-uri}/api/python-driver/current/api.html#neo4j.api.BookmarkManager[`BookmarkManager`] interface to implement a custom bookmark manager, or use the default implementation provided by the driver through link:{neo4j-docs-base-uri}/api/python-driver/current/api.html#neo4j.GraphDatabase.bookmark_manager[`GraphDatabase.bookmark_manager()`]. When implementing a bookmark manager, keep in mind that all methods must be concurrency safe.

The details of the interface can be found in the link:{neo4j-docs-base-uri}/api/python-driver/current/api.html#neo4j.api.BookmarkManager[API documentation].


ifndef::backend-pdf[]
[discrete.glossary]
== Glossary

include::{common-partial}/glossary.adoc[]
include::../partials/glossary.adoc[]
endif::[]
Loading