Google Cloud Platform (GCP)

Google Cloud Platform 的 Natural Language API 允许用户使用 Google 机器学习从未结构化文本中获取洞察。本章中的过程充当此 API 调用的封装器,用于从存储为节点属性的文本中提取实体、类别或情感。

每个过程有两种模式

  • 流模式 (Stream) - 返回一个根据 API 返回的 JSON 构建的映射

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

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

目前,GCP Natural Language API 支持 10 多种语言的文本输入。为了获得更好的结果,请确保您的文本是 Natural Language API 支持的语言 之一。如果输入不支持语言的文本,可能会收到“HTTP response code: 400”错误。

过程概览

过程描述如下

限定名称 类型 发布

apoc.nlp.gcp.entities.graph

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

过程

Apoc Extended

apoc.nlp.gcp.entities.stream

为提供的文本返回实体流

过程

Apoc Extended

apoc.nlp.gcp.classify.graph

将文档分类到类别中。

过程

Apoc Extended

apoc.nlp.gcp.classify.stream

将文档分类到类别中。

过程

Apoc Extended

实体提取

实体提取过程 (apoc.nlp.gcp.entities.*) 是 Google Natural Language API 的 documents.analyzeEntities 方法的封装器。此 API 方法在文本中查找命名实体(当前包括专有名词和普通名词),以及实体类型、显著性、每个实体的提及及其他属性。

过程描述如下

签名

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

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

过程支持以下配置参数

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

key

String

null

Google Natural Language API 的 API Key

nodeProperty

String

text

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

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

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

scoreCutoff

Double

0.0

实体出现在图中的显著性得分下限。值必须介于 0 和 1 之间。

显著性表示该实体对于整个文档文本的重要程度或中心性。得分越接近 0 显著性越低,得分越接近 1.0 显著性越高。

write

Boolean

false

持久化实体图

writeRelationshipType

String

ENTITY

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

writeRelationshipProperty

String

score

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

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

分类

实体提取过程 (apoc.nlp.gcp.classify.*) 是 Google Natural Language API 的 documents.classifyText 方法的封装器。此 API 方法将文档分类到类别中。

过程描述如下

签名

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

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

过程支持以下配置参数

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

key

String

null

Google Natural Language API 的 API Key

nodeProperty

String

text

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

此外,apoc.nlp.gcp.classify.graph 支持以下配置参数

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

scoreCutoff

Double

0.0

类别出现在图中的置信度得分下限。值必须介于 0 和 1 之间。

置信度是一个数字,表示分类器对该类别代表给定文本的确定程度。

write

Boolean

false

持久化实体图

writeRelationshipType

String

CATEGORY

从源节点到类别节点的关系类型

writeRelationshipProperty

String

score

从源节点到类别节点的关系属性

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

安装依赖

NLP 过程依赖于 APOC Extended 库中未包含的 Kotlin 和客户端库。

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

设置 API Key

可以通过访问 console.cloud.google.com/apis/credentials 生成有权访问 Cloud Natural Language API 的 API Key。创建 Key 后,可以填充并执行以下命令来创建包含这些详细信息的参数。

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

或者,可以将这些凭据添加到 apoc.conf 并使用静态值存储函数加载它们。

apoc.conf
apoc.static.gcp.apiKey=<api-key-here>
以下从 apoc.conf 中检索 GCP 凭据
RETURN apoc.static.getAll("gcp") AS gcp;
表 5. 结果
gcp

{apiKey: "<api-key-here>"}

批量请求

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

以下以 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.gcp.entities.graph(nodes, {
    key: $apiKey,
    nodeProperty: 'body',
    writeRelationshipType: 'GCP_ENTITY',
    write:true
  })
  YIELD graph
  RETURN distinct 'done'", {
    batchSize: 1,
    params: { apiKey: $apiKey }
  }
);

