Amazon Web Services (AWS)

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

每个过程有两种模式

  • Stream - 返回一个由 API 返回的 JSON 构建的映射

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

本章描述的过程在调用线程上进行 API 调用并随后更新数据库。如果我们想并行地向 API 发送请求,并避免在运行向数据库写入数据的过程时,因内存中保留太多事务状态而导致内存不足错误,请参阅 批量请求

过程概述

过程描述如下

限定名称 类型 版本

apoc.nlp.aws.entities.graph

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

过程

Apoc 扩展

apoc.nlp.aws.entities.stream

返回提供的文本的实体流

过程

Apoc 扩展

apoc.nlp.aws.keyPhrases.graph

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

过程

Apoc 扩展

apoc.nlp.aws.keyPhrases.stream

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

过程

Apoc 扩展

apoc.nlp.aws.sentiment.graph

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

过程

Apoc 扩展

apoc.nlp.aws.sentiment.stream

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

过程

Apoc 扩展

目前,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. 配置参数
名称 类型 默认值 描述

key

String

null

AWS 访问控制密钥

secret

String

null

AWS 访问控制密匙

nodeProperty

String

text

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

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

表 2. 配置参数
名称 类型 默认值 描述

scoreCutoff

Double

0.0

实体在图中显示的最小分数限制。值必须介于 0 和 1 之间。

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

write

Boolean

false

持久化实体图

writeRelationshipType

String

ENTITY

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

writeRelationshipProperty

String

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. 配置参数
名称 类型 默认值 描述

key

String

null

AWS 访问控制密钥

secret

String

null

AWS 访问控制密匙

nodeProperty

String

text

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

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

表 4. 配置参数
名称 类型 默认值 描述

scoreCutoff

Double

0.0

实体在图中显示的最小分数限制。值必须介于 0 和 1 之间。

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

write

Boolean

false

持久化关键短语图

writeRelationshipType

String

KEY_PHRASE

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

writeRelationshipProperty

String

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. 配置参数
名称 类型 默认值 描述

key

String

null

AWS 访问控制密钥

secret

String

null

AWS 访问控制密匙

nodeProperty

String

text

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

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

表 6. 配置参数
名称 类型 默认值 描述

write

Boolean

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 扩展库中。

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

设置 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 密钥>", apiSecret: "<此处为 api 密匙>"}

批量请求

可以使用 Periodic Iterate 对 AWS API 的请求和结果的处理进行批量操作。如果要并行地向 AWS API 发送请求,并减少在运行向数据库写入数据的过程时内存中保留的事务状态量,此方法非常有用。

AWS Comprehend API 在一个请求中最多处理 25 个文档,因此为获得最佳性能,我们应传入其大小为 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: "https://neo4j.ac.cn/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: "https://neo4j.ac.cn/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: "https://neo4j.ac.cn/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: "https://neo4j.ac.cn/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 属性指定分数的最小截止值。

以下返回分数 >= 0.7 的 Pokemon 和 Nintendo Switch 文章的虚拟实体图
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

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

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

如果我们对此图满意并希望将其持久化到 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

"https://neo4j.ac.cn/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: "https://neo4j.ac.cn/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: "https://neo4j.ac.cn/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: "https://neo4j.ac.cn/blog/pokegraph-gotta-graph-em-all/"})
RETURN a.uri AS article,
       [(a)-[:KEY_PHRASE]->(k:KeyPhrase) | k.text] AS keyPhrases;
表 11. 结果
article keyPhrases

"https://neo4j.ac.cn/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: "https://neo4j.ac.cn/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.aws.sentiment.stream(a, {
  key: $apiKey,
  secret: $apiSecret,
  nodeProperty: "body"
})
YIELD value
RETURN value;
表 12. 结果
value

{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: "https://neo4j.ac.cn/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. 结果
node

{sentiment: "Positive", sentimentScore: 0.6660025119781494, uri: "https://neo4j.ac.cn/blog/pokegraph-gotta-graph-em-all/"}

© . All rights reserved.