Microsoft Azure 认知服务

Microsoft Azure 认知服务 API 使用机器学习来查找文本中的见解和关系。本章中的过程充当对该 API 调用的包装器,以从存储为节点属性的文本中提取实体和关键词,并提供情感分析。

每个过程都有两种模式

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

过程概述

下面描述了这些过程

限定名称 类型 发布

apoc.nlp.azure.entities.graph

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

过程

Apoc 扩展

apoc.nlp.azure.entities.stream

为提供的文本提供实体分析

过程

Apoc 扩展

apoc.nlp.azure.keyPhrases.graph

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

过程

Apoc 扩展

apoc.nlp.azure.keyPhrases.stream

为提供的文本提供实体分析

过程

Apoc 扩展

apoc.nlp.azure.sentiment.graph

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

过程

Apoc 扩展

apoc.nlp.azure.sentiment.stream

为提供的文本提供情感分析

过程

Apoc 扩展

目前,Microsoft Azure 认知服务 API 支持十多种语言的文本输入。为了获得最佳效果,请确保您的文本是 认知服务支持的语言之一.

实体提取

实体提取过程 (apoc.nlp.azure.entities.*) 是 Azure 文本分析 API 的 实体 终结点的包装器。此 API 方法返回给定文档中已知实体和一般命名实体(“人物”、“位置”、“组织”等)的列表。

下面描述了这些过程

签名

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

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

此过程支持以下配置参数

表 1. 配置参数
名称 类型 默认值 说明

key

字符串

Microsoft.CognitiveServicesTextAnalytics API 密钥

url

字符串

Microsoft.CognitiveServicesTextAnalytics 端点

nodeProperty

字符串

text

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

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

表 2. 配置参数
名称 类型 默认值 说明

scoreCutoff

双精度

0.0

实体在图中存在的得分的较低限制。值必须介于 0 和 1 之间。

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

write

布尔值

false

持久化实体图

writeRelationshipType

字符串

ENTITY

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

writeRelationshipProperty

字符串

score

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

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

关键短语

关键短语过程 (apoc.nlp.azure.keyPhrases.*) 是围绕 关键短语 Azure 文本分析 API 端点的包装器。关键短语是输入文本中的关键谈话要点。

过程如下所述

签名

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

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

该过程支持以下配置参数

表 3. 配置参数
名称 类型 默认值 说明

key

字符串

Microsoft.CognitiveServicesTextAnalytics API 密钥

url

字符串

Microsoft.CognitiveServicesTextAnalytics 端点

nodeProperty

字符串

text

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

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

表 4. 配置参数
名称 类型 默认值 说明

write

布尔值

false

持久化关键短语图

writeRelationshipType

字符串

KEY_PHRASE

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

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

情感

情感过程 (apoc.nlp.azure.sentiment.*) 是围绕 情感 Azure 文本分析 API 端点的包装器。该 API 返回介于 0 和 1 之间的数字分数。接近 1 的分数表示积极的情感,而接近 0 的分数表示消极的情感。分数为 0.5 表示缺乏情感(例如,事实陈述)。

下面描述了这些过程

签名

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

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

该过程支持以下配置参数

表 5. 配置参数
名称 类型 默认值 说明

key

字符串

Microsoft.CognitiveServicesTextAnalytics API 密钥

url

字符串

Microsoft.CognitiveServicesTextAnalytics 端点

nodeProperty

字符串

text

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

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

表 6. 配置参数
名称 类型 默认值 说明

write

布尔值

false

持久化情感图

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

安装依赖项

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

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

设置 API 密钥和 URL

我们可以按照 快速入门:使用文本分析客户端库 文章中的说明生成 API 密钥和 URL。完成此操作后,我们应该能够看到一个页面列出我们的凭据,类似于下面的屏幕截图

azure text analytics keys
图 1. Azure 文本分析凭据

在本例中,我们的 API URL 是 https://neo4j-nlp-text-analytics.cognitiveservices.azure.com/,我们可以使用任何隐藏的密钥。

让我们填充并执行以下命令以创建包含这些详细信息的参数。

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

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

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

{apiKey: "<api-key-here>", apiUrl: "<api-url-here>"}

示例

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

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

{name: "Nintendo Switch", wikipediaId: "Nintendo Switch", type: "Other", matches: [{length: 15, text: "Nintendo Switch", wikipediaScore: 0.8339868065025469, offset: 56}], bingId: "b3d617ef-81fc-4188-9a2b-a5cf1f8534b5", wikipediaLanguage: "en", wikipediaUrl: "https://en.wikipedia.org/wiki/Nintendo_Switch"}

{name: "Nintendo Switch", type: "Organization", matches: [{length: 15, entityTypeScore: 0.94, text: "Nintendo Switch", offset: 56}]}

{name: "Oberon Media", wikipediaId: "Oberon Media", type: "Organization", matches: [{length: 6, text: "I play", wikipediaScore: 0.032446316016667254, offset: 76}], bingId: "166f6e0f-33b7-8707-bb8b-5a932c498333", wikipediaLanguage: "en", wikipediaUrl: "https://en.wikipedia.org/wiki/Oberon_Media"}