示例

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

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.gcp.entities.stream(a, {
  key: $apiKey,
  nodeProperty: "body"
})
YIELD value
UNWIND value.entities AS entity
RETURN entity;
表 6. 结果
实体

{name: "纸牌游戏", salience: 0.17967656, metadata: {}, type: "CONSUMER_GOOD", mentions: [{type: "COMMON", text: {content: "纸牌游戏", beginOffset: -1}}]}

{name: "角色扮演游戏", salience: 0.16441391, metadata: {}, type: "OTHER", mentions: [{type: "COMMON", text: {content: "角色扮演游戏", beginOffset: -1}}]}

{name: "Switch", salience: 0.143287, metadata: {}, type: "OTHER", mentions: [{type: "COMMON", text: {content: "Switch", beginOffset: -1}}]}

{name: "朋友", salience: 0.13336793, metadata: {}, type: "PERSON", mentions: [{type: "COMMON", text: {content: "朋友", beginOffset: -1}}]}

{name: "任天堂", salience: 0.12601112, metadata: {mid: "/g/1ymzszlpz"}, type: "ORGANIZATION", mentions: [{type: "PROPER", text: {content: "任天堂", beginOffset: -1}}]}

{name: "棋盘游戏", salience: 0.08861496, metadata: {}, type: "CONSUMER_GOOD", mentions: [{type: "COMMON", text: {content: "棋盘游戏", beginOffset: -1}}]}

{name: "锦标赛", salience: 0.0603245, metadata: {}, type: "EVENT", mentions: [{type: "COMMON", text: {content: "锦标赛", beginOffset: -1}}]}

{name: "办公室", salience: 0.034420907, metadata: {}, type: "LOCATION", mentions: [{type: "COMMON", text: {content: "办公室", beginOffset: -1}}]}

{name: "马力欧卡丁车 8", salience: 0.029095741, metadata: {wikipedia_url: "https://en.wikipedia.org/wiki/Mario_Kart_8", mid: "/m/0119mf7q"}, type: "PERSON", mentions: [{type: "PROPER", text: {content: "马力欧卡丁车 8", beginOffset: -1}}]}

{name: "欧洲", salience: 0.020393685, metadata: {mid: "/m/02j9z", wikipedia_url: "https://en.wikipedia.org/wiki/Europe"}, type: "LOCATION", mentions: [{type: "PROPER", text: {content: "欧洲", beginOffset: -1}}]}

{name: "Neo4j", salience: 0.020393685, metadata: {mid: "/m/0b76t3s", wikipedia_url: "https://en.wikipedia.org/wiki/Neo4j"}, type: "ORGANIZATION", mentions: [{type: "PROPER", text: {content: "Neo4j", beginOffset: -1}}]}

{name: "8", salience: 0, metadata: {value: "8"}, type: "NUMBER", mentions: [{type: "TYPE_UNKNOWN", text: {content: "8", beginOffset: -1}}]}

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

以下流式传输 Pokemon 文章的实体,然后为每个实体创建节点
MATCH (a:Article {uri: "https://neo4j.ac.cn/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.gcp.entities.stream(a, {
  key: $apiKey,
  nodeProperty: "body"
})
YIELD value
UNWIND value.entities AS entity
MERGE (e:Entity {name: entity.name})
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.gcp.entities.graph(a, {
  key: $apiKey,
  nodeProperty: "body",
  writeRelationshipType: "ENTITY"
})
YIELD graph AS g
RETURN g;

可以在 Pokemon 实体图 中查看实体虚拟图的 Neo4j Browser 可视化效果。

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

通过将节点列表传递给过程,可以计算多个节点的实体。

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

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

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

在此可视化中,还可以看到每个实体节点的得分。此得分表示该实体在整个文档中的重要程度。可以使用 scoreCutoff 属性指定得分的最小截止值。

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

可以在 Pokemon 和 Nintendo Switch 实体图,重要性 >= 0.01 中查看实体虚拟图的 Neo4j Browser 可视化效果。

