亚马逊 Web 服务 (AWS)

Amazon Web Services (AWS) Comprehend 自然语言 API 使用机器学习来挖掘文本中的见解和关系。本章中的过程是对调用此 API 的封装,用于从存储在节点属性中的文本中提取实体和关键短语。

每个过程有两种模式

  • Stream(流模式) - 返回由 API 返回的 JSON 构建的映射(map)

  • Graph(图模式) - 根据 API 返回的值创建图或虚拟图

本章中描述的过程会在调用线程上进行 API 调用并随后更新数据库。如果我们希望并行请求 API,并避免在运行写入数据库的过程时因在内存中保留过多事务状态而导致的内存溢出错误,请参阅 批处理请求

过程概述

过程描述如下

限定名称 类型 版本

apoc.nlp.aws.entities.graph

为提供的文本创建(虚拟)实体图

过程

Apoc Extended

apoc.nlp.aws.entities.stream

返回提供的文本的实体流

过程

Apoc Extended

apoc.nlp.aws.keyPhrases.graph

为提供的文本创建(虚拟)关键短语图

过程

Apoc Extended

apoc.nlp.aws.keyPhrases.stream

返回提供的文本的关键短语流

过程

Apoc Extended

apoc.nlp.aws.sentiment.graph

为提供的文本创建(虚拟)情感图

过程

Apoc Extended

apoc.nlp.aws.sentiment.stream

返回提供的文本中项的情感流

过程

Apoc Extended

目前,Amazon Comprehend API 支持超过 10 种语言的文本输入。为了获得更好的结果,请确保您的文本属于 Amazon Comprehend 支持的语言

实体提取

实体提取过程 (apoc.nlp.aws.entities.*) 是对 AWS Comprehend 自然语言 API 的 检测实体 操作的封装。此 API 方法在文本中查找实体,这些实体定义为对现实世界对象(如人、地点和商业物品)的唯一名称的文本引用,以及对测量值(如日期和数量)的精确引用。

过程描述如下

签名

apoc.nlp.aws.entities.stream(source :: ANY?, config = {} :: MAP?) :: (node :: NODE?, value :: MAP?, error :: MAP?)

apoc.nlp.aws.entities.graph(source :: ANY?, config = {} :: MAP?) :: (graph :: MAP?)

该过程支持以下配置参数

表 1. 配置参数
名称 (name) type 默认 description(描述)

键 (key)

字符串

null

AWS 访问控制密钥 (Access Control Key)

密钥 (secret)

字符串

null

AWS 访问控制密码 (Access Control Secret)

nodeProperty

字符串

文本 (text)

提供的节点上包含待分析非结构化文本的属性

此外,apoc.nlp.aws.entities.graph 支持以下配置参数

表 2. 配置参数
名称 (name) type 默认 description(描述)

scoreCutoff

双精度浮点数

0.0

实体出现在图中的得分下限。值必须在 0 到 1 之间。

得分是 Amazon Comprehend 对检测准确性的置信度指标。

write

布尔值

false

持久化实体图

writeRelationshipType

字符串

ENTITY

从源节点到实体节点的关系类型

writeRelationshipProperty

字符串

score

从源节点到实体节点的关系属性

流模式
CALL apoc.nlp.aws.entities.stream(source:Node or List<Node>, {
  key: String,
  secret: String,
  nodeProperty: String
})
YIELD value
图模式
CALL apoc.nlp.aws.entities.graph(source:Node or List<Node>, {
  key: String,
  secret: String,
  nodeProperty: String,
  scoreCutoff: Double,
  writeRelationshipType: String,
  writeRelationshipProperty: String,
  write: Boolean
})
YIELD graph

关键短语

关键短语过程 (apoc.nlp.aws.keyPhrases.*) 是对 AWS Comprehend 自然语言 API 的 检测关键短语 操作的封装。关键短语是包含描述特定事物的名词短语的字符串。它通常由一个名词和区分它的修饰语组成。

过程描述如下

签名

apoc.nlp.aws.keyPhrases.stream(source :: ANY?, config = {} :: MAP?) :: (node :: NODE?, value :: MAP?, error :: MAP?)

apoc.nlp.aws.keyPhrases.graph(source :: ANY?, config = {} :: MAP?) :: (graph :: MAP?)

