GraphGists

英国公司数据

本Neo4j Browser指南将引导您完成英国公司注册、土地所有权和政治捐赠数据的导入和查询过程。我们在此过程中将学习Cypher!

在学习示例时,请务必参考Cypher参考卡

概要

  • 数据导入

  • 使用MATCH查询

  • 使用关系

  • 模糊匹配

  • 处理数字

  • 日期

  • 位置数据

  • 图算法

ukcompanies model

导入

请务必在Neo4j Browser中启用多语句查询编辑器,然后运行

CREATE CONSTRAINT ON (c:Company) ASSERT c.companyNumber IS UNIQUE;
//Constraint for a node key is a Neo4j Enterprise feature only - run on an instance with enterprise
//CREATE CONSTRAINT ON (p:Person) ASSERT (p.birthMonth, p.birthYear, p.name) IS NODE KEY
CREATE CONSTRAINT ON (p:Property) ASSERT p.titleNumber IS UNIQUE;
LOAD CSV WITH HEADERS FROM "https://guides.neo4j.com/ukcompanies/data/PSCAmericans.csv" AS row
MERGE (c:Company {companyNumber: row.company_number})
RETURN COUNT(*);
LOAD CSV WITH HEADERS FROM "https://guides.neo4j.com/ukcompanies/data/PSCAmericans.csv" AS row
MERGE (p:Person {name: row.`data.name`, birthYear: row.`data.date_of_birth.year`, birthMonth: row.`data.date_of_birth.month`})
ON CREATE SET p.nationality = row.`data.nationality`,
              p.countryOfResidence = row.`data.country_of_residence`
              // TODO: Address
RETURN COUNT(*);
LOAD CSV WITH HEADERS FROM "https://guides.neo4j.com/ukcompanies/data/PSCAmericans.csv" AS row
MATCH (c:Company {companyNumber: row.company_number})
MATCH (p:Person {name: row.`data.name`, birthYear: row.`data.date_of_birth.year`, birthMonth: row.`data.date_of_birth.month`})
MERGE (p)-[r:HAS_CONTROL]->(c)
 SET r.nature = split(replace(replace(replace(row.`data.natures_of_control`, "[",""),"]",""),  '"', ""), ",")
RETURN COUNT(*);
LOAD CSV WITH HEADERS FROM "https://guides.neo4j.com/ukcompanies/data/CompanyDataAmericans.csv" AS row
MATCH (c:Company {companyNumber: row.` CompanyNumber`})
SET c.name = row.CompanyName,
    c.mortgagesOutstanding = toInteger(row.`Mortgages.NumMortOutstanding`),
    c.incorporationDate = Date(Datetime({epochSeconds: apoc.date.parse(row.IncorporationDate,'s','dd/MM/yyyy')})),
    c.SIC = row.`SICCode.SicText_1`,
    c.countryOfOrigin = row.CountryOfOrigin,
    c.status = row.CompanyStatus,
    c.category = row.CompanyCategory;
LOAD CSV WITH HEADERS FROM "https://guides.neo4j.com/ukcompanies/data/ElectionDonationsAmericans.csv" AS row
MATCH (c:Company) WHERE c.companyNumber = row.CompanyRegistrationNumber
MERGE (p:Recipient {name: row.RegulatedEntityName})
SET p.entityType = row.RegulatedEntityType
MERGE (c)-[r:DONATED {ref: row.ECRef}]->(p)
SET r.date  = Date(Datetime({epochSeconds: apoc.date.parse(row.ReceivedDate,'s','dd/MM/yyyy')})),
    r.value = toFloat(replace(replace(row.Value, "£", ""), ",", ""));
LOAD CSV WITH HEADERS FROM "https://guides.neo4j.com/ukcompanies/data/LandOwnershipAmericans.csv" AS row
MATCH (c:Company {companyNumber: row.`Company Registration No. (1)`})
MERGE (p:Property {titleNumber: row.`Title Number`})
SET p.address = row.`Property Address`,
    p.county  = row.County,
    p.price   = toInteger(row.`Price Paid`),
    p.district = row.District
MERGE (c)-[r:OWNS]->(p)
WITH row, c,r,p WHERE row.`Date Proprietor Added` IS NOT NULL
SET r.date = Date(Datetime({epochSeconds: apoc.date.parse(row.`Date Proprietor Added`,'s','dd-MM-yyyy')}));

CREATE INDEX ON :Company(incorporationDate);

验证数据导入

通过运行以下命令验证导入的数据模型

CALL db.schema.visualization();

人物

  • 名称

  • 国籍

  • 居住国家

  • 出生年份

  • 出生月份

关系

(:人物)-[:HAS_CONTROL]→(:公司)

公司

  • 公司编号

  • 名称

  • 状态

  • SIC

  • 原产国家

  • 注册日期

  • 未偿抵押贷款

