Java 实现可导航图形的优雅方式?

Java 实现可导航图形的优雅方式?,java,python,graph-databases,ognl,object-graph,Java,Python,Graph Databases,Ognl,Object Graph,这是一个设计问题。我正在努力为我面临的问题创建一个概念模型 我有一个许多对象的图表(这取决于你希望你的表现在哪里 如果您想要快速查询,并且不介意在添加对象时有一点额外的时间/内存,保留一个指向具有特定属性的对象的指针数组/列表可能是一个好主意(特别是如果您在设计时知道可能的属性)。然后,在添加新对象时,说: {name: A, attributes:{black, thin, invalid}, connections: {B,C}} 添加指向黑色列表、精简列表和无效列表的新指针。快速查询连

这是一个设计问题。我正在努力为我面临的问题创建一个概念模型


我有一个许多对象的图表(这取决于你希望你的表现在哪里

如果您想要快速查询,并且不介意在添加对象时有一点额外的时间/内存,保留一个指向具有特定属性的对象的指针数组/列表可能是一个好主意(特别是如果您在设计时知道可能的属性)。然后,在添加新对象时,说:

{name: A, attributes:{black, thin, invalid}, connections: {B,C}} 
添加指向
黑色
列表、
精简
列表和
无效
列表的新指针。快速查询连接可能需要保留一个指针列表/数组作为
对象
类的成员。然后在创建对象时,为正确的对象添加指针

如果您不介意较慢的查询并且希望在添加对象时优化性能,则使用链表可能是一种更好的方法。您可以在所有对象之间循环,检查每个对象是否满足查询条件

在这种情况下,如果(正如您的问题所表明的)您希望执行多级查询(即
a.connections[0]。connections[0]
,则保留连接的成员指针仍然是一个好主意。如果通过嵌套循环执行,将导致极低的性能。)


希望这会有所帮助,这实际上取决于您希望最频繁调用的查询类型。

用Java表达这一点没有问题。只需定义表示节点集的类。假设有一组固定的属性,它可能会如下所示:

enum Attribute {
    BLACK, WHITE, THIN, VALID /* etc. */ ;
}
class Node {
    public final String name;
    public final EnumSet<Attribute> attrs
        = EnumSet.noneOf(Attribute.class);
    public final NodeSet connections
        = new NodeSet();

    public Node(String name)
    {
        this.name = name;
    }

    // ... methods for adding attributes and connections
}

听起来你有一些对象模型,你想以不同的方式查询。一种解决方案是使用Java创建模型,然后使用脚本语言以不同的方式支持对该模型的查询。例如:我建议使用Java+Groovy

您可以为模型使用以下Java类

public class Node {

    private String name;
    private final Set<String> attributes = new HashSet<String>();
    private final List<Node> connections = new ArrayList<Node>();

    // getter / setter for all
}
公共类节点{
私有字符串名称;
私有最终集属性=新HashSet();
私有最终列表连接=新建ArrayList();
//所有人的接受者/接受者
}
然后,应使用正确填充的“connections”属性填充此类对象的列表

要支持不同类型的脚本,您需要做的是为脚本创建上下文,然后填充此上下文。上下文基本上是一个映射。映射的键成为脚本可用的变量。诀窍是填充此上下文以支持您的查询要求

例如,在groovy中,绑定是上下文(请参阅)。因此,如果您以以下方式填充它,您的查询需求将得到满足

上下文/绑定映射

1. <Node name(String), Node object instance(Node)>
2. <Attribute name(String), list of nodes having this attribute(List<Node>)>
1。
2.

当您计算一个名为“a.connections[0]”的脚本时,将在绑定中查找针对键“a”存储的对象。然后将访问返回的对象“connections”属性。因为这是一个列表,所以“[0]'在groovy中允许使用此语法。这将返回索引0处的对象。同样,为了支持查询要求,您需要填充上下文。

我认为使用图形解决此问题是有意义的。您提到了使用图形数据库的可能性,我认为这将使您能够更好地关注您的问题一个简单的内存中的图形,如来自项目的,将是一个很好的开始

通过使用TinkerGraph,您可以访问名为(另请参阅)的查询语言这有助于回答您在文章中提出的问题。下面是中的一个Gremlin会话,它展示了如何构造您所展示的图,以及一些示例图遍历,这些示例图遍历可以得到您想要的答案……第一部分简单地构造了您的示例图:

gremlin> g = new TinkerGraph()
==>tinkergraph[vertices:0 edges:0]
gremlin> a = g.addVertex("A",['color':'black','width':'thin','status':'invalid']) 
==>v[A]
gremlin> b = g.addVertex("B",['color':'white','width':'thin','status':'valid'])  
==>v[B]
gremlin> c = g.addVertex("C",['color':'black','width':'thick','status':'invalid'])
==>v[C]
gremlin> a.addEdge('connection',b)                                                
==>e[0][A-connection->B]
gremlin> a.addEdge('connection',c)                                                
==>e[1][A-connection->C]
gremlin> b.addEdge('connection',a)                                                
==>e[2][B-connection->A]
gremlin> c.addEdge('connection',a)                                                
==>e[3][C-connection->A]
gremlin> c.addEdge('connection',b)                                                
==>e[4][C-connection->B]
现在查询:

// black - yields [A,C]
gremlin> g.V.has('color','black')
==>v[A]
==>v[C]

// black.thick - yields C
gremlin> g.V.has('width','thick')
==>v[C]

// A.connections[0].connections[0] - yields A
gremlin> a.out.out[0]
==>v[A]

// black[0].connections[0] - yields B
gremlin> g.V.has('color','black')[0].out[0]
==>v[B]

如果您不熟悉堆栈,这种方法确实会引入一些学习曲线,但我认为您会发现,图形适合作为许多问题的解决方案,并且对TinkerPop堆栈有一些经验通常会对您遇到的其他场景有所帮助。

是否有任何标准的、众所周知的数据结构可以组合要提供您需要的功能?@Thorbjørnravandersen,如果我知道我不会问您。:)我正在考虑类似JQuery的功能,它允许通过ID(名称)或属性导航DOM元素
$('forma[href~=“value”]”)
我觉得你应该写几个例子,详细说明你需要做的各种事情。这样做的原因是,在我看来,您尚未全面了解这项计划要解决的问题。
class NodeSet extends LinkedHashSet<Node> {
    /**
     * Filters out nodes with at least one of the attributes.
     */
    public NodeSet with(Attribute... as) {
        NodeSet out = new NodeSet();
        for(Node n : this) {
            for(a : as)
                if (n.attrs.contains(a)) {
                    out.add(n);
                    break;
                }
        }
        return out;
    }

    /**
     * Returns all nodes connected to this set.
     */
    public NodeSet connections() {
        NodeSet out = new NodeSet();
        for(Node n : this)
            out.addAll(n.connections);
        return out;
    }

    /**
     * Returns the first node in the set.
     */
    public Node first() {
        return iterator().next();
    }
}
all.with(BLACK).first().connections()
public class Node {

    private String name;
    private final Set<String> attributes = new HashSet<String>();
    private final List<Node> connections = new ArrayList<Node>();

    // getter / setter for all
}
1. <Node name(String), Node object instance(Node)>
2. <Attribute name(String), list of nodes having this attribute(List<Node>)>
gremlin> g = new TinkerGraph()
==>tinkergraph[vertices:0 edges:0]
gremlin> a = g.addVertex("A",['color':'black','width':'thin','status':'invalid']) 
==>v[A]
gremlin> b = g.addVertex("B",['color':'white','width':'thin','status':'valid'])  
==>v[B]
gremlin> c = g.addVertex("C",['color':'black','width':'thick','status':'invalid'])
==>v[C]
gremlin> a.addEdge('connection',b)                                                
==>e[0][A-connection->B]
gremlin> a.addEdge('connection',c)                                                
==>e[1][A-connection->C]
gremlin> b.addEdge('connection',a)                                                
==>e[2][B-connection->A]
gremlin> c.addEdge('connection',a)                                                
==>e[3][C-connection->A]
gremlin> c.addEdge('connection',b)                                                
==>e[4][C-connection->B]
// black - yields [A,C]
gremlin> g.V.has('color','black')
==>v[A]
==>v[C]

// black.thick - yields C
gremlin> g.V.has('width','thick')
==>v[C]

// A.connections[0].connections[0] - yields A
gremlin> a.out.out[0]
==>v[A]

// black[0].connections[0] - yields B
gremlin> g.V.has('color','black')[0].out[0]
==>v[B]