Indexes for search performance

This page explains how to manage indexes used for search performance.

For query performance purposes, it is important to also understand how the indexes are used by the Cypher® planner. Refer to Query tuning for examples and in-depth discussions on how query plans result from different index and query scenarios. See specifically The use of indexes for examples of how various index scenarios result in different query plans.

For information on index configuration and limitations, refer to Operations Manual → Index configuration.

Indexes (types and limitations)

A database index is a redundant copy of some of the data in the database for the purpose of making searches of related data more efficient. This comes at the cost of additional storage space and slower writes, so deciding what to index and what not to index is an important and often non-trivial task.

Once an index has been created, it will be managed and kept up to date by the DBMS. Neo4j will automatically pick up and start using the index once it has been created and brought online.

There are multiple index types available:

  • Range index.

  • Lookup index.

  • Text index.

  • Point index.

  • Full-text index.

See Full-text search index for more information about full-text indexes. Lookup indexes contain nodes with one or more labels or relationship types, without regard for any properties.

Cypher enables the creation of range indexes on one or more properties for all nodes or relationships with a given label or relationship type:

  • An index created on a single property for any given label or relationship type is called a single-property index.

  • An index created on more than one property for any given label or relationship type is called a composite index.

Differences in the usage patterns between composite and single-property indexes are described in Composite index limitations.

Additionally, text and point indexes are a kind of single-property indexes, with the limitation that they only recognize properties with string and point values, respectively. Nodes or relationships with the indexed label or relationship type where the indexed property is of another value type are not included in the index.

The following is true for indexes:

  • Best practice is to give the index a name when it is created. If the index is not explicitly named, it gets an auto-generated name.

  • The index name must be unique among both indexes and constraints.

  • Index creation is by default not idempotent, and an error will be thrown if you attempt to create the same index twice. Using the keyword IF NOT EXISTS makes the command idempotent, and no error will be thrown if you attempt to create the same index twice.

For a brief overview of the syntax, for all the index commands, see Syntax.

CREATE INDEX

Creating an index is done with the CREATE ... INDEX ... command. If no index type is specified in the create command a range index will be created.

Best practice is to give the index a name when it is created. If the index is not explicitly named, it gets an auto-generated name.

The index name must be unique among both indexes and constraints.

The CREATE INDEX command is optionally idempotent. This mean that its default behavior is to throw an error if an attempt is made to create the same index twice. With IF NOT EXISTS, no error is thrown and nothing happens should an index with the same name or same schema and index type already exist. It may still throw an error if conflicting constraints exist, such as constraints with the same name or schema and backing index type.

Creating an index requires the CREATE INDEX privilege.

The new index is not immediately available, but is created in the background.

Creating a range index

Creating a range index can be done with the CREATE INDEX command. Note that the index name must be unique.

CREATE [RANGE] INDEX [index_name] [IF NOT EXISTS]
FOR (n:LabelName)
ON (n.propertyName_1[,
    n.propertyName_2,
    ...
    n.propertyName_n])
CREATE [RANGE] INDEX [index_name] [IF NOT EXISTS]
FOR ()-"["r:TYPE_NAME"]"-()
ON (r.propertyName_1[,
    r.propertyName_2,
    ...
    r.propertyName_n])

Range indexes have only one index provider available, range-1.0, and no supported index configuration.

Examples

Create a single-property range index for nodes

The following statement will create a named range index on all nodes labeled with Person and which have the surname property.

Creating a node range index on a single property
CREATE INDEX node_range_index_name FOR (n:Person) ON (n.surname)
Create a single-property range index for relationships

The following statement will create a named range index on all relationships with relationship type KNOWS and property since.

Creating a relationship range index on a single property
CREATE INDEX rel_range_index_name FOR ()-[r:KNOWS]-() ON (r.since)
Create a composite range index for nodes

A range index on multiple properties is also called a composite index. For node range indexes, only nodes with the specified label and that contain all the specified properties will be added to the index.

The following statement will create a named composite range index on all nodes labeled with Person and which have both an age and country property.

Creating a composite node range index on multiple properties
CREATE INDEX composite_range_node_index_name FOR (n:Person) ON (n.age, n.country)
Create a composite range index for relationships