关系

  • (:公司)-[:OWNS]→(:房产)

  • (:公司)-[:DONATED]→(:接收方)

房产

  • 产权编号

  • 地址

  • 价格

接收方

  • 名称

  • 实体类型

使用MATCH查询

数据导入完成后,就可以开始查询了!

在Neo4j中,我们使用MATCH命令来查询数据。语法是MATCH,后跟图模式。例如

MATCH (p:Person {name: "Margery Kraus"})
RETURN p
  • ()表示一个节点

  • :人物是节点标签

  • {}表示属性

  • {name: ""}

  • p成为一个变量,绑定到与模式匹配的图部分

  • 我们使用RETURN返回数据并可视化结果

使用MATCH查询 - 练习

现在轮到你了!

  • 查找名称为Michael Rubens Bloomberg人物节点

  • 查找名称为GRAPHIC PLC公司

记住MATCH的基本格式

MATCH (variable:NodeLabel {property: "value"})
RETURN variable

使用MATCH查询 - 答案

查找名称为Michael Rubens Bloomberg人物节点

MATCH (p:Person {name: "Michael Rubens Bloomberg"})
RETURN p

查找名称为GRAPHIC PLC公司

MATCH (c:Company {name: "GRAPHIC PLC"})
RETURN c

使用关系

节点通过关系连接。我们可以在MATCH语句中使用方括号[]定义关系,从而定义包含关系的更复杂的图模式。例如

MATCH (p:Person {name: "Margery Kraus"})-[:HAS_CONTROL]->(c:Company)
RETURN p, c
  • 注意-[:HAS_CONTROL]→模式

使用关系 - 练习

  • 您能找到与Michael Rubens Bloomberg关联的公司吗?

  • 这些与Michael Ruben Bloomberg关联的公司拥有任何房产吗?

  • 这些与Michael Ruben Bloomberg关联的公司是否进行过政治捐赠?

使用关系 - 答案

与Michael Rubens Bloomberg关联的公司?

MATCH (p:Person {name: "Michael Rubens Bloomberg"})-[:HAS_CONTROL]->(c:Company)
RETURN p, c

这些公司拥有任何房产吗?

MATCH (p:Person {name: "Michael Rubens Bloomberg"})-[:HAS_CONTROL]->(c:Company)-[:OWNS]->(pr:Property)
RETURN p, c, pr

这些公司是否进行过政治捐赠?

MATCH (p:Person {name: "Michael Rubens Bloomberg"})-[:HAS_CONTROL]->(c:Company)-[:DONATED]->(r:Recipient)
RETURN p, c, r

模糊匹配

我们已经了解了如何进行精确比较,但是“模糊”匹配呢?例如,如果我们不知道Michael Bloomberg的中间名怎么办?或者想考虑细微的拼写错误?

对于非精确匹配,我们有几种选择

  • CONTAINS字符串比较运算符

  • 正则表达式

  • 使用全文索引实现真正的模糊匹配

模糊匹配 - CONTAINS

CONTAINS字符串比较运算符可用于匹配包含子字符串的字符串。

要利用CONTAINS,我们需要引入WHERE子句。我们可以在WHERE子句中使用任何布尔表达式来过滤匹配项。例如

MATCH (p:Person)
WHERE p.name CONTAINS "Bloomberg"
RETURN p

模糊匹配 - 正则表达式

我们也可以使用正则表达式。

这等同于使用CONTAINS

MATCH (p:Person)
WHERE p.name =~ ".*Bloomberg.*"
RETURN p

我们也可以进行不区分大小写的匹配

MATCH (c:Company)
WHERE c.name =~ "(?i)graphic.*"
RETURN c

更多示例请参阅正则表达式文档

模糊匹配 - 全文索引

全文索引可以帮助我们进行真正的模糊比较——考虑到拼写错误。

首先,我们必须创建全文索引

CALL db.index.fulltext.createNodeIndex("nameIndex", ["Person"], ["name"])

然后我们可以查询它

CALL db.index.fulltext.queryNodes("nameIndex", "Peterson~")

请注意名称中的~。这表示我们应该匹配搜索词的细微拼写错误。有关模糊匹配查询语法的更多信息,请参阅此处

模糊匹配 - 练习

1) Contains

查找Abigail Johnson以及与她关联的任何公司。提示:数据可能包含名称前缀(如Mr、Mrs、Ms等),因此我们需要将其考虑在内。

2) 正则表达式

我们想查找伦敦的所有房产;然而,我们注意到房产节点上的address属性包含“London”和“LONDON”。编写一个使用正则表达式查找伦敦所有房产节点的查询。

模糊匹配 - 答案

1) Contains

MATCH (p:Person)-[:HAS_CONTROL]->(c:Company)
WHERE p.name CONTAINS "Abigail Johnson"
RETURN p,c