{name: "a week", subType: "Duration", type: "DateTime", matches: [{length: 6, entityTypeScore: 0.8, text: "a week", offset: 166}]}

{name: "Mario Kart 8", wikipediaId: "Mario Kart 8", type: "Other", matches: [{length: 12, text: "Mario Kart 8", wikipediaScore: 0.7802000593632747, offset: 205}], bingId: "ce6f55ec-d3d7-032a-0bf8-15ad3e8df3f4", wikipediaLanguage: "en", wikipediaUrl: "https://en.wikipedia.org/wiki/Mario_Kart_8"}

{name: "Mario Kart", type: "Organization", matches: [{length: 10, entityTypeScore: 0.72, text: "Mario Kart", offset: 205}]}

{name: "8", subType: "Number", type: "Quantity", matches: [{length: 1, entityTypeScore: 0.8, text: "8", offset: 216}]}

{name: "Neo4j", wikipediaId: "Neo4j", type: "Other", matches: [{length: 5, text: "Neo4j", wikipediaScore: 0.8150388253887939, offset: 242}], bingId: "bc2f436b-8edd-6ba6-b2d3-69901348d653", wikipediaLanguage: "en", wikipediaUrl: "https://en.wikipedia.org/wiki/Neo4j"}

{name: "Europe", wikipediaId: "Europe", type: "Location", matches: [{length: 8, text: "European", wikipediaScore: 0.00591759926701263, offset: 248}], bingId: "501457aa-5b70-cfba-cfd8-be882b4bac1e", wikipediaLanguage: "en", wikipediaUrl: "https://en.wikipedia.org/wiki/Europe"}

我们得到了 9 个不同的实体,尽管我们可以看到其中一些实体指的是同一个东西,但它们的 type 值不同。然后,我们可以应用一个 Cypher 语句,为每个实体创建一个节点,并从这些节点中的每一个节点到 Article 节点创建一个 ENTITY 关系。

以下流式传输 Pokemon 文章的实体,然后为每个实体创建节点
MATCH (a:Article {uri: "https://neo4j.ac.cn/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.azure.entities.stream(a, {
  key: $apiKey,
  url: $apiUrl,
  nodeProperty: "body"
})
YIELD value
UNWIND value.entities AS entity
WITH a, entity.name AS entity, collect(entity.type) AS types
MERGE (e:Entity {name: entity})
SET e.type = types
MERGE (a)-[:ENTITY]->(e);

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

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

我们可以在 Pokemon 和 Nintendo Switch 实体图 中看到虚拟图的 Neo4j 浏览器可视化效果。

apoc.nlp.azure.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.azure.entities.graph(articles, {
  key: $apiKey,
  url: $apiUrl,
  nodeProperty: "body",
  scoreCutoff: 0.7,
  writeRelationshipType: "ENTITY"
})
YIELD graph AS g
RETURN g

我们可以在 置信度 >= 0.7 的 Pokemon 和 Nintendo Switch 实体图 中看到虚拟图的 Neo4j 浏览器可视化效果。

apoc.nlp.azure.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.azure.entities.graph(articles, {
  key: $apiKey,
  url: $apiUrl,
  nodeProperty: "body",
  scoreCutoff: 0.7,
  writeRelationshipType: "HAS_ENTITY",
  writeRelationshipProperty: "azureEntityScore",
  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.azureEntityScore}] AS entities;
表 9. 结果
article entities

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

[{score: 0.72, text: "Mario Kart"}, {score: 0.7802000593632747, text: "Mario Kart 8"}, {score: 0.8, text: "8"}, {score: 0.8, text: "a week"}, {score: 0.94, text: "Nintendo Switch"}, {score: 0.8150388253887939, text: "Neo4j"}]

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

[{score: 0.9023679924293266, text: "Joy-Con"}, {score: 0.98, text: "Nintendo"}, {score: 0.8, text: "March 3, 2017"}, {score: 0.9355623498560008, text: "Nintendo Switch"}, {score: 0.92, text: "Mario Kart"}, {score: 0.8, text: "8"}, {score: 0.8863202650046607, text: "Mario Kart 8"}, {score: 0.8, text: "October 20, 2016"}]

关键短语

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

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

"board games"

"card games"

"tournaments"

"role"

"organised lunch-time Mario Kart"

"Neo4j European offices"

"Nintendo Switch"

"friends"

"feet"

"days"

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

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

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

我们可以在 Pokemon 关键短语图 中看到虚拟图的 Neo4j 浏览器可视化效果。

apoc.nlp.azure.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/"

["card games", "board games", "friends", "feet", "Nintendo Switch", "days", "organised lunch-time Mario Kart", "tournaments", "Neo4j European offices", "role"]

情感

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

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

{score: 0.5, id: "0"}

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

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

以下返回带有 Pokemon 文章情感的图
MATCH (a:Article {uri: "https://neo4j.ac.cn/blog/pokegraph-gotta-graph-em-all/"})
CALL apoc.nlp.azure.sentiment.graph(a, {
  key: $apiKey,
  url: $apiUrl,
  nodeProperty: "body",
  write: true
})
YIELD graph AS g
UNWIND g.nodes AS node
RETURN node {.uri, .sentimentScore} AS node;
表 13. 结果
node

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