该过程支持以下配置参数

表 3. 配置参数
名称 (name) type 默认 description(描述)

键 (key)

字符串

null

AWS 访问控制密钥 (Access Control Key)

密钥 (secret)

字符串

null

AWS 访问控制密码 (Access Control Secret)

nodeProperty

字符串

文本 (text)

提供的节点上包含待分析非结构化文本的属性

此外,apoc.nlp.aws.keyPhrases.graph 支持以下配置参数

表 4. 配置参数
名称 (name) type 默认 description(描述)

scoreCutoff

双精度浮点数

0.0

实体出现在图中的得分下限。值必须在 0 到 1 之间。

得分是 Amazon Comprehend 对检测准确性的置信度指标。

write

布尔值

false

持久化关键短语图

writeRelationshipType

字符串

KEY_PHRASE

从源节点到关键短语节点的关系类型

writeRelationshipProperty

字符串

score

从源节点到关键短语节点的关系属性

流模式
CALL apoc.nlp.aws.keyPhrases.stream(source:Node or List<Node>, {
  key: String,
  secret: String,
  nodeProperty: String
})
YIELD value
图模式
CALL apoc.nlp.aws.keyPhrases.graph(source:Node or List<Node>, {
  key: String,
  secret: String,
  nodeProperty: String,
  scoreCutoff: Double,
  writeRelationshipType: String,
  writeRelationshipProperty: String,
  write: Boolean
})
YIELD graph

情感分析

情感分析过程 (apoc.nlp.aws.sentiment.*) 是对 AWS Comprehend 自然语言 API 的 确定情感 操作的封装。您可以确定情感是积极、消极、中性还是混合的。

过程描述如下

签名

apoc.nlp.aws.sentiment.stream(source :: ANY?, config = {} :: MAP?) :: (node :: NODE?, value :: MAP?, error :: MAP?)

apoc.nlp.aws.sentiment.graph(source :: ANY?, config = {} :: MAP?) :: (graph :: MAP?)

该过程支持以下配置参数

表 5. 配置参数
名称 (name) type 默认 description(描述)

键 (key)

字符串

null

AWS 访问控制密钥 (Access Control Key)

密钥 (secret)

字符串

null

AWS 访问控制密码 (Access Control Secret)

nodeProperty

字符串

文本 (text)

提供的节点上包含待分析非结构化文本的属性

此外,apoc.nlp.aws.sentiment.graph 支持以下配置参数

表 6. 配置参数
名称 (name) type 默认 description(描述)

write

布尔值

false

持久化情感图

流模式
CALL apoc.nlp.aws.sentiment.stream(source:Node or List<Node>, {
  key: String,
  secret: String,
  nodeProperty: String
})
YIELD value
图模式
CALL apoc.nlp.aws.sentiment.graph(source:Node or List<Node>, {
  key: String,
  secret: String,
  nodeProperty: String,
  writeRelationshipType: String,
  write: Boolean
})
YIELD graph

安装依赖项

NLP 过程依赖于 Kotlin 和客户端库,这些库未包含在 APOC Extended 库中。

这些依赖项包含在 apoc-nlp-dependencies-2025.10.0-all.jar 中,可从 发布页面 下载。下载该文件后,应将其放入 plugins 目录并重启 Neo4j 服务器。

设置 API 密钥和密码

我们可以按照 docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html 上的说明生成访问密钥和密码。完成后,我们可以填充并执行以下命令来创建包含这些详细信息的参数。

以下定义了 apiKeyapiSecret 参数
:param apiKey => ("<api-key-here>");
:param apiSecret => ("<api-secret-here>");

或者,我们可以将这些凭据添加到 apoc.conf 中,并使用静态值存储函数检索它们。请参阅 静态值存储

apoc.conf
apoc.static.aws.apiKey=<api-key-here>
apoc.static.aws.apiSecret=<api-secret-here>
以下从 apoc.conf 中检索 AWS 凭据
RETURN apoc.static.getAll("aws") AS aws;
表 7. 结果
aws

{apiKey: "<api-key-here>", apiSecret: "<api-secret-here>"}

批处理请求

