【问题标题】:OrientDB SQL: How to find vertices and create edges between them?OrientDB SQL:如何找到顶点并在它们之间创建边?
【发布时间】:2015-06-19 06:06:48
【问题描述】:

在我的数据库上,我运行以下查询:

SELECT @rid AS module_rid, out('USES').out('BELONGS_TO').@rid AS project_rid FROM MODULES LIMIT 10

我收到了以下回复:

module_rid | project_rid
-----------|----------------
#12:0      | []
#12:1      | []
#12:2      | []
#12:3      |        
#11:48677  | #11:48677 #11:48677 #11:48677 #11:48677 #11:48677 ..More(49)
#12:4      |        
#11:48677  | #11:48677 #11:48677 #11:48677 #11:48677 #11:48677 ..More(49)
#12:5      |        
#11:2526   | #11:2526 #11:2526 #11:47148 #11:47148 #11:25338 ..More(30)
#12:6      | []

如何在模块和它们所依赖的项目(它们至少使用项目的一个模块)之间创建边缘(例如 RELIES_ON)?

【问题讨论】:

    标签: sql graph graph-databases orientdb


    【解决方案1】:
    create class Module extends V
    create class Project extends V
    
    create class Uses extends E
    create class ReliesOn extends E
    
    
    create vertex Module set name = 'm1'
    create vertex Module set name = 'm2'
    create vertex Module set name = 'm3'
    
    create vertex Project set name = 'p1'
    create vertex Project set name = 'p2'
    create vertex Project set name = 'p3'
    
    
    create edge Uses from (select from Module where name = 'm2') to (select from Project where name = 'p1')
    create edge Uses from (select from Module where name = 'm3') to (select from Project where name = 'p2')
    create edge Uses from (select from Module where name = 'm3') to (select from Project where name = 'p3')
    

    我了解上述情况与您的情况略有不同,但我相信这足以了解您的问题的可能解决方案。

    你可以定义一个函数 createEdges 例如,像这样:

    var gdb = orient.getGraph();
    
    if(to.size() != 0){
        var command = "create edge ReliesOn from " + from + " to " + to;
        gdb.command("sql", command);
    }
    return;
    

    现在以下查询将在创建边的同时找到顶点:

    select from (
        select @rid as module_rid, out('Uses').@rid as project_rid from Module
    )
    let $ce = createEdges(module_rid, project_rid)
    

    更新:

    如果您想确保“to”不包含重复项,您可以:

    select from (
        select @rid as module_rid, $aux[0].set.@rid as project_rid from Module
        let $aux = ( select set(out('Uses')) from $current )
    ) 
    let $ce = createEdges(module_rid, project_rid)
    

    【讨论】:

    • 太棒了!我今晚会检查它。
    • @retrography 进展如何?
    • 问题是我在“to”中获得的摆脱列表包含许多重复项,我无法弄清楚如何使此列表独一无二。我试图将“to”视为一个数组,以便可以从中删除重复的值,但似乎该变量未被解释器识别为数组。知道这个集合的性质是什么吗?
    • 这是一个很棒的 hack,但考虑到我在源和目标之间有两个分离度,我需要两级选择嵌套,这会减慢操作到死(1500 万次迭代)涉及)。肯定还是没问题的,因为这是一次性操作,但有没有办法将消除作为一组而不是作为一个列表?
    • 你不能let $aux = ( select set(out('Uses').out('ThatOtherLevel')) from $current )吗?
    【解决方案2】:

    这就是我最终做的:

    用三个参数定义函数createEdgescreateEdges(from, to, type)

    // Check whether "from" is invalid or empty
    if (from instanceof java.util.Collection) {
      if (from.isEmpty()) {
        return [];
      } else {
        var it = from.iterator();
        var obj = it.next();
        if (!(obj instanceof com.orientechnologies.orient.core.id.ORecordId)) {
          throw "Bad Input: createdEdges() only accepts ORecordIds or Collections of ORecordIds";
        }
      } 
    } else if (!(from instanceof com.orientechnologies.orient.core.id.ORecordId)) {
      throw "Bad Input: createdEdges() only accepts ORecordIds or Collections of ORecordIds";
    }
    
    // Check whether "to" is invalid or empty
    if (to instanceof java.util.Collection) {
      if (to.isEmpty()) {
        return [];
      } else {
        var it = to.iterator();
        var obj = it.next();
        if (!(obj instanceof com.orientechnologies.orient.core.id.ORecordId)) {
          throw "Bad Input: createdEdges() only accepts ORecordIds or Collections of ORecordIds";
        }
      } 
    } else if (!(to instanceof com.orientechnologies.orient.core.id.ORecordId)) {
      throw "Bad Input: createdEdges() only accepts ORecordIds or Collections of ORecordIds";
    }
    
    var g = orient.getGraph();
    var cmd = "CREATE EDGE " + type + " FROM " + from + " TO " + to;
    
    return g.command("sql", cmd);
    

    用一个参数定义函数uniquniq(collection)

    if (collection instanceof java.util.Collection) {
      if (collection.isEmpty()) {
        return collection
      } else {
        return new java.util.HashSet(collection)
      }
    } else {
      throw "Bad Input: uniq() only accepts Java collections as input"
    }
    

    现在我可以运行以下 SQL 命令:

    SELECT createEdges(src, dst, 'RELIES_ON') FROM
    (SELECT @rid AS src, uniq(out('USES').out('BELONGS_TO').@rid) AS dst FROM Modules)
    

    这将在模块和它们所依赖的项目之间创建独特的边缘,而且速度非常快。

    感谢@vitorenesduarte,他提供了最初的回应和主要灵感......

    【讨论】:

      猜你喜欢
      • 2018-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多