全文索引

全文索引用于根据 STRING 属性索引节点和关系。与只能执行有限 STRING 匹配(精确、前缀、子字符串或后缀匹配)的范围文本索引不同,全文索引将给定 STRING 属性中的单个词语存储起来。这意味着全文索引可用于在 STRING 属性的内容中进行匹配。全文索引还会返回给定查询字符串与数据库中存储的 STRING 值之间的近似分数,从而使它们能够语义化地解释数据。

全文索引由 Apache Lucene 索引和搜索库提供支持。

示例图

以下图用于下方示例

full text graph

要重新创建它,请对空的 Neo4j 数据库运行以下查询

CREATE (nilsE:Employee {name: "Nils-Erik Karlsson", position: "Engineer", team: "Kernel", peerReviews: ['Nils-Erik is difficult to work with.', 'Nils-Erik is often late for work.']}),
(lisa:Manager {name: "Lisa Danielsson", position: "Engineering manager"}),
(nils:Employee {name: "Nils Johansson", position: "Engineer", team: "Operations"}),
(maya:Employee {name: "Maya Tanaka", position: "Senior Engineer", team:"Operations"}),
(lisa)-[:REVIEWED {message: "Nils-Erik is reportedly difficult to work with."}]->(nilsE),
(maya)-[:EMAILED {message: "I have booked a team meeting tomorrow."}]->(nils)

创建全文索引

全文索引通过 CREATE FULLTEXT INDEX [index_name] 命令创建。建议在创建时为索引命名。如果创建时未指定名称,则会为该全文索引分配一个随机名称。

CREATE FULLTEXT INDEX 命令是可选幂等的。这意味着其默认行为是,如果尝试两次创建相同的索引,则会抛出错误。如果将 IF NOT EXISTS 附加到命令中,则如果具有相同名称的索引或相同Schema上的全文索引已存在,则不会抛出错误,也不会发生任何事情。从 Neo4j 5.17 开始,会返回一个信息通知,显示阻止创建的现有索引。从 Neo4j 5.16 开始,索引名称也可以作为参数给出,例如 CREATE FULLTEXT INDEX $name FOR …​

创建全文索引需要CREATE INDEX 权限

创建全文索引时,您需要指定它应该应用于的标签/关系类型和属性名称。

此语句为标签为 EmployeeManager 的节点在每个 nameteam 属性上创建一个名为 namesAndTeams 的全文索引

在节点标签和属性组合上创建全文索引
CREATE FULLTEXT INDEX namesAndTeams FOR (n:Employee|Manager) ON EACH [n.name, n.team]

此查询突出了全文索引和搜索性能索引之间的两个主要区别

  • 全文索引可以应用于多个节点标签。

  • 全文索引可以应用于多个属性,但与复合搜索性能索引不同,全文索引存储的实体具有索引标签或关系类型中的至少一个,并且具有索引属性中的至少一个

类似地,虽然关系只能有一种类型,但全文索引可以存储多种关系类型。在这种情况下,所有匹配关系类型中至少一种和索引属性中至少一种的类型都将包含在内。

此语句为关系类型 REVIEWEDEMAILEDmessage 属性上创建一个名为 communications 的全文索引

在关系类型和属性组合上创建全文索引
CREATE FULLTEXT INDEX communications FOR ()-[r:REVIEWED|EMAILED]-() ON EACH [r.message]

分词和分析器

全文索引将单个词语存储在 STRING 属性中。这是通过分词器实现的,它将字符流分解为单个词元(通常是单个词语)。STRING 如何分词取决于全文索引配置的分析器。默认分析器 (standard-no-stop-words) 会分析索引值和查询字符串。

停用词是语言中常见的词语,可以在信息检索任务中过滤掉,因为它们在确定字符串含义时被认为用处不大。这些词语通常较短且在各种上下文中频繁使用。

例如,Lucene 的 english 分析器中包含以下停用词:"a", "an", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", 和 "with"。

删除停用词有助于减小存储数据的大小,从而提高数据检索的效率。