可以使用 Periodic Iterate 对 AWS API 的请求和结果处理进行批处理。如果我们希望并行向 AWS API 发出请求,并减少在运行写入数据库的过程时保存在内存中的事务状态量,这种方法非常有用。

AWS Comprehend API 在一个请求中最多处理 25 个文档,因此为了获得最佳性能,我们应该传入该大小倍数的列表。请记住,如果我们传入过大的列表,在写入数据库时会导致更多的事务状态,并可能导致内存溢出异常。

以下创建 25 个节点为一批的实体图
CALL apoc.periodic.iterate("
  MATCH (n)
  WITH collect(n) as total
  CALL apoc.coll.partition(total, 25)
  YIELD value as nodes
  RETURN nodes", "
  CALL apoc.nlp.aws.entities.graph(nodes, {
    key: $apiKey,
    secret: $apiSecret,
    nodeProperty: 'body',
    writeRelationshipType: 'AWS_ENTITY',
    write:true
  })
  YIELD graph
  RETURN distinct 'done'", {
    batchSize: 1,
    params: { apiKey: $apiKey, apiSecret: $apiSecret }
  }
);

示例

本节中的示例基于以下示例图

CREATE (:Article {
  uri: "/blog/pokegraph-gotta-graph-em-all/",
  body: "These days I’m rarely more than a few feet away from my Nintendo Switch and I play board games, card games and role playing games with friends at least once or twice a week. I’ve even organised lunch-time Mario Kart 8 tournaments between the Neo4j European offices!"
});

CREATE (:Article {
  uri: "https://en.wikipedia.org/wiki/Nintendo_Switch",
  body: "The Nintendo Switch is a video game console developed by Nintendo, released worldwide in most regions on March 3, 2017. It is a hybrid console that can be used as a home console and portable device. The Nintendo Switch was unveiled on October 20, 2016. Nintendo offers a Joy-Con Wheel, a small steering wheel-like unit that a Joy-Con can slot into, allowing it to be used for racing games such as Mario Kart 8."
});

实体提取

让我们从从 Article 节点提取实体开始。我们要分析的文本存储在节点的 body 属性中,因此我们需要通过 nodeProperty 配置参数指定它。

以下流式输出 Pokemon 文章的实体
MATCH (a:Article {uri: "/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.aws.entities.stream(a, {
  key: $apiKey,
  secret: $apiSecret,
  nodeProperty: "body"
})
YIELD value
UNWIND value.entities AS entity
RETURN entity;
表 8. 结果
实体 (entity)

{score: 0.780032217502594, endOffset: 71, text: "Nintendo Switch", type: "COMMERCIAL_ITEM", beginOffset: 56}

{score: 0.8155304193496704, endOffset: 151, text: "at least", type: "QUANTITY", beginOffset: 143}

{score: 0.7507548332214355, endOffset: 156, text: "once", type: "QUANTITY", beginOffset: 152}

{score: 0.8760746717453003, endOffset: 172, text: "twice a week", type: "QUANTITY", beginOffset: 160}

{score: 0.9944096803665161, endOffset: 217, text: "Mario Kart 8", type: "TITLE", beginOffset: 205}

{score: 0.9946564435958862, endOffset: 247, text: "Neo4j", type: "ORGANIZATION", beginOffset: 242}

{score: 0.6274040937423706, endOffset: 256, text: "European", type: "LOCATION", beginOffset: 248}

我们获得了 7 个不同的实体。然后,我们可以应用一条 Cypher 语句,为每个实体创建一个节点,并从这些节点中的每一个创建一条回到 Article 节点的 ENTITY 关系。

以下流式输出 Pokemon 文章的实体,并为每个实体创建节点
MATCH (a:Article {uri: "/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.aws.entities.stream(a, {
  key: $apiKey,
  secret: $apiSecret,
  nodeProperty: "body"
})
YIELD value
UNWIND value.entities AS entity
MERGE (e:Entity {name: entity.text})
SET e.type = entity.type
MERGE (a)-[:ENTITY]->(e)

或者,我们可以使用图模式自动创建实体图。除了拥有 Entity 标签外,每个实体节点还会根据 type 属性的值拥有另一个标签。默认情况下,返回一个虚拟图。

