我正在创建一个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
可以是某个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 )
并返回布尔值。
从哪里开始为更简单的图形创建查询语言? 注意:我没有使用现有图库的选项,我将拥有数十万个节点,以及边缘..
答案 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”)返回查询的那一点。