Example #1
0
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()
}