以下返回 Pokemon 文章的实体虚拟图
MATCH (a:Article {uri: "/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.aws.entities.graph(a, {
  key: $apiKey,
  secret: $apiSecret,
  nodeProperty: "body",
  writeRelationshipType: "ENTITY"
})
YIELD graph AS g
RETURN g;

我们可以在 Pokemon 实体图 中查看该虚拟图的 Neo4j Browser 可视化。

apoc.nlp.aws.entities.graph
图 1. Pokemon 实体图

我们可以通过将节点列表传递给该过程,来为多个节点计算实体。

以下返回 Pokemon 和 Nintendo Switch 文章的实体虚拟图
MATCH (a:Article)
WITH collect(a) AS articles
CALL apoc.nlp.aws.entities.graph(articles, {
  key: $apiKey,
  secret: $apiSecret,
  nodeProperty: "body",
  writeRelationshipType: "ENTITY"
})
YIELD graph AS g
RETURN g

我们可以在 Pokemon 和 Nintendo Switch 实体图 中查看该虚拟图的 Neo4j Browser 可视化。

apoc.nlp.aws.entities multiple.graph
图 2. Pokemon 和 Nintendo Switch 实体图

在此可视化中,我们还可以看到每个实体节点的得分。此得分代表 API 对其检测该实体的置信度。我们可以使用 scoreCutoff 属性为得分指定最低截止值。

以下返回 Pokemon 和 Nintendo Switch 文章得分 >= 0.7 的实体虚拟图
MATCH (a:Article)
WITH collect(a) AS articles
CALL apoc.nlp.aws.entities.graph(articles, {
  key: $apiKey,
  secret: $apiSecret,
  nodeProperty: "body",
  scoreCutoff: 0.7,
  writeRelationshipType: "ENTITY"
})
YIELD graph AS g
RETURN g

我们可以在 置信度 >= 0.7 的 Pokemon 和 Nintendo Switch 实体图 中查看该虚拟图的 Neo4j Browser 可视化。

apoc.nlp.aws.entities multiple.graph cutoff
图 3. 置信度 >= 0.7 的 Pokemon 和 Nintendo Switch 实体图

如果我们对这个图感到满意并希望将其持久化到 Neo4j 中,可以通过指定 write: true 配置来实现。

以下创建从文章到每个实体的 HAS_ENTITY 关系
MATCH (a:Article)
WITH collect(a) AS articles
CALL apoc.nlp.aws.entities.graph(articles, {
  key: $apiKey,
  secret: $apiSecret,
  nodeProperty: "body",
  scoreCutoff: 0.7,
  writeRelationshipType: "HAS_ENTITY",
  writeRelationshipProperty: "awsEntityScore",
  write: true
})
YIELD graph AS g
RETURN g;

然后,我们可以编写一个查询来返回已创建的实体。

以下返回文章及其对应的实体
MATCH (article:Article)
RETURN article.uri AS article,
       [(article)-[r:HAS_ENTITY]->(e:Entity) | {text: e.text, score: r.awsEntityScore}] AS entities;
表 9. 结果
article entities

"/blog/pokegraph-gotta-graph-em-all/"

[{score: 0.9944096803665161, text: "Mario Kart 8"}, {score: 0.8760746717453003, text: "twice a week"}, {score: 0.9946564435958862, text: "Neo4j"}, {score: 0.7507548332214355, text: "once"}, {score: 0.8155304193496704, text: "at least"}, {score: 0.780032217502594, text: "Nintendo Switch"}]

"https://en.wikipedia.org/wiki/Nintendo_Switch"

[{score: 0.9990180134773254, text: "Mario Kart 8"}, {score: 0.9997879862785339, text: "March 3, 2017"}, {score: 0.9958534240722656, text: "Nintendo"}, {score: 0.9998348355293274, text: "October 20, 2016"}, {score: 0.753325343132019, text: "Nintendo Switch"}]

关键短语

现在让我们从 Article 节点中提取关键短语。我们要分析的文本存储在节点的 body 属性中,因此我们需要通过 nodeProperty 配置参数指定它。

以下流式输出 Pokemon 文章的关键短语
MATCH (a:Article {uri: "/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.aws.keyPhrases.stream(a, {
  key: $apiKey,
  secret: $apiSecret,
  nodeProperty: "body"
})
YIELD value
UNWIND value.keyPhrases AS keyPhrase
RETURN keyPhrase;
表 10. 结果
keyPhrase

