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

Gremlin JS:如何对比遍历中前后顶点属性实现指定图查询?

Gremlin JS 查询朋友的朋友(同姓且非直接好友)异常问题

需求

查询人物属性图中满足以下条件的顶点:

  • 是指定用户的朋友的朋友
  • 姓氏(lastName)与指定用户相同
  • 不是指定用户的直接好友

尝试的查询代码

我试过几种Gremlin JS写法,均未报错但结果不符合预期:

// 写法1:用sideEffect缓存姓氏
let query = g.V(userId)
      .sideEffect(
        __.values("lastName")
          .as("userLastName")
      )
      .out("isFriendsWith")
      .out("isFriendsWith")
      .where(
        __.has("lastName", __.select("userLastName"))
      )
      .where(
        __.not(
          __.in_("isFriendsWith").hasId(userId)
        )
      )

// 写法2:用as("user")保留初始用户引用
g.V(userId)
      .as("user")
      .out("isFriendsWith")
      .out("isFriendsWith")
      .where(
        __.has("lastName", __.select("user").values("lastName"))
      )
      .where(
        __.not(
          __.in_("isFriendsWith").hasId(userId)
        )
      )

// 写法3:直接对比values
g.V(userId)
      .as("user")
      .out("isFriendsWith")
      .out("isFriendsWith")
      .where(
        __.values('lastName').is(__.select("user").values("lastName"))
      )
      .where(
        __.not(
          __.in_("isFriendsWith").hasId(userId)
        )
      )

测试数据初始化

以下测试数据中,预期返回Billy(而非John、Sarah或Sally):

await g.addV("user").property("firstName", "John").property("lastName", "Doe")
      .as('john')
      .addV("user").property("firstName", "Sally").property("lastName", "Doe")
      .as('sally')
      .addV("user").property("firstName", "Billy").property("lastName", "Doe")
      .as('billy')
      .addV("user").property("firstName", "Sarah").property("lastName", "Johnson")
      .as('sarah')
      .addE("isFriendsWith")
      .from_(__.select('john'))
      .to(__.select('sally'))
      .addE("isFriendsWith")
      .from_(__.select('sally'))
      .to(__.select('billy'))
      .addE("isFriendsWith")
      .from_(__.select('sally'))
      .to(__.select('sarah'))

问题现象

上述写法要么返回空结果,要么过滤条件失效;但硬编码姓氏(比如直接写has("lastName", "Doe"))时,查询能正常返回Billy,说明数据逻辑没问题,只是属性引用的写法有误。另外Gremlin JS文档较少,对其类型机制不太清楚,不确定Java文档是否适用。


解决方案

可以通过先缓存目标姓氏,再在遍历中对比的方式,避免路径引用的问题,或者使用match语法明确声明遍历关系:

方案1:提前缓存姓氏

const query = g.V(userId)
  // 先获取并缓存目标用户的姓氏
  .values("lastName")
  .as("targetLastName")
  // 回到目标用户,开始遍历朋友的朋友
  .V(userId)
  .out("isFriendsWith")
  .out("isFriendsWith")
  // 对比姓氏
  .where(__.values("lastName").is(__.select("targetLastName")))
  // 排除直接好友
  .where(__.not(__.in_("isFriendsWith").hasId(userId)))
  // 去重(避免同一节点被多次匹配)
  .dedup()

方案2:使用match语法明确关系

match语法更清晰地声明了各节点之间的关联,避免路径引用的歧义:

const query = g.match(
  __.as("user").hasId(userId),
  __.as("user").out("isFriendsWith").as("directFriend"),
  __.as("directFriend").out("isFriendsWith").as("friendOfFriend"),
  // 匹配姓氏相同的条件
  __.as("user").values("lastName").as("userLastName"),
  __.as("friendOfFriend").values("lastName").is(__.select("userLastName")),
  // 排除直接好友
  __.not(__.as("user").out("isFriendsWith").as("friendOfFriend"))
)
.select("friendOfFriend")
.dedup()

问题原因

之前的写法中,当遍历到朋友的朋友节点时,select("user")的路径引用可能因Gremlin的遍历上下文丢失,导致无法正确获取初始用户的姓氏。通过提前缓存姓氏或使用match明确节点关系,可以避免这种上下文丢失的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 12:23:20