GraphGists

ClimbingDB(社交网络攀岩数据库)

简介

攀岩是一项越来越受欢迎的运动,它无疑是享受户外时光和挑战自我的绝佳方式。对我来说,它提供了持续的动力和放松,我相信这对世界各地的许多攀岩者来说也是如此。

在这个示例中,我专注于最流行的攀岩类型,即运动攀岩。从本质上讲,我们可以说运动攀岩是一种垂直运动,其目标是通过使用分级系统来挑战个人极限(alpinist.com)。运动攀岩可以进一步细分为抱石和先锋攀岩。后者可能比抱石在公众中更广为人知。抱石除了垫子外不使用任何保护措施,而先锋攀岩则使用绳索和其他保护设备。

毫无疑问,我们可以说攀岩将继续作为一项运动发展,无论是对于像我这样的爱好者还是专业人士(希望在未来的奥运会上)。

动机

此示例提供了一个应用程序的概述或模型,该应用程序结合了路线和攀岩地点的数据库,以及一个攀岩者可以见面并相互交流的社交平台。关于路线、攀岩地点和包含它们的国家/地区的数据高度关联,非常适合图数据库,例如Neo4j。它的社交方面更突出了这一点。

在后面的章节中,将提供数据模型的描述以及一些术语解释,以使读者更容易理解。根据挑战规则,提供了一些用例和示例(基于示例数据)。

节点描述

  • 路线是岩石上的攀登路径:),具有属性:名称等级(参见上文的分级系统)

  • 岩场,有时称为攀岩地点或仅为岩壁,具有属性:名称方向(东、西、南、北)

  • 国家/地区代表国家/地区(英文名称),具有属性:名称

  • 俱乐部代表攀岩俱乐部,具有属性:名称

  • 攀岩者是个人攀岩者(此模型的社交方面),具有属性:名字姓氏出生日期

关系描述

岩场(攀岩地点)是路线的汇总。岩场包含路线,路线是岩场的一部分。一条路线只能属于一个岩场,但不同的路线可能有相同的名称(实际上很常见,但在一个岩场中,没有两条路线具有相同的名称)。

通常,岩场由俱乐部管理,俱乐部负责岩场(有时并非如此,但在大多数情况下是如此)。俱乐部起源于不同的国家/地区,并拥有成员,即攀岩者。

就像俱乐部一样,攀岩者也来自不同的国家/地区,并且是(或不是)俱乐部的成员。路线由攀岩者攀登(显然)。这为个人攀岩者提供了一种日记形式,以及路线的一些统计数据。许多攀岩者都有自己最喜欢的攀岩地点。

示例数据导入

为了更好地理解模型和领域,我们应该导入一些示例数据,并使用所有实体的一些代表来填充图。以下是示例数据导入的Cypher查询

首先是一些节点

CREATE (:CLIMBER{name:'Alice', last_name:'Wonderland', Dob:'12.12.2000'})
CREATE (:CLIMBER{name:'Bob', last_name:'Missy', Dob:'3.3.1989'})
CREATE (:CLIMBER{name:'Jack', last_name:'Chan', Dob:'5.6.2004'})
CREATE (:CLIMBER{name:'Hilary', last_name:'Hope', Dob:'8.5.1995'})
CREATE (:CLIMBER{name:'Annie', last_name:'Hork', Dob:'8.8.1945'})

CREATE (:ROUTE{name:'Hoax', grade:'6a'})
CREATE (:ROUTE{name:'Hooking', grade:'8b'})
CREATE (:ROUTE{name:'Banana', grade:'7c'})
CREATE (:ROUTE{name:'Pork_and_Beans', grade:'5a'})
CREATE (:ROUTE{name:'Traversal', grade:'4c+'})

CREATE (:CRAG{name:'Kamnitnik', orientation:'East'})
CREATE (:CRAG{name:'Rocky', orientation:'West'})
CREATE (:CRAG{name:'Big_Wall', orientation:'North'})
CREATE (:CRAG{name:'Jungle_Tree', orientation:'South'})
CREATE (:CRAG{name:'Beach_sunset', orientation:'South'})