A range index on multiple properties is also called a composite index. For relationship range indexes, only relationships with the specified type and that contain all the specified properties will be added to the index.

The following statement will create a named composite range index on all relationships labeled with PURCHASED and which have both a date and amount property.

Creating a composite relationship range index on multiple properties
CREATE INDEX composite_range_rel_index_name FOR ()-[r:PURCHASED]-() ON (r.date, r.amount)
Create a range index only if it does not already exist

If it is not known whether an index exists or not, add IF NOT EXISTS to ensure it does.

Creating a range index with IF NOT EXISTS
CREATE INDEX node_range_index_name IF NOT EXISTS
FOR (n:Person) ON (n.surname)

The index will not be created if there already exists an index with the same schema and type, same name or both.

Creating a text index

Creating a text index can be done with the CREATE TEXT INDEX command. Note that the index name must be unique.

CREATE TEXT INDEX [index_name] [IF NOT EXISTS]
FOR (n:LabelName)
ON (n.propertyName)
[OPTIONS "{" option: value[, ...] "}"]
CREATE TEXT INDEX [index_name] [IF NOT EXISTS]
FOR ()-"["r:TYPE_NAME"]"-()
ON (r.propertyName)
[OPTIONS "{" option: value[, ...] "}"]

As of Neo4j 5.1, text indexes have two index providers available, text-2.0 (default) and text-1.0 (deprecated), and no supported index configuration.

Text indexes only recognize string values and do not support multiple properties.

Examples

Create a node text index

The following statement will create a named text index on all nodes labeled with Person and which have the nickname string property.

Creating a node text index on a single property
CREATE TEXT INDEX node_text_index_nickname FOR (n:Person) ON (n.nickname)
Create a relationship text index

The following statement will create a named text index on all relationships with relationship type KNOWS and string property interest.

Creating a relationship text index on a single property
CREATE TEXT INDEX rel_text_index_name FOR ()-[r:KNOWS]-() ON (r.interest)
Create a text index only if it does not already exist

If it is not known whether an index exists or not, add IF NOT EXISTS to ensure it does.

The following statement will attempt to create a named text index on all nodes labeled with Person and which have the nickname string property.

Creating a text index with IF NOT EXISTS
CREATE TEXT INDEX node_index_name IF NOT EXISTS FOR (n:Person) ON (n.nickname)

Note that the index will not be created if there already exists an index with the same schema and type, same name or both.

Create a text index specifying the index provider

To create a text index with a specific index provider, the OPTIONS clause is used. The valid values for the index provider are text-2.0 and text-1.0 (deprecated). The default provider is text-2.0.

Creating a text index with index provider
CREATE TEXT INDEX text_index_with_indexprovider FOR ()-[r:TYPE]-() ON (r.prop1)
OPTIONS {indexProvider: 'text-2.0'}

There is no supported index configuration for text indexes.

Creating a point index

Creating a point index can be done with the CREATE POINT INDEX command. Note that the index name must be unique.

CREATE POINT INDEX [index_name] [IF NOT EXISTS]
FOR (n:LabelName)
ON (n.propertyName)
[OPTIONS "{" option: value[, ...] "}"]
CREATE POINT INDEX [index_name] [IF NOT EXISTS]
FOR ()-"["r:TYPE_NAME"]"-()
ON (r.propertyName)
[OPTIONS "{" option: value[, ...] "}"]

Point indexes have supported index configuration, see the last examples, but only one index provider available, point-1.0.

Note that point indexes only recognize point values and do not support multiple properties.

Examples

Create a node point index

The following statement will create a named point index on all nodes labeled with Person and which have the sublocation point property.

Creating a node point index on a single property
CREATE POINT INDEX node_point_index_name FOR (n:Person) ON (n.sublocation)
Create a relationship point index

The following statement will create a named point index on all relationships with relationship type STREET and point property intersection.

Creating a relationship point index on a single property
CREATE POINT INDEX rel_point_index_name FOR ()-[r:STREET]-() ON (r.intersection)
Create a point index only if it does not already exist

If it is not known whether an index exists or not, add IF NOT EXISTS to ensure it does.

