Tom Stambaugh
Tom Stambaugh

Reputation: 1039

Neo4j: How to call "CREATE INDEX" only if not exists

The CREATE INDEX <indexName> command is not idempotent and will cause an error if the given index already exists. I'm new to neo4j, and can't find a predicate that avoids this error. I've tried various permutations of ANY(...), and they all barf at "db.indexes()".

Since CREATE INDEX ... fails if the index exists and DROP INDEX ... fails if it doesn't, I don't know how to write a .cypher file that creates the index only if needed.

A short form might be something like CREATE INDEX indexName FOR (c:SomeLabel) ON (c.someProperty) IF NOT EXISTS, but of course that short form doesn't exist.

Is there some way to do this with a predicate, subquery or some such expression?

Upvotes: 6

Views: 6458

Answers (4)

nmervaillie
nmervaillie

Reputation: 1270

As of Neo4j 4.1.3, a new index creation syntax has been introduced to do just that

CREATE INDEX myIndex IF NOT EXISTS FOR (t:Test) ON (t.id)

Indexes for search performance

Upvotes: 12

Tom Stambaugh
Tom Stambaugh

Reputation: 1039

I tried both suggestions, and neither solves my issue. I don't have time to discover, through trial-and-error, how to install APOC in my environment.

The first line of mbh86's answer is inaccurate, at least in my system. The command is not ignored, it fails with an error. So if anything else is in the same cypher script, it will fail.

The best I can do is apparently to wrap the CREATE INDEX in a command-line string, run that string from either a bash or python script, run it, and check the return code from the calling program.

I appreciate the effort of both commentators, and I didn't want to leave either hanging.

Upvotes: 0

cybersam
cybersam

Reputation: 67019

You can use the apoc.schema.node.indexExists function to check whether an index exists before creating it.

For example, this query will create the :Foo(id) index if it does not already exist:

WITH 1 AS ignored
WHERE NOT apoc.schema.node.indexExists('Foo', ['id'])
CALL db.createIndex('index_name', ['Foo'], ['id'], 'native-btree-1.0') YIELD name, labels, properties
RETURN name, labels, properties

For some reason, the Cypher planner currently is not able to parse the normal CREATE INDEX index_name ... syntax after the above WHERE clause, so this query uses the db.createIndex procedure instead.

There is also a much more powerful APOC procedure, apoc.schema.assert, but it may be overkill for your requirements.

Upvotes: 1

mbh86
mbh86

Reputation: 6378

By default, the command is ignored if the index exists. Can you test the following?

CREATE (n:Car {id: 1});

Added 1 label, created 1 node, set 1 property, completed after 23 ms.

CREATE INDEX ON :Car (id);

1st execution: Added 1 index, completed after 6 ms.

2nd execution : (no changes, no records)

Upvotes: 0

Related Questions