Aru S
Aru S

Reputation: 1529

Which indexing system should I use?

I'm currently using py2neo to interface with my neo4j server. One thing that I'd like to do is enforce a uniqueness constraint for a label (i.e. enforce a unique client-generated hash on the server side). For the sake of example, I have the following schema:

ON :Organization(uid)    ONLINE (for uniqueness constraint)

Since I'm using py2neo, my normal node creation sequence usually entails:

  1. Generate the UID hash based on properties of the organization
  2. Add it to the database
  3. Add the "Organization" label to the hydrated node returned by the add statement

This works just fine. When I go to create a duplicate node, I:

  1. Generate the UID hash based on properties of the organization
  2. Add it to the database
  3. Attempt to add the "Organization" label, which fails due to the uniqueness constraint.

The problem with the step above is that I now have a label-less duplicate node on my graph. Instead I'd like to get a reference to the existing node since this is usually executed within the context of relationship creation. To accomplish this, I need to be able to create the node and label it before adding it to the graph, which currently cannot be done cleanly with py2neo/the REST API. I can't use the batch API as that fails with the same error (and doesn't return a copy of the existing node).

A workaround is:

  1. Generate the UID hash based on properties of the organization
  2. Query the database for a node with that hash
  3. If it exists, use that, otherwise add a node to the database and then add the "Organization" label to the node.

The downside of that is I'm performing extra network requests as well as avoidable I/O. The Cypher analogue I'm looking for is MERGE. It seems as if I have two or three options here:

  1. Instead of using the standard graph create operation, I convert the node abstract to a Cypher MERGE statement and execute that.
  2. Fall back to the "legacy" indexing system which provides a get_or_create method.

The legacy indexing system also seems to provide a better short-term outlook in that I can create full text indices, and it seems as if I also get better performance out of it. Any thoughts/suggestions?

Upvotes: 0

Views: 103

Answers (2)

Nigel Small
Nigel Small

Reputation: 4495

The next version of py2neo (1.7) will be able to handle this sort of situation more fluidly. I'm currently building functionality to separate client-side entity manipulation (e.g. labels and properties) from client-server synchronisation. This means it will be possible to create a node within an application and then push it to the server in a single HTTP request.

The code will look something like:

from py2neo import Graph, Node

graph = Graph()

# Define a node client-side with a label and a property
node = Node("Person", name="Alice")

# Create the node on the server
# (this will bind the client-side node to a new server node)
graph.create(node)

# Make a few changes (client-side)
node.labels.add("Employee")
node.properties["employee_no"] = 42

# Push the changes to the bound server-side entity
node.push()

Note that the code here is only an example and may change before release!

Upvotes: 1

Michael Hunger
Michael Hunger

Reputation: 41706

I'd say use MERGE, which also does the correct locking and guarantees the uniqueness of your node.

The uniqueness check is imho done immediately, not sure about the visibility of changes of other threads performing operations at the same time. MERGE takes an index lock and makes sure only one thread at a time checks the uniqueness constraint.

Upvotes: 2

Related Questions