{score: 0.9999966621398926, endOffset: 10, text: "These days", beginOffset: 0}

{score: 0.9867414236068726, endOffset: 42, text: "more than a few feet", beginOffset: 22}

{score: 0.9999999403953552, endOffset: 71, text: "my Nintendo Switch", beginOffset: 53}

{score: 0.9999997019767761, endOffset: 94, text: "board games", beginOffset: 83}

{score: 0.9999964237213135, endOffset: 106, text: "card games", beginOffset: 96}

{score: 0.9998161792755127, endOffset: 129, text: "role playing games", beginOffset: 111}

{score: 1.0, endOffset: 142, text: "friends", beginOffset: 135}

{score: 0.8642383217811584, endOffset: 172, text: "a week", beginOffset: 166}

{score: 0.9999430179595947, endOffset: 215, text: "lunch-time Mario Kart", beginOffset: 194}

{score: 0.9983567595481873, endOffset: 229, text: "8 tournaments", beginOffset: 216}

{score: 0.999997615814209, endOffset: 264, text: "the Neo4j European offices", beginOffset: 238}

或者,我们可以使用图模式自动创建关键短语图。为提取的每个关键短语创建一个带有 KeyPhrase 标签的节点。

默认情况下,返回一个虚拟图,但可以通过指定 write: true 配置来持久化该图。

以下返回 Pokemon 文章的关键短语图
MATCH (a:Article {uri: "/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.aws.keyPhrases.graph(a, {
  key: $apiKey,
  secret: $apiSecret,
  nodeProperty: "body",
  writeRelationshipType: "KEY_PHRASE",
  write: true
})
YIELD graph AS g
RETURN g;

我们可以在 Pokemon 关键短语图 中查看该虚拟图的 Neo4j Browser 可视化。

apoc.nlp.aws.keyPhrases.graph
图 4. Pokemon 关键短语图

然后,我们可以编写一个查询来返回已创建的关键短语。

以下返回文章及其对应的实体
MATCH (a:Article {uri: "/blog/pokegraph-gotta-graph-em-all/"})
RETURN a.uri AS article,
       [(a)-[:KEY_PHRASE]->(k:KeyPhrase) | k.text] AS keyPhrases;
表 11. 结果
article keyPhrases

"/blog/pokegraph-gotta-graph-em-all/"

["the Neo4j European offices", "a week", "friends", "8 tournaments", "lunch-time Mario Kart", "card games", "board games", "role playing games", "my Nintendo Switch", "more than a few feet", "These days"]

情感分析

现在让我们从 Article 节点中提取情感分析。我们要分析的文本存储在节点的 body 属性中,因此我们需要通过 nodeProperty 配置参数指定它。

以下流式输出 Pokemon 文章的关键短语
MATCH (a:Article {uri: "/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.aws.sentiment.stream(a, {
  key: $apiKey,
  secret: $apiSecret,
  nodeProperty: "body"
})
YIELD value
RETURN value;
表 12. 结果

{index: 0, sentiment: "POSITIVE", sentimentScore: {neutral: 0.33138760924339294, negative: 0.0026062370743602514, mixed: 3.5950531582784606E-6, positive: 0.6660025119781494}}

或者,我们可以使用图模式自动存储情感及其得分。

默认情况下,返回一个虚拟图,但可以通过指定 write: true 配置来持久化该图。情感存储在 sentiment 属性中,该情感的得分存储在 sentimentScore 属性中。

以下返回包含 Pokemon 文章情感的图
MATCH (a:Article {uri: "/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.aws.sentiment.graph(a, {
  key: $apiKey,
  secret: $apiSecret,
  nodeProperty: "body",
  write: true
})
YIELD graph AS g
UNWIND g.nodes AS node
RETURN node {.uri, .sentiment, .sentimentScore} AS node;
表 13. 结果
节点

{sentiment: "Positive", sentimentScore: 0.6660025119781494, uri: "/blog/pokegraph-gotta-graph-em-all/"}

© . This site is unofficial and not affiliated with Neo4j, Inc.