You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Neo4j Aura图谱数据模型问题:查询返回非目标区域犯罪数据

问题解决:Neo4j Aura犯罪图谱查询异常与数值建模优化

一、问题背景

构建犯罪数据图谱时,查询特定AreaUnit(如Glamorgan)会错误返回其他区域(如Glen Innes North)的Victimisations数据,同时需要优化数值数据建模以支持后续聚合与对比分析。

二、CSV样本数据

ANZSOC Group,YYYY,Territorial Authority,Area Unit,Victimisations
Aggravated Robbery,2024,Auckland,Glen Innes North,4
Aggravated Sexual Assault,2024,Auckland,Glamorgan,1
Blackmail and Extortion,2024,Auckland,Glen Innes North,4
Common Assault,2024,Auckland,Glen Innes North,2
Illegal Use of a Motor Vehicle,2024,Auckland,Glamorgan,5
Illegal Use of a Motor Vehicle,2024,Auckland,Glen Innes North,17
Serious Assault Not Resulting in Injury,2024,Auckland,Glen Innes North,3
Serious Assault Resulting in Injury,2024,Auckland,Glen Innes North,7
"Theft (Except Motor Vehicles), N.E.C.",2024,Auckland,Glamorgan,1
"Theft (Except Motor Vehicles), N.E.C.",2024,Auckland,Glen Innes North,7
Theft From a Person (Excluding By Force),2024,Auckland,Glen Innes North,1
Theft of Motor Vehicle Parts or Contents,2024,Auckland,Glamorgan,4
Theft of Motor Vehicle Parts or Contents,2024,Auckland,Glen Innes North,17
"Unlawful Entry With Intent/Burglary, Break and Enter",2024,Auckland,Glamorgan,7
"Unlawful Entry With Intent/Burglary, Break and Enter",2024,Auckland,Glen Innes North,34

三、原数据模型创建脚本

pre_ingest:
  - CREATE CONSTRAINT crimetype_anzsocgroup IF NOT EXISTS FOR (n:CrimeType) REQUIRE n.anzsocGroup IS UNIQUE;
  - CREATE CONSTRAINT territorialauthority_cityname IF NOT EXISTS FOR (n:TerritorialAuthority) REQUIRE n.cityName IS UNIQUE;
  - CREATE CONSTRAINT areaunit_areaname IF NOT EXISTS FOR (n:AreaUnit) REQUIRE n.areaName IS UNIQUE;
files:
- chunk_size: 100
  cql: |
    WITH $dict.rows AS rows
    UNWIND rows AS row
    MERGE (n:CrimeType {anzsocGroup: row.`ANZSOC Group`})
  url: $BASE/
- chunk_size: 100
  cql: |
    WITH $dict.rows AS rows
    UNWIND rows AS row
    MERGE (n:TerritorialAuthority {cityName: row.`Territorial Authority`})
  url: $BASE/
- chunk_size: 100
  cql: |
    WITH $dict.rows AS rows
    UNWIND rows AS row
    MERGE (n:AreaUnit {areaName: row.`Area Unit`})
  url: $BASE/
- chunk_size: 100
  cql: |-
    WITH $dict.rows AS rows
    UNWIND rows AS row
    MERGE (n:CrimeEvent {year:toIntegerOrNull(row.YYYY), victimisation:toIntegerOrNull(row.Victimisations)})
  url: $BASE/
- chunk_size: 100
  cql: |
    WITH $dict.rows AS rows
    UNWIND rows as row
    MATCH (source:TerritorialAuthority {cityName: row.`Territorial Authority`})
    MATCH (target:AreaUnit {areaName: row.`Area Unit`})
    MERGE (source)-[n:HAS_SUB_REGION]->(target)
  url: $BASE/
- chunk_size: 100
  cql: |
    WITH $dict.rows AS rows
    UNWIND rows as row
    MATCH (areaUnit:AreaUnit {areaName: row.`Area Unit`})
    MATCH (crimeType:CrimeType {anzsocGroup: row.`ANZSOC Group`})
    MATCH (crimeEvent:CrimeEvent {year:toIntegerOrNull(row.YYYY), victimisation:toIntegerOrNull(row.Victimisations)})
    MERGE (areaUnit)-[c:HAS_CRIME]->(crimeType)-[t:HAS_CRIME_COUNT]->(crimeEvent)
  url: $BASE/

四、查询异常情况

原查询语句

MATCH path = (n:AreaUnit {areaName:"Glamorgan"})-[c:HAS_CRIME]->(t:CrimeType)-[:HAS_CRIME_COUNT]->(e:CrimeEvent)
RETURN path

错误结果

返回了Glamorgan区域不存在的Victimisations数值(如17、7、34等,实际属于Glen Innes North),导致数据混淆。

五、问题解决与优化方案

1. 修复查询异常:调整数据模型关系

