英国公司数据
英国公司数据
本Neo4j Browser指南将引导您完成英国公司注册、土地所有权和政治捐赠数据的导入和查询过程。我们在此过程中将学习Cypher!
在学习示例时,请务必参考Cypher参考卡。
概要
-
数据导入
-
使用
MATCH
查询 -
使用关系
-
模糊匹配
-
处理数字
-
日期
-
位置数据
-
图算法

导入
请务必在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
日期 - 答案
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
这个页面有帮助吗?