Creating a point index with IF NOT EXISTS
CREATE POINT INDEX node_point_index IF NOT EXISTS
FOR (n:Person) ON (n.sublocation)

Note that the index will not be created if there already exists an index with the same schema and type, same name or both.

Create a point index specifying the index configuration

To create a point index with a specific index configuration, the OPTIONS clause is used.

The valid configuration settings are:

  • spatial.cartesian.min

  • spatial.cartesian.max

  • spatial.cartesian-3d.min

  • spatial.cartesian-3d.max

  • spatial.wgs-84.min

  • spatial.wgs-84.max

  • spatial.wgs-84-3d.min

  • spatial.wgs-84-3d.max

Non-specified settings have their respective default values.

The following statement will create a point index specifying the spatial.cartesian.min and spatial.cartesian.max settings.

Creating a point index with index configuration
CREATE POINT INDEX point_index_with_config
FOR (n:Label) ON (n.prop2)
OPTIONS {
  indexConfig: {
    `spatial.cartesian.min`: [-100.0, -100.0],
    `spatial.cartesian.max`: [100.0, 100.0]
  }
}

Specifying the index configuration can be combined with specifying index provider. Though only one valid value exists for the index provider, point-1.0, which is the default value.

Creating a token lookup index

Creating a token lookup index (node label or relationship type lookup index) can be done with the CREATE LOOKUP INDEX command. Note that the index name must be unique.

CREATE LOOKUP INDEX [index_name] [IF NOT EXISTS]
FOR (n)
ON EACH labels(n)
CREATE LOOKUP INDEX [index_name] [IF NOT EXISTS]
FOR ()-"["r"]"-()
ON [EACH] type(r)

Token lookup indexes have only one index provider available, token-lookup-1.0, and no supported index configuration.

Examples

Create a node label lookup index

The following statement will create a named node label lookup index on all nodes with one or more labels:

Creating a node label lookup index
CREATE LOOKUP INDEX node_label_lookup_index FOR (n) ON EACH labels(n)

Only one node label lookup index can exist at a time.

Create a relationship type lookup index

The following statement will create a named relationship type lookup index on all relationships with any relationship type.

Creating a relationship type lookup index
CREATE LOOKUP INDEX rel_type_lookup_index FOR ()-[r]-() ON EACH type(r)

Only one relationship type lookup index can exist at a time.

Create a token lookup index only if it does not already exist

If it is not known whether an index exists or not, add IF NOT EXISTS to ensure it does.

Creating a node label lookup index with IF NOT EXISTS
CREATE LOOKUP INDEX node_label_lookup IF NOT EXISTS FOR (n) ON EACH labels(n)

The index will not be created if there already exists an index with the same schema and type, same name or both.

Creating an index when a conflicting index or constraint exists

Failure to create an already existing index

Create an index on the property title on nodes with the Book label, when that index already exists.

Creating a duplicated index
CREATE INDEX bookTitleIndex FOR (book:Book) ON (book.title)

In this case the index can not be created because it already exists.

Error message
There already exists an index (:Book {title}).

Failure to create an index with the same name as an already existing index

Create a named index on the property numberOfPages on nodes with the Book label, when an index with the given name already exists. The index type of the existing index does not matter.

Creating an index with a duplicated name
CREATE INDEX indexOnBooks FOR (book:Book) ON (book.numberOfPages)

In this case the index can’t be created because there already exists an index with the given name.

Error message
There already exists an index called 'indexOnBooks'.

Failure to create an index when a constraint already exists

Create an index on the property isbn on nodes with the Book label, when an index-backed constraint already exists on that schema. This is only relevant for range indexes.

Creating a range index on same schema as existing index-backed constraint
CREATE INDEX bookIsbnIndex FOR (book:Book) ON (book.isbn)

In this case the index can not be created because an index-backed constraint already exists on that label and property combination.

Error message
There is a uniqueness constraint on (:Book {isbn}), so an index is already created that matches this.

Failure to create an index with the same name as an already existing constraint

Create a named index on the property numberOfPages on nodes with the Book label, when a constraint with the given name already exists.

