Amazon Web Services (AWS)

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

每个过程都有两种模式

  • 流 - 返回从 API 返回的 JSON 构建的映射

  • 图 - 基于 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.*)是围绕 Detect 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

字符串

AWS 访问控制密钥

secret

字符串

AWS 访问控制密钥

nodeProperty

字符串

text

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

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

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

scoreCutoff

双精度

0.0

实体在图中存在的评分下限。值必须介于 0 和 1 之间。

评分是 Amazon Comprehend 对检测准确性的置信水平的指标。

write

布尔值

false

持久化实体图

writeRelationshipType

字符串

实体

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

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.*)是围绕 Detect Key Phrases 的 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

字符串

AWS 访问控制密钥

secret

字符串

AWS 访问控制密钥

nodeProperty

字符串

text

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

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

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

scoreCutoff

双精度

0.0

实体在图中存在的评分下限。值必须介于 0 和 1 之间。

评分是 Amazon Comprehend 对检测准确性的置信水平的指标。

write

布尔值

false

持久化关键短语图

writeRelationshipType

字符串

关键短语

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

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.*)是围绕 Determine 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

字符串

AWS 访问控制密钥

secret

字符串

AWS 访问控制密钥

nodeProperty

字符串

text

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

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

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

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-5.21.0-all.jar 中,可以从 releases page 下载。下载该文件后,应将其放置在 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 中,并使用静态值存储函数检索它们。请参阅 Static Value Storage

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>"}

批处理请求

对 AWS API 的批处理请求和结果的处理可以使用 Periodic Iterate 完成。如果我们想对 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: "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 entities graph 中看到虚拟图的 Neo4j 浏览器可视化。

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 and Nintendo Switch entities graph 中看到虚拟图的 Neo4j 浏览器可视化。

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

我们可以在 Pokemon and Nintendo Switch entities graph with confidence >= 0.7 中看到虚拟图的 Neo4j 浏览器可视化。

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 key phrases graph 中看到虚拟图的 Neo4j 浏览器可视化。

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"]

情感

现在让我们提取文章节点的情感。我们要分析的文本存储在节点的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. 结果

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

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

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

以下返回带有神奇宝贝文章情感的图。
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. 结果
节点

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