在某些情况下,为索引值和查询字符串使用不同的分析器可能更合适。例如,如果处理用瑞典语编写的 STRING 值,选择 swedish 分析器可能会有益,它知道如何分词瑞典语单词,并会避免索引瑞典语停用词。

db.index.fulltext.listAvailableAnalyzers() 过程显示所有可用的分析器。

Neo4j 还支持使用自定义分析器。欲了解更多信息,请参阅Java 参考手册 → 全文索引分析器提供者

配置设置

CREATE FULLTEXT INDEX 命令接受一个可选的 OPTIONS 子句,其中可以指定 indexConfig。以下语句使用参数为标签为 EmployeeManager 的节点创建一个全文索引。使用参数创建和删除索引的功能是在 Neo4j 5.16 中引入的。

参数
{
  "name": "peerReviews"
}
使用 OPTIONS 创建全文索引
CREATE FULLTEXT INDEX $name FOR (n:Employee|Manager) ON EACH [n.peerReviews]
OPTIONS {
  indexConfig: {
    `fulltext.analyzer`: 'english', (1)
    `fulltext.eventually_consistent`: true (2)
  }
}
1 fulltext.analyzer 设置可用于配置索引特定的分析器。在这种情况下,它被设置为 english 分析器。fulltext.analyzer 设置的可能值可以通过 db.index.fulltext.listAvailableAnalyzers 过程列出。
2 fulltext.eventually_consistent 设置,如果设置为 true,会将索引置于最终一致的更新模式。这意味着更新将在后台线程中“尽快”应用,而不是在事务提交期间应用,这与其他索引不同。

有关如何配置全文索引的更多信息,请参阅操作手册 → 支持全文搜索的索引

查询全文索引

搜索性能索引不同,全文索引不会被 Cypher® 查询规划器自动使用。要查询全文索引,请使用 db.index.fulltext.queryNodesdb.index.fulltext.queryRelationships 过程。

索引在其 statePOPULATING(在创建后立即发生)时无法使用。要检查全文索引的 state — 无论是 ONLINE(可用)还是 POPULATING(仍在构建中;populationPercent 列显示索引创建的进度)— 请运行以下命令:SHOW FULLTEXT INDEXES

此查询使用 db.index.fulltext.queryNodes 在先前创建的全文索引 namesAndTeams 中查找 nils

查询节点属性的全文索引
CALL db.index.fulltext.queryNodes("namesAndTeams", "nils") YIELD node, score
RETURN node.name, score
表 1. 结果
node.name 分数

"Nils Johansson"

0.3300700783729553

"Nils-Erik Karlsson"

0.27725890278816223

行数:2

许多全文索引分析器(包括 Neo4j 的默认分析器)会将词元规范化为小写。因此,在 Neo4j 上使用时,全文索引默认不区分大小写。

score 列表示索引认为该条目与给定查询字符串的匹配程度。因此,除了任何精确匹配外,全文索引还会返回给定查询字符串的近似匹配。这是可能的,因为索引的属性值和对索引的查询都通过分析器处理,以便索引可以找到与所提供的 STRING 不完全匹配的数据实体。

score 结果始终按分数降序返回,其中最佳匹配结果条目排在首位。

此查询使用 db.index.fulltext.queryRelationships 查询先前创建的 communications 全文索引中包含 "meeting" 的任何 message

查询关系属性的全文索引
CALL db.index.fulltext.queryRelationships("communications", "meeting") YIELD relationship, score
RETURN type(relationship), relationship.message, score
表 2. 结果
type(关系) relationship.message 分数

"EMAILED"

"I have booked a team meeting tomorrow."

0.3239005506038666

行数:1

要仅获取精确匹配,请引用您要搜索的 STRING

查询全文索引以获取精确匹配
CALL db.index.fulltext.queryNodes("namesAndTeams", '"Nils-Erik"') YIELD node, score
RETURN node.name, score
表 3. 结果
node.name 分数

"Nils-Erik Karlsson"

0.7588480710983276

行数:1

查询字符串还支持使用 Lucene 布尔运算符 (AND, OR, NOT, +, -)