Creating an index with same name as an existing constraint
CREATE INDEX bookRecommendations FOR (book:Book) ON (book.recommendations)

In this case the index can not be created because there already exists a constraint with the given name.

Error message
There already exists a constraint called 'bookRecommendations'.

SHOW INDEXES

Listing indexes can be done with SHOW INDEXES.

SHOW [ALL \| FULLTEXT \| LOOKUP \| POINT \| RANGE \| TEXT] INDEX[ES]
  [YIELD { * \| field[, ...] } [ORDER BY field[, ...]] [SKIP n] [LIMIT n]]
  [WHERE expression]
  [RETURN field[, ...] [ORDER BY field[, ...]] [SKIP n] [LIMIT n]]

This command will produce a table with the following columns:

Table 1. List indexes output
Column Description Type

id

The id of the index. Default Output

INTEGER

name

Name of the index (explicitly set by the user or automatically assigned). Default Output

STRING

state

Current state of the index. Default Output

STRING

populationPercent

% of index population. Default Output

FLOAT

type

The IndexType of this index (FULLTEXT, LOOKUP, POINT, RANGE, or TEXT). Default Output

STRING

entityType

Type of entities this index represents (nodes or relationship). Default Output

STRING

labelsOrTypes

The labels or relationship types of this index. Default Output

LIST<STRING>

properties

The properties of this index. Default Output

LIST<STRING>

indexProvider

The index provider for this index. Default Output

STRING

owningConstraint

The name of the constraint the index is associated with or null if the index is not associated with any constraint. Default Output

STRING

lastRead

The last time the index was used for reading. Returns null if the index has not been read since trackedSince, or if the statistics are not tracked. Default Output Introduced in 5.8

ZONED DATETIME

readCount

The number of read queries that have been issued to this index since trackedSince, or null if the statistics are not tracked. Default Output Introduced in 5.8

INTEGER

trackedSince

The time when usage statistics tracking started for this index, or null if the statistics are not tracked. Introduced in 5.8

ZONED DATETIME

options

The options passed to CREATE command.

MAP

failureMessage

The failure description of a failed index.

STRING

createStatement

Statement used to create the index.

STRING

The command SHOW INDEXES returns only the default output. For a full output use the optional YIELD command. Full output: SHOW INDEXES YIELD *.

Listing indexes also allows for WHERE and YIELD clauses to filter the returned rows and columns.

Listing indexes require the SHOW INDEX privilege.

Examples

Listing all indexes

To list all indexes with the default output columns, the SHOW INDEXES command can be used. If all columns are required, use SHOW INDEXES YIELD *.