CREATE (:CLUB{name:'AO_Kranj'})
CREATE (:CLUB{name:'Pensilvania_CC'})
CREATE (:CLUB{name:'Ljubljana_CC'})
CREATE (:CLUB{name:'Best_Climbing_Club_Ever'})
CREATE (:CLUB{name:'SUDOSK'})

CREATE (:COUNTRY{name:'Pakistan'})
CREATE (:COUNTRY{name:'Turkey'})
CREATE (:COUNTRY{name:'Slovenia'})
CREATE (:COUNTRY{name:'France'})
CREATE (:COUNTRY{name:'USA'})

现在让我们添加一些关系

  • 俱乐部成员

MATCH (a:CLIMBER),(b:CLUB), (c:CLIMBER),(d:CLUB), (e:CLIMBER),(f:CLUB)
WHERE a.name = 'Jack' AND b.name = 'AO_Kranj' AND c.name = 'Hilary' AND d.name = 'SUDOSK' AND e.name = 'Annie' AND f.name = 'Best_Climbing_Club_Ever'
CREATE (a)-[r:is_member]->(b), (c)-[s:is_member]->(d), (e)-[t:is_member]->(f)
RETURN r, s, t;
  • 哪些岩场由俱乐部负责

MATCH (a:CLUB),(c:CLUB),(b:CRAG),(d:CRAG)
WHERE a.name = 'AO_Kranj' AND b.name = 'Kamnitnik' AND c.name = 'SUDOSK' AND d.name = 'Rocky'
CREATE (a)-[r:is_responsible_for]->(b), (c)-[s:is_responsible_for]->(d)
  • 不同的路线属于哪些岩场

MATCH (a:ROUTE),(b:CRAG),(c:ROUTE),(d:CRAG),(e:ROUTE),(f:CRAG), (g:ROUTE),(h:CRAG), (k:ROUTE),(j:CRAG)
WHERE a.name = 'Hoax' AND b.name = 'Kamnitnik' AND c.name = 'Hooking' AND d.name = 'Kamnitnik' AND e.name = 'Banana' AND f.name = 'Rocky' AND g.name = 'Pork_and_Beans' AND h.name = 'Rocky' AND k.name = 'Traversal' AND j.name = 'Jungle_Tree'
CREATE (a)-[r:is_part_of]->(b),(c)-[s:is_part_of]->(d), (e)-[v:is_part_of]->(f), (g)-[t:is_part_of]->(h), (k)-[z:is_part_of]->(j)
  • 在哪个国家/地区可以找到岩场

MATCH (a:CRAG),(b:COUNTRY), (c:CRAG),(d:COUNTRY), (e:CRAG),(f:COUNTRY), (g:CRAG),(h:COUNTRY), (k:CRAG),(j:COUNTRY)
WHERE a.name = 'Kamnitnik' AND b.name = 'Slovenia' AND c.name = 'Rocky' AND d.name = 'Turkey' AND e.name = 'Big_Wall' AND f.name = 'USA' AND g.name = 'Jungle_Tree' AND h.name = 'France' AND k.name = 'Beach_sunset' AND j.name = 'Pakistan'
CREATE (a)-[r:is_in]->(b), (c)-[s:is_in]->(d), (e)-[t:is_in]->(f), (g)-[w:is_in]->(h), (k)-[q:is_in]->(j)
  • 哪些岩场受到不同攀岩者的喜爱

MATCH (a:CLIMBER),(b:CRAG), (c:CLIMBER),(d:CRAG), (e:CLIMBER),(f:CRAG)
WHERE a.name = 'Annie' AND b.name = 'Kamnitnik' AND c.name = 'Bob' AND d.name = 'Kamnitnik' AND e.name = 'Jack' AND f.name = 'Kamnitnik'
CREATE (a)-[r:favours]->(b), (c)-[s:favours]->(d), (e)-[t:favours]->(f)
  • 攀岩者来自哪里

