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() }