Skip to content
Developer Edition runs on one host and does not require a product license file. Need multi-host deployment or performance testing at scale? Explore Enterprise Edition

CREATE NORMAL INDEX statement

The CREATE NORMAL INDEX statement creates a normal index on a specific graph or temporary graph.

You can specify the graph or temporary graph by using either of the following methods:

  • Add a USE clause before this statement to set the working graph.
  • Use SESSION SET in advance to set the graph or temporary graph for the current session.

If both methods are used, the graph specified in the USE clause takes precedence. If neither method is used, an error is returned.

You can create a normal index on one or more properties of a single node type or edge type to speed up queries that filter or sort data based on the indexed properties.

To create other types of indexes, see CREATE VECTOR INDEX, CREATE SPATIAL INDEX, and CREATE FULLTEXT INDEX.

Note

An operation involving a non-default schema or an object in it requires access to the schema, either implicitly or through an explicit USAGE grant, as well as the privilege required for the operation. The schema access check and the privilege check for the requested operation are independent; satisfying one does not satisfy the other. Schema access control does not apply to temporary graphs or built-in procedures and functions. For more information, see Schema access control.

Prerequisites

  • To create a normal index on a graph, you must either be the owner of the graph, be granted to perform the action INDEX on the graph, or be granted to perform the action CREATE NORMAL INDEX on the used schema. For more information, see Roles and privileges.
  • To create a normal index on a temporary graph, you must be the user with the role ADMIN or the owner of the temporary graph.

Behavior and impact

  • After executing CREATE NORMAL INDEX, the system automatically starts a background index build job. This background job can appear as a REPAIR_INDEX job in SHOW JOB or SHOW JOBS. You do not need to manually trigger a separate repair operation for the new index to take effect.
  • Queries cannot use the new index until the build is complete.
  • While the index is being built, read and write requests can continue. However, the build process consumes additional I/O (and some CPU/memory) resources, which may increase query or write latency.
  • If index creation fails, the system automatically rolls back the failed creation. Starting from 5.2, failed index creation is rolled back automatically, so no separate repair operation is needed.

Syntax

create_index_statement
CREATE NORMAL INDEX IF NOT EXISTS index_name ON NODE VERTEX TYPE node_type_name EDGE RELATIONSHIP TYPE edge_type_name ( index_property_list )
index_property_list
property_name ASC DESC ,

create_index_statement ::=
    'CREATE' 'NORMAL'? 'INDEX' ('IF NOT EXISTS')? index_name 'ON' ( ( ('NODE' | 'VERTEX') 'TYPE'? node_type_name ) | ( ('EDGE'|'RELATIONSHIP') 'TYPE'? edge_type_name ) ) '(' index_property_list ')'

index_property_list ::=
    ( property_name ('ASC' | 'DESC')? ) ( ',' ( property_name ('ASC' | 'DESC')? ) )*

Parameters

NORMAL

Explicitly specifies that the index type to create is a normal index. This keyword can be omitted.

IF NOT EXISTS

This clause checks whether an index with the same name already exists. If it does, the index is not created and no error is raised.

If this clause is not specified and an index with the same name already exists, an error is raised.

index_name

The name of the index to be created. The name is a regular identifier and must be unique among all index types within the same graph.

For more information about identifiers, see Rules for naming identifiers.

node_type_name

The name of the node type on which to create the index. You can create multiple indexes on the same node type based on different properties.

edge_type_name

The name of the edge type on which to create the index. You can create multiple indexes on the same edge type based on different properties.

index_property_list

The list of properties for the index. At least one property must be specified.

When creating a normal index on multiple properties, the order of properties in the index matches the order specified in index_property_list. Therefore, when filtering or sorting data based on indexed properties, it is recommended to write queries following the property order in the index to optimize query performance.

property_name

The name of a property of the node type or edge type to index.

The value type of the property cannot be LIST, SET, MAP, VECTOR, or GEOGRAPHY.

For edge type indexes, the system fields _src (source node) and _dst (destination node) can also be used as index properties. When _src or _dst is placed as the first column in the index property list, this creates a vertex-centric index. For more information, see Vertex-centric indexes below.

ASC | DESC

The sort order of property values in the index.

  • ASC: The default value. Sorts property values in ascending order.
  • DESC: Sorts property values in descending order.

For sorting rules of different data types, see Comparison predicates.

Vertex-centric indexes

Concept

A vertex-centric index is an edge index organized around nodes. In graph traversal scenarios, finding edges associated with a specific node is one of the most common operations. If a node has a large number of associated edges (e.g., a super node), traversing all edges and filtering them one by one can be very expensive. A vertex-centric index places the system field _src (source node) or _dst (destination node) as the first column of an edge index, allowing queries to quickly locate edges for a specific node and further filter them using subsequent index columns, thereby avoiding a full edge scan.