Showing all indexes
SHOW INDEXES
Result
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | name                              | state    | populationPercent | type     | entityType     | labelsOrTypes | properties         | indexProvider      | owningConstraint | lastRead                 | readCount |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 3  | "composite_range_node_index_name" | "ONLINE" | 100.0             | "RANGE"  | "NODE"         | ["Person"]    | ["age", "country"] | "range-1.0"        | NULL             | NULL                     | 0         |
| 4  | "composite_range_rel_index_name"  | "ONLINE" | 100.0             | "RANGE"  | "RELATIONSHIP" | ["PURCHASED"] | ["date", "amount"] | "range-1.0"        | NULL             | 2023-03-13T11:41:44.537Z | 1         |
| 13 | "example_index"                   | "ONLINE" | 100.0             | "RANGE"  | "NODE"         | ["Book"]      | ["title"]          | "range-1.0"        | NULL             | 2023-04-10T15:41:44.537Z | 2         |
| 14 | "indexOnBooks"                    | "ONLINE" | 100.0             | "TEXT"   | "NODE"         | ["Label1"]    | ["prop1"]          | "text-2.0"         | NULL             | NULL                     | 0         |
| 11 | "node_label_lookup_index"         | "ONLINE" | 100.0             | "LOOKUP" | "NODE"         | NULL          | NULL               | "token-lookup-1.0" | NULL             | 2023-04-13T08:11:15.537Z | 10        |
| 8  | "node_point_index_name"           | "ONLINE" | 100.0             | "POINT"  | "NODE"         | ["Person"]    | ["sublocation"]    | "point-1.0"        | NULL             | 2023-04-05T16:21:44.692Z | 1         |
| 1  | "node_range_index_name"           | "ONLINE" | 100.0             | "RANGE"  | "NODE"         | ["Person"]    | ["surname"]        | "range-1.0"        | NULL             | 2022-12-30T02:01:44.537Z | 6         |
| 5  | "node_text_index_nickname"        | "ONLINE" | 100.0             | "TEXT"   | "NODE"         | ["Person"]    | ["nickname"]       | "text-2.0"         | NULL             | 2023-04-13T11:41:44.537Z | 2         |
| 10 | "point_index_with_config"         | "ONLINE" | 100.0             | "POINT"  | "NODE"         | ["Label"]     | ["prop2"]          | "point-1.0"        | NULL             | NULL                     | 0         |
| 9  | "rel_point_index_name"            | "ONLINE" | 100.0             | "POINT"  | "RELATIONSHIP" | ["STREET"]    | ["intersection"]   | "point-1.0"        | NULL             | 2023-03-03T13:37:42.537Z | 2         |
| 2  | "rel_range_index_name"            | "ONLINE" | 100.0             | "RANGE"  | "RELATIONSHIP" | ["KNOWS"]     | ["since"]          | "range-1.0"        | NULL             | 2023-04-12T10:41:44.692Z | 5         |
| 6  | "rel_text_index_name"             | "ONLINE" | 100.0             | "TEXT"   | "RELATIONSHIP" | ["KNOWS"]     | ["interest"]       | "text-2.0"         | NULL             | 2023-04-01T10:40:44.537Z | 3         |
| 12 | "rel_type_lookup_index"           | "ONLINE" | 100.0             | "LOOKUP" | "RELATIONSHIP" | NULL          | NULL               | "token-lookup-1.0" | NULL             | 2023-04-12T21:41:44.537Z | 7         |
| 7  | "text_index_with_indexprovider"   | "ONLINE" | 100.0             | "TEXT"   | "RELATIONSHIP" | ["TYPE"]      | ["prop1"]          | "text-2.0"         | NULL             | NULL                     | 0         |
| 15 | "uniqueBookIsbn"                  | "ONLINE" | 100.0             | "RANGE"  | "NODE"         | ["Book"]      | ["isbn"]           | "range-1.0"        | "uniqueBookIsbn" | 2023-04-13T11:41:44.692Z | 6         |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
15 rows

One of the output columns from SHOW INDEXES is the name of the index. This can be used to drop the index with the DROP INDEX command.

Listing indexes with filtering

One way of filtering the output from SHOW INDEXES by index type is the use of type keywords, listed in the syntax description.

For example, to show only range indexes, use SHOW RANGE INDEXES.

Another more flexible way of filtering the output is to use the WHERE clause. An example is to only show indexes not belonging to constraints.

To show only range indexes that does not belong to a constraint we can combine the filtering versions.

Showing range indexes
SHOW RANGE INDEXES WHERE owningConstraint IS NULL
Result
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | name                              | state    | populationPercent | type    | entityType     | labelsOrTypes | properties         | indexProvider | owningConstraint | lastRead                 | readCount |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 3  | "composite_range_node_index_name" | "ONLINE" | 100.0             | "RANGE" | "NODE"         | ["Person"]    | ["age", "country"] | "range-1.0"   | NULL             | NULL                     | 0         |
| 4  | "composite_range_rel_index_name"  | "ONLINE" | 100.0             | "RANGE" | "RELATIONSHIP" | ["PURCHASED"] | ["date", "amount"] | "range-1.0"   | NULL             | 2023-03-13T11:41:44.537Z | 1         |
| 13 | "example_index"                   | "ONLINE" | 100.0             | "RANGE" | "NODE"         | ["Book"]      | ["title"]          | "range-1.0"   | NULL             | 2023-04-10T15:41:44.537Z | 2         |
| 1  | "node_range_index_name"           | "ONLINE" | 100.0             | "RANGE" | "NODE"         | ["Person"]    | ["surname"]        | "range-1.0"   | NULL             | 2022-12-30T02:01:44.537Z | 6         |
| 2  | "rel_range_index_name"            | "ONLINE" | 100.0             | "RANGE" | "RELATIONSHIP" | ["KNOWS"]     | ["since"]          | "range-1.0"   | NULL             | 2023-04-12T10:41:44.692Z | 5         |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
5 rows