apoc.nlp.gcp.entities multiple.graph cutoff
图 3. Pokemon 和 Nintendo Switch 实体图,重要性 >= 0.01

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

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

然后可以编写查询以返回已创建的实体。

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

"https://neo4j.ac.cn/blog/pokegraph-gotta-graph-em-all/"

[{score: 0.020393685, entity: "Neo4j"}, {score: 0.034420907, entity: "办公室"}, {score: 0.0603245, entity: "锦标赛"}, {score: 0.020393685, entity: "欧洲"}, {score: 0.029095741, entity: "马力欧卡丁车 8"}, {score: 0.12601112, entity: "任天堂"}, {score: 0.13336793, entity: "朋友"}, {score: 0.08861496, entity: "棋盘游戏"}, {score: 0.143287, entity: "Switch"}, {score: 0.16441391, entity: "角色扮演游戏"}, {score: 0.17967656, entity: "纸牌游戏"}]

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

[{score: 0.76108575, entity: "Nintendo Switch"}, {score: 0.07424594, entity: "任天堂"}, {score: 0.015900765, entity: "家用游戏机"}, {score: 0.012772448, entity: "设备"}, {score: 0.038113687, entity: "地区"}, {score: 0.07299799, entity: "Joy-Con 方向盘"}]

分类

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

以下流式传输 Pokemon 文章的类别
MATCH (a:Article {uri: "https://neo4j.ac.cn/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.gcp.classify.stream(a, {
  key: $apiKey,
  nodeProperty: "body"
})
YIELD value
UNWIND value.categories AS category
RETURN category;
表 8. 结果
类别

{name: "/Games", confidence: 0.91}

我们只获得一个类别。然后可以应用 Cypher 语句,为每个类别创建一个节点,并从每个类别节点到 Article 节点创建 CATEGORY 关系。

以下流式传输 Pokemon 文章的类别,然后为每个类别创建节点
MATCH (a:Article {uri: "https://neo4j.ac.cn/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.gcp.classify.stream(a, {
  key: $apiKey,
  nodeProperty: "body"
})
YIELD value
UNWIND value.categories AS category
MERGE (c:Category {name: category.name})
MERGE (a)-[:CATEGORY]->(c)

或者,可以使用图模式自动创建类别图。除了具有 Category 标签外,每个类别节点还将根据 type 属性的值拥有另一个标签。默认返回一个虚拟图。

以下返回 Pokemon 文章的类别虚拟图
MATCH (a:Article {uri: "https://neo4j.ac.cn/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.gcp.classify.graph(a, {
  key: $apiKey,
  nodeProperty: "body",
  writeRelationshipType: "CATEGORY"
})
YIELD graph AS g
RETURN g;

可以在 Pokemon 类别图 中查看类别虚拟图的 Neo4j Browser 可视化效果。

apoc.nlp.gcp.classify.graph
图 4. Pokemon 类别图
以下创建从文章到每个类别的 HAS_CATEGORY 关系
MATCH (a:Article)
WITH collect(a) AS articles
CALL apoc.nlp.gcp.classify.graph(articles, {
  key: $apiKey,
  nodeProperty: "body",
  writeRelationshipType: "HAS_CATEGORY",
  writeRelationshipProperty: "gcpCategoryScore",
  write: true
})
YIELD graph AS g
RETURN g;

然后可以编写查询以返回已创建的实体。

以下返回文章及其实体
MATCH (article:Article)
RETURN article.uri AS article,
       [(article)-[r:HAS_CATEGORY]->(c) | {category: c.text, score: r.gcpCategoryScore}] AS categories;
表 9. 结果
文章 类别

"https://neo4j.ac.cn/blog/pokegraph-gotta-graph-em-all/"

[{category: "/Games", score: 0.91}]

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

[{category: "/Computers & Electronics/Consumer Electronics/Game Systems & Consoles", score: 0.99}, {category: "/Games/Computer & Video Games", score: 0.99}]

© . All rights reserved.