精华 Graphs4Good: 使用Neo4j Bloom实现传染病病毒案例的接触史追踪
发布于 6 个月前 作者 graphway 1410 次浏览 最后一次编辑是 5 个月前 来自 分享

(本文的英文原文发表于:https://community.neo4j.com/t/graphs4good-protecting-community-from-covid-19-by-answering-key-questions-in-neo4j-bloom/17291)

尽管目前世界上大多数国家都在半封锁状态、以减慢致命的COVID-19病毒的传播,但寻找治愈方法的斗争从未停止。赢得这场前所未有的反病毒战争的关键很大程度上取决如何利用现有的数据来确定感染源、了解病毒如何传播以及保护社区免受感染。到目前为止,接触史追踪(Contact Tracing)已被认为是遏制情况恶化的最有效方法之一。

时机至关重要。

政府,组织甚至个人都需要一种追踪高风险患者和地点的方法。每天发布的确诊病例数量还远远不够。能够将那些确诊案例的详细信息包括何人、何时、何地以及传播途径等联系起来的能力比以往任何时候都更加重要,只有这样才能提供及时和可行的反应和预测。显然,这是图数据库解决方案的一个完美的问题。

基于Neo4j社区和相关政府机构的一些想法,使用公开可用的案例数据(不包含身份信息),我用周四花了一个晚上的时间使用Neo4j Bloom构建此解决方案,以帮助回答(是的,以自然语言)接触史追踪的关键问题。以下是具体的方法。

1.加载数据      为了深入了解病毒如何在人群中传播,我们需要个别的病例数据,而不是病例统计。实际上,Kaggle发起的COVID-19挑战赛提供这样的个别案例数据,可在此处找到:UNCOVER COVID-19挑战赛1

我也在Github上分享了本项目,可以找到2个数据文件。个例文件的布局不难理解,以下是Cypher LOAD CSV语句,可将数据加载到Neo4j中:

// 1.1 Load individual case data of Canada file by Kaggle

USING PERIODIC COMMIT 1000 LOAD CSV WITH HEADERS FROM ‘file:///individual-level-cases.csv’ AS line MERGE (p:State:Canada{name:line.province}) CREATE (c:Case:Canada{caseId:line.case_id}) SET c.ageGroup = line.age, c.healthRegion = line.health_region, c.reportDate = line.date_report, c.acquireMethod = line.locally_acquired, c.acquireSource = line.travel_history_country, c.source = line.case_source, c.sex = line.sex, c.state= line.province, c.community = line.community, c.linkedCase = line.linked_case MERGE © -[:LIVES_IN]-> § WITH c,p,split(line.travel_history_country,’,’) AS places UNWIND places AS place MERGE (pl:Place{name:trim(place)}) MERGE © -[:HAS_VISITED]-> (pl)

// 1.2 Load indivudual case file of Korea:

USING PERIODIC COMMIT 1000 LOAD CSV WITH HEADERS FROM ‘file:///PatientInfo.csv’ AS line MERGE (p:State:South Korea{name:line.province}) CREATE (c:Case:South Korea{caseId:line.patient_id}) SET c.ageGroup = line.age, c.healthRegion = line.city, c.reportDate = line.confirmed_date, c.acquireMethod = line.infection_case, c.acquireSource = line.infection_case, c.deceasedDate = line.deceased_date, c.sex = line.sex, c.state= line.province, c.linkedCase = line.infected_by, c.state = line.state MERGE © -[:LIVES_IN]-> §

我们给所有去世者案例增加一个额外的标签:

MATCH(c:Case) WHERE c.state ='deeased’SET c:Deceased

记得创建一些索引:

CREATE INDEX ON:Case(caseId); CREATE INDEX ON:Case(reportDate); CREATE INDEX ON:Case(sex);

完成后的数据模型也非常简单。 image.png

2. 使用Neo4j Bloom定义查询

Bloom可以从Neo4j Desktop安装并启动它,也可安装Bloom服务器插件从Neo4数据库服务器运行。

除了图可视化外,Bloom的美丽之处还在于其自然语言风格的搜索。例如,要找出居住在Seoul的所有案例,只需输入:“ case live_in Seoul”:

image.png

还记得上面的数据模型吗?Case是标签名称,LIVES_IN是关系类型名称。在键入时,Bloom会自动在Neo4j数据库中搜索元数据和索引,以找到最佳匹配项。

Bloom具有许多令人兴奋的功能。我喜欢的一个,并且总是令其他人惊讶的是它的搜索模板(Search Template)功能。搜索模板是一个预定义的Cypher查询,它有一个搜索短语,供其他用户查找和执行。它通常更复杂,并且支持参数。

例如,可以定义以下查询模板以查找某个地点中所有已确认的案例。

image.png

该Cyper模板有2个参数:$ place和$ date。实际的Cypher查询如下:

MATCH path = (c:Case) -[:LIVES_IN]-> (p:State) WHERE c.reportDate = $date AND p.name = $place RETURN path;

其功能应该很好理解。参数$ place的候选值来自State节点的name属性。保存此模板后,只需输入以下内容即可执行该模板: “Show confirmed cases in Seoul on 2020-03-01”,然后按Enter键就可以得到结果。是不是很酷?

3. 关键问题

这里有更多有用的搜索。

问: 案例 #2000000019 是怎样被传染的? 答: Show ultimate source of a case 2000000019.

Cypher: MATCH path = (c:Case{caseId:$case}) -[:INFECTED_FROM*]-> (c1) WITH path, size(nodes(path)) AS distance ORDER BY distance DESC LIMIT 1 RETURN path;

image.png

问: 某个地区的“零号病患”是谁? 答: Show the Super Spreader

Cypher: MATCH (c:Case) WITH c, size(© <-[:INFECTED_FROM]- ()) AS degree ORDER BY degree DESC LIMIT 1 WITH c MATCH path = © <-[:INFECTED_FROM*]- (c2) RETURN path;

image.png

问: 这个地区的确诊病例的发展过程是怎样的? 答: Show all confirmed cases till xxxx-xx-xx (这里连时间滑块都不需要!) Cypher: MATCH (c:Case) WHERE exists(c.reportDate) AND c.reportDate <= $date OPTIONAL MATCH © -[r:INFECTED_FROM]-> (c1) RETURN c,r,c1;

image.png

图中,蓝色的点是确诊案例,较大的灰色点是过时的案例。点之间的红线是感染的途径。在Bloom中可以定义条件样式,显示节点的不同风格。

4. 更进一步:添加位置信息

为了实现更有效的接触追踪,我们需要人们去过的地方和时间的位置数据。感谢我的同事Rik Van Bruggen,他创建了一些模拟的位置数据,以使其成为更具说服力和吸引力的解决方案。

免责声明:在数据集中看到的所有名称都不是真实的人名。

添加位置和场所数据后的图模型: image.png

加载数据的Cypher语句:

//import the persons load csv with headers from "https://docs.google.com/spreadsheets/u/0/d/1R-XVuynPsOWcXSderLpq3DacZdk10PZ8v6FiYGTncIE/export?format=csv&id=1R-XVuynPsOWcXSderLpq3DacZdk10PZ8v6FiYGTncIE&gid=0" as csv create (p:Person {id: csv.PersonId, name:csv.PersonName, healthstatus:csv.Healthstatus, confirmedtime:datetime(csv.ConfirmedTime)});

//import the places load csv with headers from "https://docs.google.com/spreadsheets/u/0/d/1R-XVuynPsOWcXSderLpq3DacZdk10PZ8v6FiYGTncIE/export?format=csv&id=1R-XVuynPsOWcXSderLpq3DacZdk10PZ8v6FiYGTncIE&gid=205425553" as csv create (p:Place {id: csv.PlaceId, name:csv.PlaceName, type:csv.PlaceType, location:point({x: toFloat(csv.Lat), y: toFloat(csv.Long)})});

// Speed up match by creating indices create index on :Place(id); create index on :Place(location); create index on :Place(name); create index on :Person(id); create index on :Person(name); create index on :Person(healthstatus); create index on :Person(confirmedtime);

//import the stays load csv with headers from "https://docs.google.com/spreadsheets/u/0/d/1R-XVuynPsOWcXSderLpq3DacZdk10PZ8v6FiYGTncIE/export?format=csv&id=1R-XVuynPsOWcXSderLpq3DacZdk10PZ8v6FiYGTncIE&gid=1261126668" as csv match (p:Person {id:csv.PersonId}), (pl:Place {id:csv.PlaceId}) create §-[:STAYED_AT]->(s:Stay {id:csv.StayId, starttime:datetime(csv.StartTime), endtime:datetime(csv.EndTime)})-[:LOCATED_AT]->(pl);

5. 追踪确诊病例

问:最近三天谁被感染了?去过什么地方?此外,谁也去过那些地方、并可能会面临更高的风险? 答:Show people who were infected in the last 3 days   Cypher查询模板: MATCH (p:Person) WHERE p.healthstatus = ‘Sick’ AND duration.inDays(p.confirmedtime, datetime()) + datetime() < duration({days:$num}) + datetime() RETURN p;

这里使用了Neo4j的Duration数据类型计算“过去N天”。可以在Neo4j Cypher在线手册中找到关于Duration数据类型的更多详细信息。

结果显示,过去3天中有13人被感染,在66个地方停留过105次。这些地方有其他486位(未经测试或未经确诊)、3249次停留,这些人现在可能已经面临高感染风险。

image.png

问:对于确诊的病例X,谁曾与其接触、因此有高风险? 答: Show everyone who may be infected by X.

Cypher: match (p:Person {name:$name}) with p limit 1 match path= §–(s1:Stay)–(pl:Place)–(s2:Stay)–(p2:Person {healthstatus:“Healthy”}) return path;

image.png

这里只列出部分,不难想象还有很多功能可以方便地实现。

那么,能在地图上看到案例的分布吗?当然,Neo4j的答案(总是)“YES”。Estelle Scifo开发了一个名为Neomap的图应用程序,正好满足这一目的。可以参考Neomap简介中介绍的方法、只需几分钟就可以完成。

image.png

后记

我大约用了24小时,在同事们的帮助下构建了这个演示,包括数据和可视化。的确只是24小时!所有创建的内容都通过Github共享,包括示例数据库、Cypher脚本、包含样式和搜索模板的Bloom透视文件。

对抗疫病的流行会是一项持续不断的工作,不仅需要政府机构和医务人员,而且还需要更多的普通人通过待在家里并遵循健康的生活方式来做出贡献。很棒的是,除了呆在家里,我们可以利用知识和技术(例如图数据库)来做点事情。Neo4j组织的GraphHack Graphs4Good 2 计划的最新进展,已经有许多类似项目正在创造令人鼓舞的成果。

Neo4j支持有益于公众的项目,即Graphs4Good,包括提供Neo4j Enterprise DBMS的免费订阅许可,来支持那些使用Neo4j图数据库技术来构建解决方案的公益型项目。欲知详情,请与 我们联系。

加油,Graph4good!

8 回复

您好,请教一下安装Bloom服务器插件从Neo4数据库服务器运行 这个插件在哪里能下载,官网上并没有下载链接

服务器插件需要激活码运行。如有需要请联系,提供姓名和工作邮件。

@graphway 我想申请激活码,非常感谢 袁超 923044397@qq.com

@graphway 我想申请 bloom 激活码,非常感谢 朱子明 zhushao@nestciao.com

@graphway 老师好,我想申请服务器插件的激活码。姓名:赵思聪 邮箱:dm.cain@hotmail.com

回到顶部