Overview
Indexing, or property indexing, is a technique used in Ultipa to speed up query performance by creating indexes on specific properties of nodes and edges. This allows the database to quickly locate and retrieve data based on indexed properties. Indexes are particularly beneficial for large datasets, as they optimize the filtering of specific property values without needing to scan the entire graph.
Index Types
Ultipa supports single index on one property and composite index which involve multiple properties from a schema.
Showing Indexes
To retrieve indexes in the current graphset:
// Shows all indexes
show().index()
// Shows all node indexes
show().node_index()
// Shows all edge indexes
show().edge_index()
The information about indexes is organized into the _nodeIndex
or _edgeIndex
table. Each table provides essential details about each index:
Field |
Description |
---|---|
id |
Index id. |
name |
Index name. |
properties |
The properties involved in the index. |
schema |
The schema of the properties involved in the index. |
status |
Index status, which can be DONE or CREATING . |
Creating Indexes
You can create one or more indexes using a single create()
statement. Each index is specified by chaining a node_index()
or edge_index()
method. Note that each property can only have one single index. The index creation runs as a job, you may run show().job(<id?>)
afterward to verify the success of the creation.
System properties in Ultipa are inherently optimized for query performance and have built-in efficiencies. They do not support indexing.
create()
.node_index(@<schema>.<property>(<bytes?>), "<indexName>")
.edge_index(@<schema>.<property>(<bytes?>), "<indexName>")
.node_index(@<schema>(<property1>(<bytes1?>), <property2>(<bytes2?>), ...), "<indexName>")
.edge_index(@<schema>(<property1>(<bytes1?>), <property2>(<bytes2?>), ...), "<indexName>")
...
Method | Param | Description |
---|---|---|
node_index() or edge_index() |
@<schema>.<property>(<bytes?>) or @<schema>(<property1>(<bytes1?>), <property2>(<bytes2?>),...) |
For a single index, specifies the property and its schema using @<schema>.<property> . For a composite index, lists multiple properties within a schema using @<schema>(<property1>, <property2>,...) .If the property type is string or text , you must specify the maximum number of bytes for the string used in a filter to apply this index. For standard English text, most encodings (like ASCII or UTF-8) use 1 byte per character. For non-English characters, the size may vary. For example, the size of one Chinese character is 3 bytes. Learn more about String Size Limitation. |
<indexName> |
The name of the index. Names must be unique among nodes and among edges, but a node index and an edge index may share the same name. |
To create single index named cBalance
for the property balance
of card
nodes:
create().node_index(@card.balance, "cBalance")
To create single index named name
for the property name
(string
type) of card
nodes, restricting the maximum search string length as 10
:
create().node_index(@card.name(10), "name")
To create composite index named transAmountNotes
for properties amount
and notes
(text
type, restricting the maximum search string length as 10
) for transfer
edges:
create().edge_index(@transfer(amount, notes(10)), "transAmountNotes")
To create multiple indexes:
create()
.node_index(@card.balance, "balance")
.edge_index(@transfer(amount, notes(10)), "transAmountNotes")
Dropping Indexes
You can drop one or more indexes using a single drop()
statement. Each index is specified by chaining a node_index()
or edge_index()
method. Dropping an index does not affect the actual property values stored in shards.
A property with an index cannot be dropped until the index is deleted.
To drop the node index cBalance
:
drop().node_index("cBalance")
To drop the edge index transAmountNotes
:
drop().edge_index("transAmountNotes")
To drop multiple indexes:
drop().node_index("balance").edge_index("transAmountNotes")
Using Indexes
Indexes are automatically applied when the corresponding properties are used in query filters, without the need for explicit declarations.
Leftmost Prefix Rule
The order of properties in a composite index matters — queries that match the leftmost properties of the index (i.e., the first property or the first few properties in the defined order) will benefit from the index.
For example:
create().node_index(@user(name(10),age), 'name_age')
find().nodes({@user.name == "Kavi" && @user.age > 20})
uses the index.find().nodes({@user.name == "Kavi"})
uses the index.find().nodes({@user.age > 20})
doesn't use the index.find().nodes({@user.name == "Kavi" && @user.age > 20 && @user.grade == 7})
uses the index, meanwhile it contains the filtering for the@user.grade
property which lacks an index.
String Size Limitation
For indexes with string
or text
properties, ensure the size of the string used in the filter does not exceed the defined limit.
For example, an index Username
is created for the name
property of the user
nodes with a 8-byte limitation:
create().node_index(@user.name(8), "Username")
The query below won't utilize the Username
index as the specified string Aventurine
exceeds the 8-byte limit:
find().nodes({@user.name == "Aventurine"}) as n return n