This will only return the default output columns.

To get all columns, use:

SHOW RANGE INDEXES YIELD * WHERE owningConstraint IS NULL

DROP INDEX

An index can be dropped (removed) using the name with the DROP INDEX index_name command. This command can drop indexes of any type, except those backing constraints. The name of the index can be found using the SHOW INDEXES command, given in the output column name.

DROP INDEX index_name [IF EXISTS]

The DROP INDEX command is optionally idempotent. This means that its default behavior is to throw an error if an attempt is made to drop the same index twice. With IF EXISTS, no error is thrown and nothing happens should the index not exist.

Dropping an index requires the DROP INDEX privilege.

Examples

Drop an index

The following statement will attempt to drop the index named example_index.

Dropping an index
DROP INDEX example_index

If an index with that name exists it is removed, if not the command fails.

Drop a non-existing index

If it is uncertain if an index exists and you want to drop it if it does but not get an error should it not, use IF EXISTS.

The following statement will attempt to drop the index named missing_index_name.

Dropping an index with IF EXISTS
DROP INDEX missing_index_name IF EXISTS

If an index with that name exists it is removed, if not the command does nothing.

Syntax

The index name must be unique among both indexes and constraints.

Best practice is to give the index a name when it is created. If the index is not explicitly named, it gets an auto-generated name.

The CREATE ... INDEX ... command is optionally idempotent. This mean that its default behavior is to throw an error if an attempt is made to create the same index twice. With IF NOT EXISTS, no error is thrown and nothing happens should an index with the same name or same schema and index type already exist. It may still throw an error if conflicting constraints exist, such as constraints with the same name or schema and backing index type.

Table 2. Create a range index on nodes

Syntax

CREATE [RANGE] INDEX [index_name] [IF NOT EXISTS]
FOR (n:LabelName)
ON (n.propertyName_1[,
    n.propertyName_2,
    ...
    n.propertyName_n])
[OPTIONS "{" option: value[, ...] "}"]

Description

Create a range index on nodes, either on a single property or composite.

Index provider can be specified using the OPTIONS clause. There is only one available index provider for this index.

Table 3. Create a range index on relationships

Syntax

CREATE [RANGE] INDEX [index_name] [IF NOT EXISTS]
FOR ()-"["r:TYPE_NAME"]"-()
ON (r.propertyName_1[,
    r.propertyName_2,
    ...
    r.propertyName_n])
[OPTIONS "{" option: value[, ...] "}"]

Description

Create a range index on relationships, either on a single property or composite.

Index provider can be specified using the OPTIONS clause. There is only one available index provider for this index.

Table 4. Create a text index on nodes

Syntax

CREATE TEXT INDEX [index_name] [IF NOT EXISTS]
FOR (n:LabelName)
ON (n.propertyName)
[OPTIONS "{" option: value[, ...] "}"]

Description

Create a text index on nodes where the property has a string value.

Index provider can be specified using the OPTIONS clause.

Table 5. Create a text index on relationships

Syntax

CREATE TEXT INDEX [index_name] [IF NOT EXISTS]
FOR ()-"["r:TYPE_NAME"]"-()
ON (r.propertyName)
[OPTIONS "{" option: value[, ...] "}"]

Description

Create a text index on relationships where the property has a string value.

Index provider can be specified using the OPTIONS clause.

Table 6. Create a point index on nodes

Syntax

CREATE POINT INDEX [index_name] [IF NOT EXISTS]
FOR (n:LabelName)
ON (n.propertyName)
[OPTIONS "{" option: value[, ...] "}"]

Description

Create a point index on nodes where the property has a point value.

Index provider and configuration can be specified using the OPTIONS clause. There is only one available index provider for this index.

Table 7. Create a point index on relationships

Syntax

CREATE POINT INDEX [index_name] [IF NOT EXISTS]
FOR ()-"["r:TYPE_NAME"]"-()
ON (r.propertyName)
[OPTIONS "{" option: value[, ...] "}"]

