Converted the Not operator to a complement operator in terms of functionality.

This commit is contained in:
Matei Chiperi 2014-08-27 13:42:56 -07:00
parent a0318aa7b2
commit 5d4e22498d
3 changed files with 35 additions and 48 deletions

View file

@ -7,17 +7,19 @@ import "github.com/google/cayley/graph"
type Not struct { type Not struct {
uid uint64 uid uint64
tags graph.Tagger tags graph.Tagger
ts graph.TripleStore
primaryIt graph.Iterator primaryIt graph.Iterator
forbiddenIt graph.Iterator allIt graph.Iterator
result graph.Value result graph.Value
runstats graph.IteratorStats runstats graph.IteratorStats
} }
func NewNot(primaryIt, forbiddenIt graph.Iterator) *Not { func NewNot(ts graph.TripleStore, primaryIt graph.Iterator) *Not {
return &Not{ return &Not{
uid: NextUID(), uid: NextUID(),
ts: ts,
allIt: ts.NodesAllIterator(),
primaryIt: primaryIt, primaryIt: primaryIt,
forbiddenIt: forbiddenIt,
} }
} }
@ -28,14 +30,13 @@ func (it *Not) UID() uint64 {
func (it *Not) Reset() { func (it *Not) Reset() {
it.result = nil it.result = nil
it.primaryIt.Reset() it.primaryIt.Reset()
it.forbiddenIt.Reset() it.allIt = it.ts.NodesAllIterator()
} }
func (it *Not) Tagger() *graph.Tagger { func (it *Not) Tagger() *graph.Tagger {
return &it.tags return &it.tags
} }
// TODO
func (it *Not) TagResults(dst map[string]graph.Value) { func (it *Not) TagResults(dst map[string]graph.Value) {
for _, tag := range it.tags.Tags() { for _, tag := range it.tags.Tags() {
dst[tag] = it.Result() dst[tag] = it.Result()
@ -51,19 +52,19 @@ func (it *Not) TagResults(dst map[string]graph.Value) {
} }
func (it *Not) Clone() graph.Iterator { 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) not.tags.CopyFrom(it)
return not return not
} }
func (it *Not) SubIterators() []graph.Iterator { 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 { func (it *Not) ResultTree() *graph.ResultTree {
tree := graph.NewResultTree(it.Result()) tree := graph.NewResultTree(it.Result())
tree.AddSubtree(it.primaryIt.ResultTree()) tree.AddSubtree(it.primaryIt.ResultTree())
tree.AddSubtree(it.forbiddenIt.ResultTree()) tree.AddSubtree(it.allIt.ResultTree())
return tree return tree
} }
@ -76,9 +77,7 @@ func (it *Not) Next() bool {
it.runstats.Next += 1 it.runstats.Next += 1
for graph.Next(it.primaryIt) { for graph.Next(it.primaryIt) {
// Consider only the elements from the primary set which are not if curr := it.allIt.Result(); !it.primaryIt.Contains(curr) {
// contained in the forbidden set.
if curr := it.primaryIt.Result(); !it.forbiddenIt.Contains(curr) {
it.result = curr it.result = curr
it.runstats.ContainsNext += 1 it.runstats.ContainsNext += 1
return graph.NextLogOut(it, curr, true) return graph.NextLogOut(it, curr, true)
@ -95,28 +94,30 @@ func (it *Not) Contains(val graph.Value) bool {
graph.ContainsLogIn(it, val) graph.ContainsLogIn(it, val)
it.runstats.Contains += 1 it.runstats.Contains += 1
mainGood := it.primaryIt.Contains(val) if it.primaryIt.Contains(val) {
if mainGood { return graph.ContainsLogOut(it, val, false)
mainGood = !it.forbiddenIt.Contains(val)
} }
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 { func (it *Not) NextPath() bool {
if it.primaryIt.NextPath() { if it.primaryIt.NextPath() {
return true return true
} }
return it.forbiddenIt.NextPath() return false
} }
func (it *Not) Close() { func (it *Not) Close() {
it.primaryIt.Close() it.primaryIt.Close()
it.forbiddenIt.Close() it.allIt.Close()
} }
func (it *Not) Type() graph.Type { return graph.Not } 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) { func (it *Not) Optimize() (graph.Iterator, bool) {
//it.forbiddenIt = NewMaterialize(it.forbiddenIt) //it.forbiddenIt = NewMaterialize(it.forbiddenIt)
return it, false return it, false

View file

@ -299,28 +299,14 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph.
case "in": case "in":
it = buildInOutIterator(obj, ts, subIt, true) it = buildInOutIterator(obj, ts, subIt, true)
case "not": case "not":
// Not is implemented as the difference between the primary iterator // arg, _ := obj.Get("_gremlin_values")
// and the iterator chain composed of (primaryIt->Follow->FollowR). // firstArg, _ := arg.Object().Get("0")
// if !isVertexChain(firstArg.Object()) {
// return iterator.NewNull()
// }
// forbiddenIt := buildIteratorTree(firstArg.Object(), ts)
// Arguments for follow iterator it = iterator.NewNot(ts, subIt)
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)
case "loop": case "loop":
arg, _ := obj.Get("_gremlin_values") arg, _ := obj.Get("_gremlin_values")
firstArg, _ := arg.Object().Get("0") firstArg, _ := arg.Object().Get("0")

View file

@ -38,8 +38,8 @@ func (wk *worker) embedTraversals(env *otto.Otto, obj *otto.Object) {
obj.Set("Has", wk.gremlinFunc("has", obj, env)) obj.Set("Has", wk.gremlinFunc("has", obj, env))
obj.Set("Save", wk.gremlinFunc("save", obj, env)) obj.Set("Save", wk.gremlinFunc("save", obj, env))
obj.Set("SaveR", wk.gremlinFunc("saver", obj, env)) obj.Set("SaveR", wk.gremlinFunc("saver", obj, env))
obj.Set("Loop", gremlinFunc("loop", obj, env, ses)) obj.Set("Loop", wk.gremlinFunc("loop", obj, env))
obj.Set("Not", gremlinFollowR("not", obj, env, ses)) 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 { func (wk *worker) gremlinFunc(kind string, prev *otto.Object, env *otto.Otto) func(otto.FunctionCall) otto.Value {