我有一个像这样的递归数据结构:
@Canonical
static class Person {
String name
Set<Person> knows
}
我有一个代表这种结构的Tinkerpop图:
(Jon) -- knows --> (Billy) -- knows --> (Jane) -- ... -->
\- knows --> (Suzy) -- ... -->
将任意深度的Tinkerpop图表映射到数据结构的最有效方法是什么?
我可以想象使用PathStep
,但似乎应该有一个更好的方法,而且我还没有很好地了解TP3。
def 'build recursive person object'() {
when:
def g = TinkerGraph.open()
def jon = g.addVertex(T.label, 'person', 'name', 'jon')
def bill = g.addVertex(T.label, 'person', 'name', 'bill')
def jane = g.addVertex(T.label, 'person', 'name', 'jane')
jon.addEdge('knows', bill)
bill.addEdge('knows', jane)
Multimap<String, Person> relationships = HashMultimap.create()
g.V().has('name', 'jon')
.as('a')
.jump('b', { traverser -> !traverser.get().out('knows').hasNext() })
.outE('knows')
.inV()
.jump('a')
.as('b')
.path(
Function.<Vertex>identity(),
{ Edge e ->
relationships.put(e.outV().next().value('name') as String,
new Person(e.inV().next().value('name') as String))
} as Function
)
.next()
Person root = new Person('jon')
Stack<Person> people = new Stack<>()
Set<String> alreadySeen = new HashSet<>()
people.push(root)
alreadySeen.add('jon')
while(!people.isEmpty()) {
def person = people.pop()
person.knows = relationships.get(person.name)
for(Person related : person.knows) {
if(alreadySeen.add(related.name))
people.push(related)
}
}
then:
root.name == 'jon'
root.knows*.name == ['bill']
root.knows[0].knows*.name == ['jane']
}
答案 0 :(得分:5)
我会利用Gremlin的tree
结构和一些递归方法调用:
import com.google.common.collect.Iterators;
import com.tinkerpop.gremlin.process.T;
import com.tinkerpop.gremlin.process.Traverser;
import com.tinkerpop.gremlin.process.graph.util.Tree;
import com.tinkerpop.gremlin.structure.Vertex;
import com.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.function.Function;
/**
* @author Daniel Kuppitz (daniel at thinkaurelius.com)
*/
public class App {
static class Person {
private String name;
private Set<Person> knows;
public static Person fromTree(final String name, final Tree node) {
final Person person = new Person(name);
final Tree self = (Tree) node.get(name);
final Set<String> children = (Set<String>) self.keySet();
children.forEach(n -> person.knows.add(Person.fromTree(n, self)));
return person;
}
public Person(final String name) {
this.name = name;
this.knows = new HashSet<>();
}
public String name() {
return name;
}
public Set<Person> knows() {
return knows;
}
}
public static void main(final String[] args) throws Exception {
final TinkerGraph g = TinkerGraph.open();
Vertex jon = g.addVertex(T.label, "person", "name", "jon");
Vertex bill = g.addVertex(T.label, "person", "name", "bill");
Vertex jane = g.addVertex(T.label, "person", "name", "jane");
Vertex suzy = g.addVertex(T.label, "person", "name", "suzy");
jon.addEdge("knows", bill);
bill.addEdge("knows", jane);
bill.addEdge("knows", suzy);
final Tree tree = (Tree) g.V().has("name", "jon").as("x").out("knows").until("x", (Traverser<Vertex> t) ->
t.get().outE("knows").hasNext(), t -> true).tree((Function<Vertex, String>) v -> v.value("name")).cap().next();
if (!tree.isEmpty()) {
final Person p1 = Person.fromTree("jon", tree);
assert p1.name().equals("jon");
assert p1.knows().size() == 1;
final Person p2 = p1.knows().iterator().next();
assert p2.name().equals("bill");
assert p2.knows().size() == 2;
final Iterator<Person> pitty = p2.knows().iterator();
Iterators.all(pitty, p -> (p.name().equals("jane") || p.name().equals("suzy")) && p1.knows().isEmpty());
}
}
}
这种方式归结为一句话:Person.fromTree("jon", tree)