使用逻辑运算符查询全文索引
CALL db.index.fulltext.queryNodes("namesAndTeams", 'nils AND kernel') YIELD node, score
RETURN node.name, node.team, score
表 4. 结果
node.name node.team 分数

"Nils-Erik Karlsson"

"Kernel"

0.723090410232544

行数:1

可以通过在查询字符串前加上 <propertyName>: 来将搜索限制到特定属性。

查询特定属性的全文索引
CALL db.index.fulltext.queryNodes("namesAndTeams", 'team:"Operations"') YIELD node, score
RETURN node.name, node.team, score
表 5. 结果
node.name node.team 分数

"Nils Johansson"

"Operations"

0.21363800764083862

"Maya Tanaka"

"Operations"

0.21363800764083862

行数:2

有关 Lucene 查询语法的完整描述,请参阅Lucene 文档

STRING 值列表

如果索引属性包含 STRING 值列表,则每个条目都会独立分析,并且所有生成的词元都与相同的属性名称关联。这意味着当查询此类索引节点或关系时,如果任何列表元素与查询字符串匹配,则会匹配。出于评分目的,全文索引将其视为单个属性值,分数将表示查询与整个列表匹配的接近程度。

查询全文索引以获取 STRING 属性列表中存在的内容
CALL db.index.fulltext.queryNodes('peerReviews', 'late') YIELD node, score
RETURN node.name, node.peerReviews, score
表 6. 结果
node.name node.peerReviews 分数

"Nils-Erik Karlsson"

["Nils-Erik is difficult to work with.", "Nils-Erik is often late for work."]

0.13076457381248474

显示全文索引

要列出数据库中的所有全文索引,请使用 SHOW FULLTEXT INDEXES 命令

显示数据库中的所有全文索引
SHOW FULLTEXT INDEXES
结果
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | name             | state    | populationPercent | type       | entityType     | labelsOrTypes           | properties       | indexProvider  | owningConstraint | lastRead                 | readCount |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 4  | "communications" | "ONLINE" | 100.0             | "FULLTEXT" | "RELATIONSHIP" | ["REVIEWED", "EMAILED"] | ["message"]      | "fulltext-1.0" | NULL             | 2023-10-31T15:06:10.270Z | 2         |
| 3  | "namesAndTeams"  | "ONLINE" | 100.0             | "FULLTEXT" | "NODE"         | ["Employee", "Manager"] | ["name", "team"] | "fulltext-1.0" | NULL             | 2023-10-31T15:07:48.874Z | 5         |
| 6  | "peerReviews"    | "ONLINE" | 100.0             | "FULLTEXT" | "NODE"         | ["Employee", "Manager"] | ["peerReviews"]  | "fulltext-1.0" | NULL             | 2023-10-31T15:09:05.391Z | 3         |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

与搜索性能索引类似,SHOW 命令可以按特定列进行筛选

使用筛选显示全文索引
SHOW FULLTEXT INDEXES WHERE name CONTAINS "Team"
结果
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | name            | state    | populationPercent | type       | entityType | labelsOrTypes           | properties       | indexProvider  | owningConstraint | lastRead | readCount |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 5  | "namesAndTeams" | "ONLINE" | 100.0             | "FULLTEXT" | "NODE"     | ["Employee", "Manager"] | ["name", "team"] | "fulltext-1.0" | NULL             | NULL     | 0         |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

要返回完整的索引详细信息,请使用 YIELD 子句。例如

