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

适配JanusGraph:如何聚合Gremlin遍历结果统计时段内唯一车辆数

问题背景

给定以下使用TinkerPop 3.7.2创建的车辆停放图结构:

// 车辆停放图结构
g = TinkerGraph.open().traversal();

// 创建3个停车场,每个停车场3个车位
for (parking in ['Mayfair', 'Euston', 'GareDuNord']) {
    g.addV('parking').property('name', parking).iterate();
    for (slot = 1; slot < 4; slot++) {
        var slotName = String.format('%s %s', parking, slot);
        g.addV('slot').property('name', slotName).
        addE('hasSlot').from(__.V().has('parking', 'name', parking)).iterate();
    }
}

// 关联停车场与所属城市
g.addV('city').property('name', 'London').addE('hasParking').to(__.V().has('parking', 'name', 'Mayfair'));
g.V().has('city', 'name', 'London').addE('hasParking').to(__.V().has('parking', 'name', 'Euston'));
g.addV('city').property('name', 'Paris').addE('hasParking').to(__.V().has('parking', 'name', 'GareDuNord'));

// 查看所有停车场和车位(注释)
// g.V().hasLabel('parking').bothE().elementMap()

// 创建3辆车及其不同时间的停放记录
locationMaps = [
    'v1': ['Mayfair 1', 'Euston 2', 'GareDuNord 3'],
    'v2': ['Mayfair 2', 'Mayfair 3', 'Mayfair 1'],
    'v3': ['Mayfair 3', null, 'Euston 1']
]
for (lMap in locationMaps) {
    vehicleName = lMap.key;
    g.addV('vehicle').property('name', vehicleName).iterate();
    locations = lMap.value;
    t = 1;
    for (locationName in locations) {
        if (locationName != null) {
            g.V().has('vehicle', 'name', vehicleName).
                addE('parkedAt').to(__.V().has('slot', 'name', locationName)).
                property('time', t).iterate();
        }
        t += 1;
    }
}

// 查看所有停放事件(注释)
// g.E().hasLabel('parkedAt').elementMap()
当前尝试与问题

我写出的Gremlin查询能得到去重的城市-停车场-车辆组合:

// 查询时间区间内各城市停车场的唯一车辆数(当前版本)
g.V().hasLabel('city').
    out('hasParking').
    out('hasSlot').
    inE('parkedAt').has('time', P.lte(2)).has('time', P.gte(1)).
    project('city', 'parking', 'vehicle').
    by(inV().in('hasSlot').in('hasParking').values('name')).
    by(inV().in('hasSlot').values('name')).
    by(outV().values('name')).
    dedup()

输出结果:

==>[city:London,parking:Mayfair,vehicle:v1]
==>[city:London,parking:Mayfair,vehicle:v2]
==>[city:London,parking:Mayfair,vehicle:v3]
==>[city:London,parking:Euston,vehicle:v1]

但我需要按城市-停车场分组统计唯一车辆数,预期输出:

==>[city:London,parking:Mayfair,count:3]
==>[city:London,parking:Euston,count:1]

我还尝试用path()方法获取数据:

g.V().hasLabel('city').
    out('hasParking').
    out('hasSlot').
    inE('parkedAt').has('time', P.lte(2)).has('time', P.gte(1)).
    outV().
    path().
    by('name').         // 城市名称
    by('name').         // 停车场名称
    by(constant('')).   // 忽略车位
    by(constant('')).   // 忽略停放边
    by('name').         // 车辆名称
    dedup()

结果类似,但缺少映射键,仍无法实现按城市和停车场统计唯一车辆数的需求。另外实际场景中有时需要从单个路径步骤里获取多个信息,不知道该怎么操作。

环境限制

查询将在JanusGraph服务器上通过gremlin-python执行,有以下限制:

  • 标签未建立索引,不能以g.V().hasLabel('vehicle')作为查询起点;
  • 无法使用lambda表达式。
解决方案

以下是符合限制的Gremlin查询,可实现指定时间区间内各城市停车场的唯一车辆停放数量统计:

方案一:利用节点标记+嵌套分组

g.V().hasLabel('city').
    out('hasParking').as('parking').
    out('hasSlot').
    inE('parkedAt').has('time', between(1,2)).
    outV().as('vehicle').
    // 按城市、停车场分组,统计唯一车辆数
    group().
        by(__.select('parking').in('hasParking').values('name')). // 城市
        by(group().
            by(__.select('parking').values('name')). // 停车场
            by(__.select('vehicle').values('name').dedup().count())).
    // 展开分组并整理成预期格式
    unfold().
    select(values).unfold().
    project('city', 'parking', 'count').
        by(select(keys)).
        by(select(keys)).
        by(select(values))

方案二:路径提取+分组统计

g.V().hasLabel('city').as('city').
    out('hasParking').as('parking').
    out('hasSlot').
    inE('parkedAt').has('time', P.gte(1).and(P.lte(2))).
    outV().as('vehicle').
    path().by('name').
    // 提取路径中的关键信息
    map(select('city', 'parking', 'vehicle')).
    dedup().
    // 按城市、停车场分组统计
    group().
        by('city').
        by(group().
            by('parking').
            by(count())).
    // 整理输出格式
    unfold().select(values).unfold().
    project('city', 'parking', 'count').
        by(constant(select(keys).next())).
        by(select(keys)).
        by(select(values))

核心逻辑说明

  1. 节点标记:通过as()标记城市、停车场、车辆节点,避免重复遍历图结构,提升查询效率;
  2. 去重处理:用dedup()确保同一车辆在同一城市-停车场下仅被统计一次;
  3. 嵌套分组:通过两层group()实现先按城市分组,再按停车场分组统计唯一车辆数;
  4. 格式整理:最后用project()将分组结果转换为预期的键值对格式,完全符合环境限制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 17:17:03