索引和约束
此页面介绍如何在 Neo4j GraphQL 库中使用索引和约束。
唯一节点属性约束
唯一节点属性约束映射到您类型定义中使用的@unique
指令,其定义如下
"""Informs @neo4j/graphql that there should be a uniqueness constraint in the database for the decorated field."""
directive @unique(
"""The name which should be used for this constraint. By default; type name, followed by an underscore, followed by the field name."""
constraintName: String
) on FIELD_DEFINITION
使用此指令不会自动确保这些约束的存在,您需要在服务器启动时运行一个函数。有关详细信息,请参阅断言约束部分。
用法
@unique
指令只能用于表示节点的 GraphQL 对象类型,并且仅适用于节点的“主”标签。
在以下示例中,为标签Colour
和属性hexadecimal
断言了一个唯一约束
type Colour {
hexadecimal: String! @unique
}
在下一个示例中,为标签Colour
和属性hexadecimal
断言了一个名为unique_colour
的唯一约束
type Colour {
hexadecimal: String! @unique(constraintName: "unique_colour")
}
@node
指令用于在此下一个示例中更改数据库标签映射,因此为列表中的第一个标签Color
和属性hexadecimal
断言了一个唯一约束
type Colour @node(labels: ["Color"]) {
hexadecimal: String! @unique
}
在以下示例中,在断言约束时也会检查@node
指令的labels
参数中指定的所有标签。如果为具有Hue
标签的节点的hexadecimal
属性指定了唯一约束,但没有为Color
标签指定,则在运行assertIndexesAndConstraints
时不会抛出错误,也不会创建新的约束。
type Colour @node(labels: ["Color", "Hue"]) {
hexadecimal: String! @unique
}
全文索引
您可以使用@fulltext
指令在 Neo4j 中添加全文索引。例如
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
使用此指令不会自动确保这些索引的存在。您需要在服务器启动时运行一个函数。有关详细信息,请参阅断言约束部分。
指定
@fulltext
指令可用于节点。在此示例中,为Product
节点上的name
字段添加了一个名为“ProductName”的Fulltext
索引
type Product @fulltext(indexes: [{ indexName: "ProductName", fields: ["name"] }]) {
name: String!
color: Color! @relationship(type: "OF_COLOR", direction: OUT)
}
当您运行断言约束时,它们会像这样创建索引
CREATE FULLTEXT INDEX ProductName FOR (n:Product) ON EACH [n.name]
用法
对于每个指定的索引,库都会生成一个新的顶级查询。例如,对于前面的类型定义,会生成以下查询和类型
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
}
然后可以使用此查询执行Lucene 全文查询以匹配和返回产品。这是一个示例
query {
productsFulltextProductName(phrase: "Hot sauce", where: { score: { min: 1.1 } } sort: [{ product: { name: ASC } }]) {
score
product {
name
}
}
}
此查询以以下格式生成结果
{
"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"
}
}
]
}
}
此外,可以通过使用queryName
参数在@fulltext
指令中定义自定义查询名称
type Product @fulltext(indexes: [{ queryName: "CustomProductFulltextQuery", indexName: "ProductName", fields: ["name"] }]) {
name: String!
color: Color! @relationship(type: "OF_COLOR", direction: OUT)
}
这会生成以下顶级查询
type Query {
CustomProductFulltextQuery(phrase: String!, where: ProductFulltextWhere, sort: [ProductFulltextSort!],
limit: Int, offset: Int): [ProductFulltextResult!]!
}
然后可以像这样使用此查询
query {
CustomProductFulltextQuery(phrase: "Hot sauce", sort: [{ score: ASC }]) {
score
product {
name
}
}
}
断言约束
为了确保数据库中存在指定的约束,您需要运行函数assertIndexesAndConstraints
。一个创建必要约束的简单示例可能如下所示,假设变量driver
中有一个有效的驱动程序实例。这将创建两个约束,一个用于每个用@id
和@unique
装饰的字段,并应用@fulltext
中指定的索引
const typeDefs = `#graphql
type Color {
id: ID! @id
hexadecimal: String! @unique
}
type Product @fulltext(indexes: [{ indexName: "ProductName", fields: ["name"] }]) {
name: String!
color: Color! @relationship(type: "OF_COLOR", direction: OUT)
}
`;
const neoSchema = new Neo4jGraphQL({ typeDefs, driver });
const schema = await neoSchema.getSchema();
await neoSchema.assertIndexesAndConstraints({ options: { create: true }});
向量索引搜索
使用@vector
GraphQL 指令,您可以查询数据库以执行向量索引搜索。查询通过传入向量索引或查询短语来执行。
通过向量索引进行的查询查找具有与该索引相似的向量嵌入的节点。也就是说,查询执行最近邻搜索。
相反,通过短语(一段文本)进行的查询会将短语转发到Neo4j GenAI 插件,插件会为此生成向量嵌入。然后将此嵌入与数据库中的节点向量嵌入进行比较。
先决条件
|
从某种意义上说,向量索引搜索是只读的,因为查询操作的数据是从数据库中检索的,但不会更改或写回数据库。 |
定义
"""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
定义如下
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
}
如果设置了可选字段provider
,则该类型用于通过短语进行查询,否则用于通过向量进行查询。provider
字段的允许值由可用的GenAI 提供程序定义。
用法
通过向量索引查询
通过传递向量来执行最近邻搜索,以查找具有与该向量相似的向量嵌入的节点。
type Product @vector(indexes: [{
indexName: "productDescriptionIndex",
embeddingProperty: "descriptionVector",
queryName: "searchByDescription"
}]) {
id: ID!
name: String!
description: String!
}
这定义了要对所有具有名为productDescriptionIndex
的向量索引(用于属性descriptionVector
)的Product
节点执行的查询,这意味着已为每个节点的description
属性创建了向量嵌入。
query FindSimilarProducts($vector: [Float]!) {
searchByDescription(vector: $vector) {
edges {
cursor
score
node {
id
name
description
}
}
}
}
输入$vector
是FLOAT
值的列表,应类似于以下内容
{
"vector": [
0.123456,
...,
0.654321,
]
}
查询返回所有Product
节点,这些节点在其descriptionVector
属性上具有与查询参数$vector
相似的向量嵌入。
通过短语查询
执行一个查询,该查询利用Neo4j GenAI 插件为搜索短语创建向量嵌入,然后将其与数据库中节点上的现有向量嵌入进行比较。
需要插件的凭据。 |
确保在对 Neo4jGraphQL 的调用中设置了您的提供程序凭据,例如
const neoSchema = new Neo4jGraphQL({
typeDefs,
driver,
features: {
vector: {
OpenAI: {
token: "my-open-ai-token",
model: "text-embedding-3-small",
},
},
},
});
OpenAI
是用于生成向量嵌入的 GenAI 提供程序之一。有关提供程序及其相应标识符的完整列表,请参阅GenAI 提供程序。
type Product @vector(indexes: [{
indexName: "productDescriptionIndex",
embeddingProperty: "descriptionVector",
provider: OPEN_AI, # Assuming this is configured in the server
queryName: "searchByPhrase"
}]) {
id: ID!
name: String!
description: String!
}
这定义了要对所有具有名为productDescriptionIndex
的向量索引(用于属性descriptionVector
)的Product
节点执行的查询,这意味着已为每个节点的description
属性创建了向量嵌入。
query SearchProductsByPhrase($phrase: String!) {
searchByPhrase(phrase: $phrase) {
edges {
cursor
score
node {
id
name
description
}
}
}
}
首先,查询将查询短语参数$phrase
传递给 GenAI 插件,并让它为该短语生成向量嵌入。然后,它返回所有Product
节点,这些节点在其descriptionVector
属性上具有与插件生成的向量嵌入相似的向量嵌入。