显示所有全文索引和所有返回列
SHOW FULLTEXT INDEXES YIELD *
结果
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | name             | state    | populationPercent | type       | entityType     | labelsOrTypes           | properties       | indexProvider  | owningConstraint | lastRead | readCount | trackedSince             | options                                                                                                 | failureMessage | createStatement                                                                                                                                                                                                   |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 4  | "communications" | "ONLINE" | 100.0             | "FULLTEXT" | "RELATIONSHIP" | ["REVIEWED", "EMAILED"] | ["message"]      | "fulltext-1.0" | NULL             | NULL     | 0         | 2023-11-01T09:27:57.024Z | {indexConfig: {`fulltext.analyzer`: "standard-no-stop-words", `fulltext.eventually_consistent`: FALSE}} | ""             | "CREATE FULLTEXT INDEX `communications` FOR ()-[r:`REVIEWED`|`EMAILED`]-() ON EACH [r.`message`] OPTIONS {indexConfig: {`fulltext.analyzer`: 'standard-no-stop-words',`fulltext.eventually_consistent`: false}}"  |
| 5  | "namesAndTeams"  | "ONLINE" | 100.0             | "FULLTEXT" | "NODE"         | ["Employee", "Manager"] | ["name", "team"] | "fulltext-1.0" | NULL             | NULL     | 0         | 2023-11-01T12:24:48.002Z | {indexConfig: {`fulltext.analyzer`: "standard-no-stop-words", `fulltext.eventually_consistent`: FALSE}} | ""             | "CREATE FULLTEXT INDEX `namesAndTeams` FOR (n:`Employee`|`Manager`) ON EACH [n.`name`, n.`team`] OPTIONS {indexConfig: {`fulltext.analyzer`: 'standard-no-stop-words',`fulltext.eventually_consistent`: false}}"  |
| 6  | "peerReviews"    | "ONLINE" | 100.0             | "FULLTEXT" | "NODE"         | ["Employee", "Manager"] | ["peerReviews"]  | "fulltext-1.0" | NULL             | NULL     | 0         | 2023-11-01T12:25:41.495Z | {indexConfig: {`fulltext.analyzer`: "english", `fulltext.eventually_consistent`: TRUE}}                 | ""             | "CREATE FULLTEXT INDEX `peerReviews` FOR (n:`Employee`|`Manager`) ON EACH [n.`peerReviews`] OPTIONS {indexConfig: {`fulltext.analyzer`: 'english',`fulltext.eventually_consistent`: true}}"                       |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

有关所有返回列的完整描述,请参阅搜索性能索引 → 列出索引的结果列

删除全文索引

全文节点索引通过使用与其他索引相同的命令 DROP INDEX 删除。

在以下示例中,先前创建的 communications 全文索引将从数据库中删除

删除全文索引
DROP INDEX communications

从 Neo4j 5.16 开始,在删除索引时,索引名称也可以作为参数给出:DROP INDEX $name

全文索引过程列表

全文索引的过程列于下表

用法 过程/命令 描述

最终一致索引。

db.index.fulltext.awaitEventuallyConsistentIndexRefresh

等待最近提交的事务更新应用到任何最终一致的全文索引。

列出可用分析器。

db.index.fulltext.listAvailableAnalyzers

列出可用于配置全文索引的可用分析器。

使用全文节点索引。

db.index.fulltext.queryNodes

查询给定的全文索引。返回匹配的节点及其 Lucene 查询分数,按分数排序。

使用全文关系索引。

db.index.fulltext.queryRelationships

查询给定的全文索引。返回匹配的关系及其 Lucene 查询分数,按分数排序。

摘要

  • 全文索引支持节点和关系的索引。

  • 全文索引仅包含 STRINGLIST<STRING> 类型的值。

  • 全文索引通过 Cypher 过程访问。

  • 全文索引返回查询中每个结果的分数

  • 全文索引支持配置自定义分析器,包括 Lucene 本身不包含的分析器。

  • 全文索引可以使用 Lucene 查询语言进行查询。

  • 随着节点和关系的添加、删除和修改,全文索引会自动保持最新。

  • 全文索引将自动用存储中现有数据填充新创建的索引。

  • 全文索引可以通过一致性检查器进行检查,如果存在问题,可以重建它们。

  • 新创建的全文索引会自动填充数据库中的现有数据。

  • 全文索引可以在单个索引中支持任意数量的属性。

  • 全文索引以事务方式创建、删除和更新,并自动在整个集群中复制。

  • 全文索引可以配置为最终一致,其中索引更新从提交路径移动到后台线程。使用此功能,可以解决性能关键的提交过程中 Lucene 写入缓慢的问题,从而消除 Neo4j 写入性能的主要瓶颈。