MATCH (a:CLIMBER),(b:COUNTRY), (c:CLIMBER),(d:COUNTRY), (e:CLIMBER),(f:COUNTRY), (g:CLIMBER),(h:COUNTRY), (k:CLIMBER),(j:COUNTRY) WHERE a.name = 'Alice' AND b.name = 'Pakistan' AND c.name = 'Bob' AND d.name = 'Turkey' AND e.name = 'Jack' AND f.name = 'Slovenia' AND g.name = 'Hilary' AND h.name = 'France' AND k.name = 'Annie' AND j.name = 'USA'
CREATE (a)-[r:comes_from]->(b), (d)-[s:comes_from]->(c), (e)-[t:comes_from]->(f), (g)-[w:comes_from]->(h), (k)-[q:comes_from]->(j)
  • 俱乐部起源于哪些国家/地区

MATCH (a:CLUB),(b:COUNTRY),(c:CLUB),(d:COUNTRY), (e:CLUB),(f:COUNTRY), (g:CLUB),(h:COUNTRY), (j:CLUB),(k:COUNTRY)
WHERE a.name = 'AO_Kranj' AND b.name = 'Slovenia' AND c.name = 'SUDOSK' AND d.name = 'France' AND e.name = 'Pensilvania_CC' AND f.name = 'USA' AND g.name = 'Ljubljana_CC' AND h.name = 'Slovenia' AND j.name = 'Best_Climbing_Club_Ever' AND k.name = 'USA'
CREATE (a)-[r:originates_from]->(b), (c)-[s:originates_from]->(d), (e)-[t:originates_from]->(f), (g)-[w:originates_from]->(h), (j)-[q:originates_from]->(k)
  • 谁攀登了什么

MATCH (a:CLIMBER),(b:ROUTE),(c:CLIMBER),(d:ROUTE), (e:CLIMBER),(f:ROUTE), (g:CLIMBER),(h:ROUTE), (j:CLIMBER),(k:ROUTE), (l:CLIMBER),(m:ROUTE)
WHERE a.name = 'Alice' AND b.name = 'Hoax' AND c.name = 'Jack' AND d.name = 'Hoax' AND e.name = 'Annie' AND f.name = 'Banana' AND g.name = 'Hilary' AND h.name = 'Banana' AND j.name = 'Bob' AND k.name = 'Banana' AND l.name = 'Alice' AND m.name = 'Pork_and_Beans'
CREATE (a)-[r:climbed]->(b),(c)-[s:climbed]->(d), (e)-[t:climbed]->(f), (g)-[v:climbed]->(h), (j)-[z:climbed]->(k),(l)-[q:climbed]->(m)
  • 谁认识谁

MATCH (a:CLIMBER),(b:CLIMBER),(c:CLIMBER),(d:CLIMBER), (e:CLIMBER),(f:CLIMBER), (g:CLIMBER),(h:CLIMBER), (j:CLIMBER),(k:CLIMBER), (m:CLIMBER),(n:CLIMBER)
WHERE a.name = 'Alice' AND b.name = 'Jack' AND c.name = 'Alice' AND d.name = 'Jack' AND e.name = 'Alice' AND f.name = 'Hilary' AND g.name = 'Annie' AND h.name = 'Bob' AND j.name = 'Alice' AND k.name = 'Annie' AND m.name = 'Jack' AND n.name = 'Annie'
CREATE (a)-[r:is_friends_with]->(b), (c)-[s:is_friends_with]->(d), (e)-[t:is_friends_with]->(f), (g)-[v:is_friends_with]->(h), (j)-[q:is_friends_with]->(k), (m)-[z:is_friends_with]->(n)

现在我们已经填充了数据库,并且拥有了一个可以执行一些查询的图,并在下一部分中展示了用例。为了更好地可视化,请参考下面的图表示

用例

