Indexes and constraints
This is the documentation of the GraphQL Library version 7. For the long-term support (LTS) version 5, refer to GraphQL Library version 5 LTS. |
This page describes how to use indexes and constraints in the Neo4j GraphQL Library.
@fulltext
Definition
You can use the @fulltext
directive to specify a full-text index inside Neo4j.
For example:
input FullTextInput {
indexName: String!
queryName: String!
fields: [String]!
}
"""
Informs @neo4j/graphql that there should be a fulltext index in the database, allows users to search by the index in the generated schema.
"""
directive @fulltext(indexes: [FullTextInput]!) on OBJECT
Using this directive does not automatically ensure the existence of these indexes. They must be created manually.
Usage
The @fulltext
directive can be used on nodes.
In this example, a full-text index called "ProductName", for the name field
, on the Product
node, is specified:
type Product @fulltext(indexes: [{ indexName: "ProductName", fields: ["name"] }]) @node {
name: String!
color: Color! @relationship(type: "OF_COLOR", direction: OUT)
}
This index can be created in the database by running the following Cypher:
CREATE FULLTEXT INDEX ProductName FOR (n:Product) ON EACH [n.name]
For every index specified, a new top level query is generated by the library. For example, for the previous type definitions, the following query and types are generated:
type Query {
productsFulltextProductName(phrase: String!, where: ProductFulltextWhere, sort: [ProductFulltextSort!],
limit: Int, offset: Int): [ProductFulltextResult!]!
}
"""The result of a fulltext search on an index of Product"""
type ProductFulltextResult {
score: Float
product: Product
}
"""The input for filtering a fulltext query on an index of Product"""
input ProductFulltextWhere {
score: FloatWhere
product: ProductWhere
}
"""The input for sorting a fulltext query on an index of Product"""
input ProductFulltextSort {
score: SortDirection
product: ProductSort
}
"""The input for filtering the score of a fulltext search"""
input FloatWhere {
min: Float
max: Float
}
This query can then be used to perform a Lucene full-text query to match and return products. Here is an example of this:
query {
productsFulltextProductName(phrase: "Hot sauce", where: { score: { min: 1.1 } } sort: [{ product: { name: ASC } }]) {
score
product {
name
}
}
}
This query produces results in the following format:
{
"data": {
"productsFulltextProductName": [
{
"score": 2.1265015602111816,
"product": {
"name": "Louisiana Fiery Hot Pepper Sauce"
}
},
{
"score": 1.2077560424804688,
"product": {
"name": "Louisiana Hot Spiced Okra"
}
},
{
"score": 1.3977186679840088,
"product": {
"name": "Northwoods Cranberry Sauce"
}
}
]
}
}
Additionally, it is possible to define a custom query name as part of the @fulltext
directive by using the queryName
argument:
type Product @fulltext(indexes: [{ queryName: "CustomProductFulltextQuery", indexName: "ProductName", fields: ["name"] }]) @node {
name: String!
color: Color! @relationship(type: "OF_COLOR", direction: OUT)
}
This produces the following top-level query:
type Query {
CustomProductFulltextQuery(phrase: String!, where: ProductFulltextWhere, sort: [ProductFulltextSort!],
limit: Int, offset: Int): [ProductFulltextResult!]!
}
This query can then be used like this:
query {
CustomProductFulltextQuery(phrase: "Hot sauce", sort: [{ score: ASC }]) {
score
product {
name
}
}
}
@vector
With the @vector
GraphQL directive you can query your database to perform a vector index search.
Queries are performed by passing in either a vector index or a query phrase.
A query by vector index finds nodes with a vector embedding similar to that index. That is, the query performs a nearest neighbor search.
In contrast, a query by phrase (a string of text) forwards the phrase to the Neo4j GenAI plugin and the plugin generates a vector embedding for it. This embedding is then compared to the node vector embeddings in the database.
Prerequisites
|
Vector index searches are read-only in the sense that the data which the queries operate on are retrieved from the database but not altered or written back to the database. |
Definition
"""Informs @neo4j/graphql that there should be a vector index in the database, allows users to search by the index in the generated schema."""
directive @vector(indexes: [VectorIndexInput]!) on OBJECT
VectorIndexInput
is defined as follows:
input VectorIndexInput {
"""(Required) The name of the vector index."""
indexName: String!
"""(Required) The name of the embedding property on the node."""
embeddingProperty: String!
"""(Required) The name of the query."""
queryName: String
"""(Optional) The name of the provider."""
provider: String
}
If the optional field provider
is set, the type is used for a query by phrase, otherwise for a query by vector.
Allowed values for the provider
field are defined by the available GenAI providers.
Usage
Query by vector index
Perform a nearest neighbor search by passing a vector to find nodes with a vector embedding similar to that vector.
type Product @node @vector(indexes: [{
indexName: "productDescriptionIndex",
embeddingProperty: "descriptionVector",
queryName: "searchByDescription"
}]) {
id: ID!
name: String!
description: String!
}
This defines the query to be performed on all Product
nodes which have a vector index named productDescriptionIndex
for the property descriptionVector
, implying that a vector embedding has been created for the description
property of each node.
query FindSimilarProducts($vector: [Float]!) {
searchByDescription(vector: $vector) {
edges {
cursor
score
node {
id
name
description
}
}
}
}
The input $vector
is a list of FLOAT
values and should look similar to this:
{
"vector": [
0.123456,
...,
0.654321,
]
}
The query returns all Product
nodes with a vector embedding on their descriptionVector
property which is similar to the query argument $vector
.
Query by phrase
Perform a query which utilizes the Neo4j GenAI plugin to create a vector embedding for a search phrase and then compare it to existing vector embeddings on nodes in the database.
Requires credentials for the plugin. |
Ensure your provider credentials are set in the call to Neo4jGraphQL, for example:
const neoSchema = new Neo4jGraphQL({
typeDefs,
driver,
features: {
vector: {
OpenAI: {
token: "my-open-ai-token",
model: "text-embedding-3-small",
},
},
},
});
OpenAI
is one of the GenAI providers for generating vector embeddings.
See GenAI providers for the full list of providers and their respective identifiers.
type Product @node @vector(indexes: [{
indexName: "productDescriptionIndex",
embeddingProperty: "descriptionVector",
provider: OPEN_AI, # Assuming this is configured in the server
queryName: "searchByPhrase"
}]) {
id: ID!
name: String!
description: String!
}
This defines the query to be performed on all Product
nodes which have a vector index named productDescriptionIndex
for the property descriptionVector
, implying that a vector embedding has been created for the description
property of each node.
query SearchProductsByPhrase($phrase: String!) {
searchByPhrase(phrase: $phrase) {
edges {
cursor
score
node {
id
name
description
}
}
}
}
First, the query passes the query phrase argument $phrase
to the GenAI plugin and lets it generate a vector embedding for the phrase.
Then it returns all Product
nodes with a vector embedding on their descriptionVector
property which are similar to the vector embedding generated by the plugin.