From 5d4e22498da75523322e1b40c532062b0faaf596 Mon Sep 17 00:00:00 2001 From: Matei Chiperi Date: Wed, 27 Aug 2014 13:42:56 -0700 Subject: [PATCH] Converted the Not operator to a complement operator in terms of functionality. --- graph/iterator/not_iterator.go | 51 +++++++++++++++++++++-------------------- query/gremlin/build_iterator.go | 28 ++++++---------------- query/gremlin/traversals.go | 4 ++-- 3 files changed, 35 insertions(+), 48 deletions(-) diff --git a/graph/iterator/not_iterator.go b/graph/iterator/not_iterator.go index 2c6182f..0b35406 100644 --- a/graph/iterator/not_iterator.go +++ b/graph/iterator/not_iterator.go @@ -5,19 +5,21 @@ import "github.com/google/cayley/graph" // Not iterator acts like a set difference between the primary iterator // and the forbidden iterator. type Not struct { - uid uint64 - tags graph.Tagger - primaryIt graph.Iterator - forbiddenIt graph.Iterator - result graph.Value - runstats graph.IteratorStats + uid uint64 + tags graph.Tagger + ts graph.TripleStore + primaryIt graph.Iterator + allIt graph.Iterator + result graph.Value + runstats graph.IteratorStats } -func NewNot(primaryIt, forbiddenIt graph.Iterator) *Not { +func NewNot(ts graph.TripleStore, primaryIt graph.Iterator) *Not { return &Not{ - uid: NextUID(), - primaryIt: primaryIt, - forbiddenIt: forbiddenIt, + uid: NextUID(), + ts: ts, + allIt: ts.NodesAllIterator(), + primaryIt: primaryIt, } } @@ -28,14 +30,13 @@ func (it *Not) UID() uint64 { func (it *Not) Reset() { it.result = nil it.primaryIt.Reset() - it.forbiddenIt.Reset() + it.allIt = it.ts.NodesAllIterator() } func (it *Not) Tagger() *graph.Tagger { return &it.tags } -// TODO func (it *Not) TagResults(dst map[string]graph.Value) { for _, tag := range it.tags.Tags() { dst[tag] = it.Result() @@ -51,19 +52,19 @@ func (it *Not) TagResults(dst map[string]graph.Value) { } func (it *Not) Clone() graph.Iterator { - not := NewNot(it.primaryIt.Clone(), it.forbiddenIt.Clone()) + not := NewNot(it.ts, it.primaryIt.Clone()) not.tags.CopyFrom(it) return not } func (it *Not) SubIterators() []graph.Iterator { - return []graph.Iterator{it.primaryIt, it.forbiddenIt} + return []graph.Iterator{it.primaryIt, it.allIt} } func (it *Not) ResultTree() *graph.ResultTree { tree := graph.NewResultTree(it.Result()) tree.AddSubtree(it.primaryIt.ResultTree()) - tree.AddSubtree(it.forbiddenIt.ResultTree()) + tree.AddSubtree(it.allIt.ResultTree()) return tree } @@ -76,9 +77,7 @@ func (it *Not) Next() bool { it.runstats.Next += 1 for graph.Next(it.primaryIt) { - // Consider only the elements from the primary set which are not - // contained in the forbidden set. - if curr := it.primaryIt.Result(); !it.forbiddenIt.Contains(curr) { + if curr := it.allIt.Result(); !it.primaryIt.Contains(curr) { it.result = curr it.runstats.ContainsNext += 1 return graph.NextLogOut(it, curr, true) @@ -95,28 +94,30 @@ func (it *Not) Contains(val graph.Value) bool { graph.ContainsLogIn(it, val) it.runstats.Contains += 1 - mainGood := it.primaryIt.Contains(val) - if mainGood { - mainGood = !it.forbiddenIt.Contains(val) + if it.primaryIt.Contains(val) { + return graph.ContainsLogOut(it, val, false) } - return graph.ContainsLogOut(it, val, mainGood) + + // TODO - figure out if this really needs to be checked or it's safe to return true directly + return graph.ContainsLogOut(it, val, it.allIt.Contains(val)) } +// TODO func (it *Not) NextPath() bool { if it.primaryIt.NextPath() { return true } - return it.forbiddenIt.NextPath() + return false } func (it *Not) Close() { it.primaryIt.Close() - it.forbiddenIt.Close() + it.allIt.Close() } func (it *Not) Type() graph.Type { return graph.Not } -// TODO +// TODO - call optimize for the primaryIt and allIt? func (it *Not) Optimize() (graph.Iterator, bool) { //it.forbiddenIt = NewMaterialize(it.forbiddenIt) return it, false diff --git a/query/gremlin/build_iterator.go b/query/gremlin/build_iterator.go index 60e53d7..11fd453 100644 --- a/query/gremlin/build_iterator.go +++ b/query/gremlin/build_iterator.go @@ -299,28 +299,14 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph. case "in": it = buildInOutIterator(obj, ts, subIt, true) case "not": - // Not is implemented as the difference between the primary iterator - // and the iterator chain composed of (primaryIt->Follow->FollowR). + // arg, _ := obj.Get("_gremlin_values") + // firstArg, _ := arg.Object().Get("0") + // if !isVertexChain(firstArg.Object()) { + // return iterator.NewNull() + // } + // forbiddenIt := buildIteratorTree(firstArg.Object(), ts) - // Arguments for follow iterator - arg, _ := obj.Get("_gremlin_values") - firstArg, _ := arg.Object().Get("0") - if isVertexChain(firstArg.Object()) { - return iterator.NewNull() - } - - // Arguments for followR iterator - revArg, _ := obj.Get("_gremlin_followr") - if isVertexChain(revArg.Object()) { - return iterator.NewNull() - } - - // Build the primaryIt->Follow iterator - followIt := buildIteratorTreeHelper(firstArg.Object(), ts, subIt) - // Build the primaryIt->Follow->FollowR iterator - forbiddenIt := buildIteratorTreeHelper(revArg.Object(), ts, followIt) - - it = iterator.NewNot(subIt, forbiddenIt) + it = iterator.NewNot(ts, subIt) case "loop": arg, _ := obj.Get("_gremlin_values") firstArg, _ := arg.Object().Get("0") diff --git a/query/gremlin/traversals.go b/query/gremlin/traversals.go index 6f752dc..83d3853 100644 --- a/query/gremlin/traversals.go +++ b/query/gremlin/traversals.go @@ -38,8 +38,8 @@ func (wk *worker) embedTraversals(env *otto.Otto, obj *otto.Object) { obj.Set("Has", wk.gremlinFunc("has", obj, env)) obj.Set("Save", wk.gremlinFunc("save", obj, env)) obj.Set("SaveR", wk.gremlinFunc("saver", obj, env)) - obj.Set("Loop", gremlinFunc("loop", obj, env, ses)) - obj.Set("Not", gremlinFollowR("not", obj, env, ses)) + obj.Set("Loop", wk.gremlinFunc("loop", obj, env)) + obj.Set("Not", wk.gremlinFunc("not", obj, env)) } func (wk *worker) gremlinFunc(kind string, prev *otto.Object, env *otto.Otto) func(otto.FunctionCall) otto.Value {