在本部分中,我们介绍了一些可以应用于我们的图/数据的可能用例。如前所述,我们将数据库和社交媒体的功能结合在一起。这为我们提供了广泛的潜在用例范围(从通常的调查性查询到一些复杂的社交图分析)。在这里,我们使用Cypher代码片段介绍了一些用例,还提供了一些在更广泛的场景(更多实际数据)中可能出现的思路。

一些可能的查询可能包括

  • 谁攀登次数最多

MATCH (climber)-[r:climbed]->(route)
RETURN climber.name AS WHO, count(r) AS HOW_MUCH, collect(route.name) AS WHAT
ORDER BY count(r) DESC
  • 攀岩者在哪里攀岩(访问次数最多的攀岩地点)以及谁已经访问过它

MATCH (climber)-[s:climbed]->(route)-[r:is_part_of]->(crag)-[:is_in]->(country)
RETURN crag.name AS CRAG, country.name AS COUNTRY , COUNT(r) AS NUMBER_OF_VISITS, collect(climber.name) AS WHO
  • 谁负责最受欢迎(最受喜爱)的攀岩地点

MATCH (climber)-[s:favours]->(crag)<-[:is_responsible_for]-(club)
RETURN crag.name AS CRAG, count(s) AS FAVOURED, club.name AS RESPONSIBILITY_OF

这些只是一些可能由对这项运动感兴趣的人或应用程序的功能提出的一些查询。由于这里我们只有少量示例数据,因此查询和结果不太有趣。

让我们检查一个涉及图的社交网络维度的示例场景,有人可能会称之为调查性数据科学。我们已经通过查询发现了攀岩者最喜欢的攀岩地点。还包括已经喜欢它的攀岩者列表

MATCH (climber)-[s:favours]->(crag)-[:is_in]->(country)
RETURN crag.name AS CRAG, count(s) AS COUNT, collect(climber.name) AS WHO

通过这样做,我们发现Annie、Jack、Bob喜欢同一个岩场。通过以下查询,我们可以发现这三个人来自哪里

MATCH (country1)-[t:comes_from]-(climber)-[s:favours]->(crag)-[r:is_in]->(country2)
WHERE climber.name IN ['Annie','Bob','Jack']
RETURN climber.name AS CLIMBER, country1.name AS COMING_FROM, crag.name AS LIKED , country2.name AS FROM

事实证明,这三个人中只有一人来自与受欢迎的岩场所在的国家/地区相同的国家/地区。有人可能会问,为什么来自美国(Annie)和/或土耳其(Bob)的人会喜欢斯洛文尼亚这样的小国的攀岩地点。

让我们检查一下我们的斯洛文尼亚攀岩者Jack的社交图。我们可能会获得一些关于他的信息。我们使用以下查询获取Jack的朋友(以及Jack朋友的朋友)

MATCH (country)<-[t:comes_from]-(climber)-[z:is_friends_with]->(others)-[r:is_friends_with]-(some_others) WITH country, climber, others, some_others, t, z, r
WHERE country.name = 'Slovenia'
RETURN climber.name AS CLIMBER, collect(distinct others.name) AS ONE , collect(some_others.name) AS TWO

或者我们只需返回图的整个社交维度(我们的数据量很小,所以我们可以这样做)。**通过观察,我们可以发现,在喜欢斯洛文尼亚同一个岩场的攀岩者中,只有一人实际上来自斯洛文尼亚。另外两个人与他有一级(Annie)或二级(Bob)的关系。**

结论

社交网络和高度关联的数据的结合是使用Neo4j的绝佳机会。在此示例中,我们仅探讨了在这样的应用程序中可能会遇到的一小部分可能性。示例数据量很小,结果可能对每个人来说都不有趣,但随着数据的增长,探索和应用想法的可能性也会增加。我希望此示例提供了一些关于攀岩的有用信息,并且也许有人会加入我们的行列。

一如既往,使用Neo4j、Cypher和图本身都非常有趣。