原模型核心问题是CrimeEvent仅用year和victimisation作为唯一标识,不同区域的同数值事件被合并,进而错误关联到所有同类型犯罪的区域。

修正后的建模脚本(推荐方案:关系属性存储统计值)

删除原CrimeEvent节点创建步骤,将统计数据存储在AreaUnit与CrimeType的关联关系中:

pre_ingest:
  - CREATE CONSTRAINT crimetype_anzsocgroup IF NOT EXISTS FOR (n:CrimeType) REQUIRE n.anzsocGroup IS UNIQUE;
  - CREATE CONSTRAINT territorialauthority_cityname IF NOT EXISTS FOR (n:TerritorialAuthority) REQUIRE n.cityName IS UNIQUE;
  - CREATE CONSTRAINT areaunit_areaname IF NOT EXISTS FOR (n:AreaUnit) REQUIRE n.areaName IS UNIQUE;
files:
- chunk_size: 100
  cql: |
    WITH $dict.rows AS rows
    UNWIND rows AS row
    MERGE (n:CrimeType {anzsocGroup: row.`ANZSOC Group`})
  url: $BASE/
- chunk_size: 100
  cql: |
    WITH $dict.rows AS rows
    UNWIND rows AS row
    MERGE (n:TerritorialAuthority {cityName: row.`Territorial Authority`})
  url: $BASE/
- chunk_size: 100
  cql: |
    WITH $dict.rows AS rows
    UNWIND rows AS row
    MERGE (n:AreaUnit {areaName: row.`Area Unit`})
  url: $BASE/
- chunk_size: 100
  cql: |
    WITH $dict.rows AS rows
    UNWIND rows as row
    MATCH (source:TerritorialAuthority {cityName: row.`Territorial Authority`})
    MATCH (target:AreaUnit {areaName: row.`Area Unit`})
    MERGE (source)-[n:HAS_SUB_REGION]->(target)
  url: $BASE/
- chunk_size: 100
  cql: |
    WITH $dict.rows AS rows
    UNWIND rows as row
    MATCH (areaUnit:AreaUnit {areaName: row.`Area Unit`})
    MATCH (crimeType:CrimeType {anzsocGroup: row.`ANZSOC Group`})
    MERGE (areaUnit)-[r:HAS_CRIME_STATS {year: toIntegerOrNull(row.YYYY), victimisations: toIntegerOrNull(row.Victimisations)}]->(crimeType)
  url: $BASE/

修正后的查询语句

MATCH (n:AreaUnit {areaName:"Glamorgan"})-[r:HAS_CRIME_STATS]->(t:CrimeType)
RETURN n.areaName, t.anzsocGroup, r.year, r.victimisations

2. 适合聚合与对比的数值数据建模方法

方法一:关系属性存储统计值(推荐)

将year、victimisations存储在关联关系中,便于直接按维度聚合:

  • 按区域统计年度总受害数:
    MATCH (a:AreaUnit)-[r:HAS_CRIME_STATS]->()
    WHERE r.year = 2024
    RETURN a.areaName, SUM(r.victimisations) AS total_victimisations
    ORDER BY total_victimisations DESC
    
  • 对比同一犯罪类型在不同区域的数值:
    MATCH (a:AreaUnit)-[r:HAS_CRIME_STATS]->(t:CrimeType {anzsocGroup:"Illegal Use of a Motor Vehicle"})
    WHERE r.year = 2024
    RETURN a.areaName, r.victimisations
    ORDER BY r.victimisations DESC
    

方法二:节点存储预聚合数据

如果需要存储多维度聚合结果(如月度、季度统计),创建CrimeAggregation节点:

MERGE (a:AreaUnit {areaName:"Glamorgan"})
MERGE (t:CrimeType {anzsocGroup:"Illegal Use of a Motor Vehicle"})
MERGE (agg:CrimeAggregation {
    areaName: a.areaName,
    crimeType: t.anzsocGroup,
    year: 2024,
    totalVictimisations: 5,
    avgMonthly: 0.42
})
MERGE (a)-[:HAS_AGGREGATE]->(agg)
MERGE (t)-[:AGGREGATED_FOR]->(agg)

该方式适合预计算聚合结果,提升查询效率。

方法三:图算法动态聚合分析

对于复杂对比(如区域犯罪相似度),使用Neo4j GDS库计算:

CALL gds.nodeSimilarity.stream({
    nodeProjection: 'AreaUnit',
    relationshipProjection: {
        HAS_CRIME_STATS: {
            type: 'HAS_CRIME_STATS',
            properties: 'victimisations',
            orientation: 'REVERSE'
        }
    }
})
YIELD node1, node2, similarity
RETURN gds.util.asNode(node1).areaName AS area1, gds.util.asNode(node2).areaName AS area2, similarity
ORDER BY similarity DESC

内容的提问来源于stack exchange,提问作者Gelo Bee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 09:07:32