2) 正则表达式

MATCH (c:Company)
WHERE c.name =~ "(?i).*london.*"
RETURN c

处理数字

将属性值存储为数字对于回答以下问题非常有用

显示所有在1,000至10,000英镑之间的政治捐赠

MATCH (c:Company)-[d:DONATED]->(r:Recipient)
WHERE 1000 < d.value < 10000
RETURN c,d,r

请注意,这里我们正在访问关系上的一个属性!

显示伦敦所有价值超过1000万英镑、由美国人控制的公司拥有的房产

MATCH path=(prop:Property)<-[:OWNS]-(:Company)<-[:HAS_CONTROL]-(per:Person)
WHERE prop.price > 10000000 AND prop.address =~ "(?i).*London.*"
    AND per.nationality = "American"
RETURN path

对于给定个体,他们控制的公司进行的政治捐赠总额是多少?

MATCH (p:Person {name: "Ms Abigail Johnson"})-[:HAS_CONTROL]->(c:Company)-[d:DONATED]->(:Recipient)
RETURN sum(d.value) AS totalDonations, p.name AS person, c.name AS company

这里我们执行聚合,对模式中所有匹配的DONATED关系的value属性求和。有关Cypher中聚合函数的更多信息,请参阅此处

处理数字 - 练习

  • 查找由Michael Bloomberg控制的公司进行的竞选捐赠总额。

  • 这些捐赠给了哪些政党?总共给了每个政党多少?

  • 在与Bloomberg关联的公司中,哪家公司进行了最多的竞选捐赠?

处理数字 - 答案

查找由Michael Bloomberg控制的公司进行的竞选捐赠总额。

//Find the total value of campaign donations made by companies controlled by Michael Bloomberg.

// First be sure to find all Michael Bloombergs in the data
MATCH (p:Person)
WHERE p.name =~  "(?i).*Michael.*Bloomberg.*"
// Find all companies connected to Bloomberg and donations
MATCH (p)-[:HAS_CONTROL]->(c:Company)-[r:DONATED]->(party:Recipient)
// Aggregate the value property of all donations from these companies
RETURN sum(r.value) AS total

这些捐赠给了哪些政党?总共给了每个政党多少?

MATCH (p:Person)
WHERE p.name =~  "(?i).*Michael.*Bloomberg.*"
MATCH (p)-[:HAS_CONTROL]->(c:Company)-[r:DONATED]->(party:Recipient)
// When we add party.name to the RETURN clause we group our sum aggregation by party.name
RETURN party.name, sum(r.value) AS total
ORDER BY total DESC

在与Bloomberg关联的公司中,哪家公司进行了最多的竞选捐赠?

MATCH (p:Person)
WHERE p.name =~  "(?i).*Michael.*Bloomberg.*"
MATCH (p)-[:HAS_CONTROL]->(c:Company)-[r:DONATED]->(party:Recipient)
RETURN c.name, sum(r.value) AS total
ORDER BY total DESC

日期

日期在Neo4j中被视为特殊类型,并在Cypher中有自己的函数。

例如,构造一个日期

RETURN date("2019-03-06")

我们可以像这样过滤日期范围内的事件

MATCH (c:Company)
WHERE date("2017-01-01") < c.incorporationDate < date("2017-01-15")
RETURN c

日期 - 练习

  • 查找在2016年1月1日之后成立并进行过竞选捐赠的所有公司。

日期 - 答案

MATCH (c:Company)-[r:DONATED]->(party:Recipient)
WHERE Date("2016-01-01") < c.incorporationDate
RETURN c

位置数据

源数据包含地址。如果我们可以将这些地址转换为经度/纬度,我们就可以搜索彼此接近、在某个点或多边形范围内的房产,或者创建交互式地理数据可视化

幸运的是,我们可以利用Neo4j的地理编码过程来实现这一点。

CALL apoc.spatial.geocodeOnce("6 Anchorage Terrace, Durham (DH1 3DL)") YIELD location, latitude, longitude

我们可以更新房产节点,为其添加一个类型为Point的新属性location

MATCH (p:Property) WITH p LIMIT 1
CALL apoc.spatial.geocodeOnce(p.address) YIELD location, latitude, longitude, description
SET p.location = Point({latitude: latitude, longitude: longitude})
RETURN p

注意:您需要拥有数据库的写入权限

查找数据集中距离Neo4j伦敦办公室10公里以内的房产

MATCH path=(p:Property)<-[:OWNS]-(:Company)<-[:HAS_CONTROL]-(:Person)
WHERE distance(p.location, Point({latitude:51.5122338, longitude:-0.1180369})) < 10000
RETURN path

位置数据 - 练习

开放式练习

假设您正在研究黑石集团的CEO Stephen A. Schwarzman。您可以在数据中找到关于他的哪些信息?

© . All rights reserved.