创建图形查询语言(节点/边缘/ HyperEdge)

时间:2012-11-29 15:52:09

标签: java graph visitor-pattern edges

我正在创建一个API,它使用其他属性和帮助程序封装JPA个对象。我不希望用户访问数据库,因为我必须为API的使用者提供某些查询功能。

我有以下内容:

Node1(w/ attributes) -- > Edge1(w/ attr.) -- > Node2(w/ attr.)

Node1(w/ attributes) -- > |
Node2(w/ attributes) -- > |  -- > HyperEdge1(w/ attr.)
Node3(w/ attributes) -- > |

Node/Edge/HyperEdge example

基本上Node可以是某个type,这将决定可用的属性类型。所以我需要能够根据不同的类型和属性查询这些“路径”。

例如:从节点开始,找到路径typeA > typeB & attr1 > typeC

所以我需要做一些简单的事情,并能够将查询编写为字符串,或者可能是构建器模式样式。

到目前为止,我设置的访问者模式是为了遍历Nodes / Edges / HyperEdges,这允许进行某种查询,但这并不是很简单,因为你必须为新类型创建一个新的访问者查询。

这是我到目前为止的实施:

    ConditionImpl hasMass = ConditionFactory.createHasMass( 2.5 );
    ConditionImpl noAttributes = ConditionFactory.createNoAttributes();

    List<ConditionImpl> conditions = new ArrayList<ConditionImpl>();
    conditions.add( hasMass );
    conditions.add( noAttributes );

    ConditionVisitor conditionVisitor = new ConditionVisitor( conditions );
    node.accept( conditionVisitor );

    List<Set<Node>> validPaths = conditionVisitor.getValidPaths();

上面的代码执行一个查询,检查起始节点的质量是否为2.5,链接节点(子节点)是否没有属性。访问者执行condition.check( Node )并返回布尔值。


从哪里开始为更简单的图形创建查询语言? 注意:我没有使用现有图库的选项,我将拥有数十万个节点,以及边缘..

2 个答案:

答案 0 :(得分:1)

就个人而言,我喜欢访问者模式的想法,但访问所有节点可能会变得昂贵。

查询界面:如果用户/其他开发人员正在使用它,我会使用一个带有可读方法名称的构建器样式界面:

    Visitor v = QueryBuilder
                  .selectNodes(ConditionFactory.hasMass(2.5))
                  .withChildren(ConditionFactory.noAttributes())
                  .buildVisitor();
    node.accept(v);
    List<Set<Node>> validPaths = v.getValidPaths();

正如上面所指出的,这或多或少只是你已经拥有的语法糖(但糖有所不同)。我会从实际检查(或是)条件的代码中分离“移动图形”的代码(如“检查访问节点是否满足条件”或“检查连接节点是否满足条件”)。此外,在构建条件和/或使用复合材料时:

    // Select nodes with mass 2.5, follow edges with both conditions fulfilled and check that the children on these edges have no attributes. 
    Visitor v = QueryBuilder
                  .selectNodes(ConditionFactory.hasMass(2.5))
                  .withEdges(ConditionFactory.and(ConditionFactory.freestyle("att1 > 12"), ConditionFactory.freestyle("att2 > 23")) 
                  .withChildren(ConditionFactory.noAttributes())
                  .buildVisitor();

(我之所以使用“自由式”是因为现在缺少创造力,但其意图应该是明确的)节点通常这可能是两个不同的接口,以便不构建奇怪的查询。

    public interface QueryBuilder {
         QuerySelector selectNodes(Condition c);
         QuerySelector allNodes();
    }

    public interface QuerySelector {
         QuerySelector withEdges(Condition c);
         QuerySelector withChildren(Condition c);
         QuerySelector withHyperChildren(Condition c);
         // ...
         QuerySelector and(QuerySelector... selectors);
         QuerySelector or(QuerySelector... selectors);

         Visitor buildVisitor();
    }       

使用这种语法糖使得查询可以从源代码中读取,而不必强制您实现自己的数据查询语言。 QuerySelector实现将负责围绕访问的节点“移动”,而Conditition实现将检查条件是否匹配。

这种方法的明显缺点是,您需要预见接口中的大多数查询,并且需要已经实现它们。

节点数量可扩展性:您可能需要添加某种索引以加速查找“有趣”节点。弹出的一个想法是向图中添加(对于每个索引)一个图层,其中每个节点为“索引变量”建模一个不同的属性设置。然后,正常边缘可以将这些索引节点与原始图中的节点连接起来。然后索引上的超边缘可以构建一个较小的网络来搜索。当然,仍然存在将索引存储在具有attributeValue -> node映射的类似地图的结构中的无聊方式。无论如何,这可能比上面的想法更有效。

如果你有某种索引,请确保索引也可以接收访问者,这样就不必访问图中的所有节点。

答案 1 :(得分:0)

听起来你除了一些语法糖之外还有其他所有的东西。

如上所示创建整个列表的不可变样式如何

Visitor v = Visitor.empty
    .hasMass(2.5)
    .edge()
    .node()
    .hasNoAttributes();

您可以使用此样式创建任何类型的线性查询模式;如果你添加一些额外的状态,你甚至可以通过例如分支查询setName(“A”)和更晚的.node(“A”)返回查询的那一点。