func (qs *QuadStore) optimizeAnd(it *iterator.And) (graph.Iterator, bool) { subs := it.SubIterators() var unusedIts []graph.Iterator var newit *SQLIterator newit = nil changed := false var err error // Combine SQL iterators if clog.V(4) { clog.Infof("Combining SQL %#v", subs) } for _, subit := range subs { if subit.Type() == sqlType { if newit == nil { newit = subit.(*SQLIterator) } else { changed = true newit, err = intersect(newit.sql, subit.(*SQLIterator).sql, qs) if err != nil { clog.Errorf("%v", err) return it, false } } } else { unusedIts = append(unusedIts, subit) } } if newit == nil { return it, false } // Combine fixed iterators into the SQL iterators. if clog.V(4) { clog.Infof("Combining fixed %#v", unusedIts) } var nodeit *SQLNodeIterator if n, ok := newit.sql.(*SQLNodeIterator); ok { nodeit = n } else if n, ok := newit.sql.(*SQLNodeIntersection); ok { nodeit = n.nodeIts[0].(*SQLNodeIterator) } if nodeit != nil { passOneIts := unusedIts unusedIts = nil for _, subit := range passOneIts { if subit.Type() != graph.Fixed { unusedIts = append(unusedIts, subit) continue } changed = true for subit.Next() { nodeit.fixedSet = append(nodeit.fixedSet, qs.NameOf(subit.Result())) } } } if !changed { return it, false } // Clean up if we're done. if len(unusedIts) == 0 { newit.Tagger().CopyFrom(it) return newit, true } newAnd := iterator.NewAnd(qs) newAnd.Tagger().CopyFrom(it) newAnd.AddSubIterator(newit) for _, i := range unusedIts { newAnd.AddSubIterator(i) } return newAnd.Optimize() }
func (qs *QuadStore) optimizeAndIterator(it *iterator.And) (graph.Iterator, bool) { // Fail fast if nothing can happen if clog.V(4) { clog.Infof("Entering optimizeAndIterator %v", it.UID()) } found := false for _, it := range it.SubIterators() { if clog.V(4) { clog.Infof("%v", it.Type()) } if it.Type() == mongoType { found = true } } if !found { if clog.V(4) { clog.Infof("Aborting optimizeAndIterator") } return it, false } newAnd := iterator.NewAnd(qs) var mongoIt *Iterator for _, it := range it.SubIterators() { switch it.Type() { case mongoType: if mongoIt == nil { mongoIt = it.(*Iterator) } else { newAnd.AddSubIterator(it) } case graph.LinksTo: continue default: newAnd.AddSubIterator(it) } } stats := mongoIt.Stats() lset := []graph.Linkage{ { Dir: mongoIt.dir, Value: qs.ValueOf(mongoIt.name), }, } n := 0 for _, it := range it.SubIterators() { if it.Type() == graph.LinksTo { lto := it.(*iterator.LinksTo) // Is it more effective to do the replacement, or let the mongo check the linksto? ltostats := lto.Stats() if (ltostats.ContainsCost+stats.NextCost)*stats.Size > (ltostats.NextCost+stats.ContainsCost)*ltostats.Size { continue } newLto := NewLinksTo(qs, lto.SubIterators()[0], "quads", lto.Direction(), lset) newAnd.AddSubIterator(newLto) n++ } } if n == 0 { return it, false } return newAnd.Optimize() }