Description

Create a point index on relationships where the property has a point value.

Index provider and configuration can be specified using the OPTIONS clause. There is only one available index provider for this index.

Table 8. Create a node label lookup index

Syntax

CREATE LOOKUP INDEX [index_name] [IF NOT EXISTS]
FOR (n)
ON EACH labels(n)
[OPTIONS "{" option: value[, ...] "}"]

Description

Create a node label lookup index.

Index provider can be specified using the OPTIONS clause. There is only one available index provider for this index.

Table 9. Create a relationship type lookup index

Syntax

CREATE LOOKUP INDEX [index_name] [IF NOT EXISTS]
FOR ()-"["r"]"-()
ON [EACH] type(r)
[OPTIONS "{" option: value[, ...] "}"]

Description

Create a relationship type lookup index.

Index provider can be specified using the OPTIONS clause. There is only one available index provider for this index.

Table 10. Drop an index

Syntax

DROP INDEX index_name [IF EXISTS]

Description

Drop an index of any index type.

Note

The command is optionally idempotent. This means that its default behavior is to throw an error if an attempt is made to drop the same index twice. With IF EXISTS, no error is thrown and nothing happens should the index not exist.

Table 11. List indexes

Syntax

SHOW [ALL | FULLTEXT | LOOKUP | POINT | RANGE | TEXT] INDEX[ES]
  [YIELD { * | field[, ...] } [ORDER BY field[, ...]] [SKIP n] [LIMIT n]]
  [WHERE expression]
  [RETURN field[, ...] [ORDER BY field[, ...]] [SKIP n] [LIMIT n]]

Description

List indexes in the database, either all or filtered on index type.

Note

When using the RETURN clause, the YIELD clause is mandatory and must not be omitted.

Creating an index requires the CREATE INDEX privilege, while dropping an index requires the DROP INDEX privilege and listing indexes require the SHOW INDEX privilege.

Planner hints and the USING keyword describes how to make the Cypher planner use specific indexes (especially in cases where the planner would not necessarily have used them).

Composite index limitations

Like single-property range indexes, composite range indexes support all predicates:

  • equality check: n.prop = value

  • list membership check: n.prop IN list

  • existence check: n.prop IS NOT NULL

  • range search: n.prop > value

  • prefix search: STARTS WITH

For details about each operator, see Operators.

However, predicates might be planned as existence check and a filter. For most predicates, this can be avoided by following these restrictions:

  • If there is any equality check and list membership check predicates, they need to be for the first properties defined by the index.

  • There can be up to one range search or prefix search predicate.

  • There can be any number of existence check predicates.

  • Any predicate after a range search, prefix search or existence check predicate has to be an existence check predicate.

The suffix search (ENDS WITH) and substring search (CONTAINS) predicates can utilize the index as well. However, they are always planned as an existence check and a filter and any predicates following after will therefore also be planned as such.

For example, an index on nodes with :Label(prop1,prop2,prop3,prop4,prop5,prop6) and predicates:

WHERE n.prop1 = 'x' AND n.prop2 = 1 AND n.prop3 > 5 AND n.prop4 < 'e' AND n.prop5 = true AND n.prop6 IS NOT NULL

will be planned as:

WHERE n.prop1 = 'x' AND n.prop2 = 1 AND n.prop3 > 5 AND n.prop4 IS NOT NULL AND n.prop5 IS NOT NULL AND n.prop6 IS NOT NULL

with filters on n.prop4 < 'e' and n.prop5 = true, since n.prop3 has a range search predicate.

And an index on nodes with :Label(prop1,prop2) with predicates:

WHERE n.prop1 ENDS WITH 'x' AND n.prop2 = false

will be planned as:

WHERE n.prop1 IS NOT NULL AND n.prop2 IS NOT NULL

with filters on n.prop1 ENDS WITH 'x' and n.prop2 = false, since n.prop1 has a suffix search predicate.

Composite indexes require predicates on all properties indexed. If there are predicates on only a subset of the indexed properties, it will not be possible to use the composite index. To get this kind of fallback behavior, it is necessary to create additional indexes on the relevant sub-set of properties or on single properties.