A vertex-centric index is not a separate index type but a special way to build a normal edge index. It uses the standard CREATE NORMAL INDEX syntax. You simply place _src or _dst as the first column in the index property list.

Use cases

  • Find qualifying outgoing edges from a specific source node: use _src as the first index column.
  • Find incoming edges to a specific destination node: use _dst as the first index column.
  • Filter edges on super nodes: when a node has a large number of associated edges, a vertex-centric index can significantly reduce the number of edges that need to be scanned.

Auto-selection

The optimizer can automatically select vertex-centric indexes during edge-scan planning when the query's WHERE clause contains at least one filter condition on an edge property (e.g., w.rate >= 3). Specifically, auto-selection requires a usable vertex-centric index whose key columns match the scan direction (outgoing uses a _src-leading index, incoming uses a _dst-leading index) and cover the filtered edge property. When these conditions are met, you do not need to specify an index hint.

If the query does not filter on any edge property (i.e., only the anchor vertex ID is used to locate edges), the optimizer will not auto-select a vertex-centric index. This is because without an edge property filter, the vertex-centric index can only utilize its leading _src/_dst column, which offers no advantage over the default edge-table prefix scan. You can still use an explicit hint to force a specific vertex-centric index when needed.

Limitations

  • Applicable only to edge type indexes, not to node type indexes.
  • _src or _dst can only be placed as the first column in the index property list.
  • Creating vertex-centric indexes on undirected edge types is not supported.
  • Indexes starting with _src and indexes starting with _dst serve different query directions. To speed up both outgoing and incoming edge queries, you need to create two separate indexes.
  • All other limitations of normal indexes also apply (e.g., you cannot create an index on a LIST type property).

Examples

The following examples are based on the graph movie and the temporary graph #movie_temporary_graph created in CREATE GRAPH and CREATE TEMPORARY GRAPH respectively.

Create a normal index on a node type in a graph

'''
USE movie
CREATE NORMAL INDEX IF NOT EXISTS idx_actor_age ON NODE Actor ( birthDate ASC )
'''

This creates an ascending normal index named idx_actor_age on the birthDate property of the Actor node type.

Create a normal index on an edge type in a graph

'''
USE movie
CREATE NORMAL INDEX IF NOT EXISTS idx_watch_rating ON EDGE Watch ( rate DESC )
'''

This creates a descending normal index named idx_watch_rating on the rate property of the Watch edge type.

Create a normal index on a temporary graph

'''
USE #movie_temporary_graph
CREATE NORMAL INDEX IF NOT EXISTS idx_actor_age_temp ON NODE Actor ( birthDate ASC )
'''
'''
USE #movie_temporary_graph
CREATE NORMAL INDEX IF NOT EXISTS idx_watch_rating_temp ON EDGE Watch ( rate DESC )
'''

Create a vertex-centric index

Create a vertex-centric index with _src as the first column to speed up finding watch records from a specific user, filtered by rating:

'''
USE movie
CREATE NORMAL INDEX IF NOT EXISTS idx_watch_src_rate ON EDGE Watch ( _src ASC, rate DESC )
'''

Create a vertex-centric index with _dst as the first column to speed up finding all users who watched a specific movie, filtered by rating:

'''
USE movie
CREATE NORMAL INDEX IF NOT EXISTS idx_watch_dst_rate ON EDGE Watch ( _dst ASC, rate DESC )
'''

Auto-selection of vertex-centric indexes

When the query has an edge property filter, the optimizer automatically selects the appropriate vertex-centric index.

Query outgoing edges by source node:

'''
PROFILE 
USE movie
MATCH (a:Person)-[w:Watch]->(m:Movie)
WHERE a.id > 100 AND w.rate >= 3
RETURN m.name, w.rate
ORDER BY w.rate DESC
LIMIT 20
'''

Query incoming edges by destination node:

'''
PROFILE
USE movie
MATCH (m:Movie{id:101})<-[w:Watch]-(a:Person)
WHERE a.id > 100 AND w.rate >= 3
RETURN a.id, w.rate
ORDER BY w.rate DESC
LIMIT 20
'''

Use the PROFILE or EXPLAIN command to verify the execution plan. If it contains an IndexScan operator referencing a vertex-centric index name (e.g., idx_watch_src_rate or idx_watch_dst_rate), the vertex-centric index is in effect. For more information, see EXPLAIN and PROFILE.

Note

If the query does not filter on any edge property (e.g., no condition like w.rate >= 3), the optimizer will not auto-select a vertex-centric index. In this case, you can still use an explicit index hint to force its use (e.g., MATCH (a:Person)-[w:Watch/*+ INDEX(idx_watch_src_rate) */]->(m:Movie)). For more information about hints, see Configure index hints.