Gremlin查询:按startDate取前10顶点且每个groupId最多3个
Gremlin 按序筛选分组限制的顶点
针对你需要按startDate排序取前10个顶点、且每个groupId最多保留3个的需求,这里提供一个能严格按顺序处理、避免获取旧数据的Gremlin查询方案:
g.V() // 按startDate排序(asc升序,最新的放后面;若要最新优先用desc) .order().by('startDate', asc) // 先折叠为列表再展开,确保后续逐个按顺序处理 .fold().unfold() // 注入空Map,用来记录每个groupId已选的数量 .inject([:]) .flatMap( union( // 保留当前的计数Map identity(), // 判断当前顶点的groupId计数是否未满3 choose( select(keys).by('groupId').where(neq(3)), // 计数未满:保留顶点,同时更新计数Map union( identity(), select(keys).by('groupId').math('+1').store(keys) ), // 计数已满:跳过该顶点,计数Map不变 identity() ) ).limit(2) // 只保留计数Map和可能被选中的顶点 ) // 筛选出被保留的顶点(排除计数Map) .where(hasLabel('vertex')) // 最终取前10个符合条件的顶点 .limit(10) // 输出需要的属性(可根据需求调整) .project('id', 'groupId') .by(id()) .by('groupId')
逻辑解释
- 排序与遍历准备:先把所有顶点按
startDate排序,再通过fold().unfold()确保后续是逐个按排序顺序处理,不会打乱顺序。 - 分组计数维护:用
inject([:])初始化一个空Map,用来实时记录每个groupId已经选中的顶点数量。 - 逐个判断筛选:遍历每个顶点时,检查对应
groupId的计数:- 若计数小于3,保留该顶点,并把计数加1;
- 若计数已到3,直接跳过该顶点,不更新计数。
- 最终限制数量:筛选出所有符合条件的顶点后,取前10个返回。
针对你的示例验证
按你给出的排序序列{1,1},{2,2},{3,1},{4,1},{5,1},{6,2},{7,1},{8,2},查询会按以下逻辑处理:
- 顶点1(groupId=1):计数1,保留;
- 顶点2(groupId=2):计数1,保留;
- 顶点3(groupId=1):计数2,保留;
- 顶点4(groupId=1):计数3,保留;
- 顶点5(groupId=1):计数已满,跳过;
- 顶点6(groupId=2):计数2,保留;
- 顶点7(groupId=1):计数已满,跳过;
- 顶点8(groupId=2):计数3,保留;
最终得到的结果就是1,3,4和2,6,8,完全符合你的需求。
注意事项
- 若需要最新的startDate优先,把
order().by('startDate', asc)改为order().by('startDate', desc)即可; - 确保
startDate属性的类型是可排序的(比如日期、时间戳类型),避免排序异常; limit(10)是最终返回的总顶点数限制,当选够10个符合条件的顶点后,查询会停止遍历,提升效率。
内容的提问来源于stack exchange,提问作者user3338268
相关产品推荐
相关产品推荐

