Rename Check-ish -> Contains-ish

Contains[*] indicates what the check is for.

[*] I considered Has/Have, but settled on Contains to avoid confusion
with the HasA iterator.
This commit is contained in:
kortschak 2014-07-31 15:29:42 +09:30
parent a81005ba21
commit 1606e98d9f
20 changed files with 142 additions and 143 deletions

View file

@ -52,7 +52,7 @@ An important failure of MQL before was that it was never well-specified. Let's n
### New Iterators ### New Iterators
#### Limit Iterator #### Limit Iterator
The necessary component to make mid-query limit work. Acts as a limit on Next(), a passthrough on Check(), and a limit on NextResult() The necessary component to make mid-query limit work. Acts as a limit on Next(), a passthrough on Contains(), and a limit on NextResult()
## Medium Term ## Medium Term

View file

@ -86,7 +86,7 @@ var benchmarkQueries = []struct {
// This is more of an optimization problem that will get better over time. This takes a lot // This is more of an optimization problem that will get better over time. This takes a lot
// of wrong turns on the walk down to what is ultimately the name, but top AND has it easy // of wrong turns on the walk down to what is ultimately the name, but top AND has it easy
// as it has a fixed ID. Exercises Check(). // as it has a fixed ID. Exercises Contains().
{ {
message: "the helpless checker", message: "the helpless checker",
long: true, long: true,
@ -383,7 +383,7 @@ func BenchmarkVeryLargeSetsSmallIntersection(b *testing.B) {
runBench(2, b) runBench(2, b)
} }
func BenchmarkHelplessChecker(b *testing.B) { func BenchmarkHelplessContainsChecker(b *testing.B) {
runBench(3, b) runBench(3, b)
} }

View file

@ -89,9 +89,8 @@ type Iterator interface {
// from the bottom up. // from the bottom up.
NextResult() bool NextResult() bool
// Check(), given a value, returns whether or not that value is within the set // Contains returns whether the value is within the set held by the iterator.
// held by this iterator. Contains(Value) bool
Check(Value) bool
// Start iteration from the beginning // Start iteration from the beginning
Reset() Reset()
@ -161,9 +160,9 @@ type FixedIterator interface {
} }
type IteratorStats struct { type IteratorStats struct {
CheckCost int64 ContainsCost int64
NextCost int64 NextCost int64
Size int64 Size int64
} }
// Type enumerates the set of Iterator types. // Type enumerates the set of Iterator types.
@ -229,20 +228,20 @@ func (t Type) String() string {
return types[t] return types[t]
} }
// Utility logging functions for when an iterator gets called Next upon, or Check upon, as // Utility logging functions for when an iterator gets called Next upon, or Contains upon, as
// well as what they return. Highly useful for tracing the execution path of a query. // well as what they return. Highly useful for tracing the execution path of a query.
func CheckLogIn(it Iterator, val Value) { func ContainsLogIn(it Iterator, val Value) {
if glog.V(4) { if glog.V(4) {
glog.V(4).Infof("%s %d CHECK %d", strings.ToUpper(it.Type().String()), it.UID(), val) glog.V(4).Infof("%s %d CHECK CONTAINS %d", strings.ToUpper(it.Type().String()), it.UID(), val)
} }
} }
func CheckLogOut(it Iterator, val Value, good bool) bool { func ContainsLogOut(it Iterator, val Value, good bool) bool {
if glog.V(4) { if glog.V(4) {
if good { if good {
glog.V(4).Infof("%s %d CHECK %d GOOD", strings.ToUpper(it.Type().String()), it.UID(), val) glog.V(4).Infof("%s %d CHECK CONTAINS %d GOOD", strings.ToUpper(it.Type().String()), it.UID(), val)
} else { } else {
glog.V(4).Infof("%s %d CHECK %d BAD", strings.ToUpper(it.Type().String()), it.UID(), val) glog.V(4).Infof("%s %d CHECK CONTAINS %d BAD", strings.ToUpper(it.Type().String()), it.UID(), val)
} }
} }
return good return good

View file

@ -126,16 +126,16 @@ func (it *Int64) Size() (int64, bool) {
return Size, true return Size, true
} }
// Check() for an Int64 is merely seeing if the passed value is // Contains() for an Int64 is merely seeing if the passed value is
// withing the range, assuming the value is an int64. // withing the range, assuming the value is an int64.
func (it *Int64) Check(tsv graph.Value) bool { func (it *Int64) Contains(tsv graph.Value) bool {
graph.CheckLogIn(it, tsv) graph.ContainsLogIn(it, tsv)
v := tsv.(int64) v := tsv.(int64)
if it.min <= v && v <= it.max { if it.min <= v && v <= it.max {
it.result = v it.result = v
return graph.CheckLogOut(it, v, true) return graph.ContainsLogOut(it, v, true)
} }
return graph.CheckLogOut(it, v, false) return graph.ContainsLogOut(it, v, false)
} }
// The type of this iterator is an "all". This is important, as it puts it in // The type of this iterator is an "all". This is important, as it puts it in
@ -150,8 +150,8 @@ func (it *Int64) Optimize() (graph.Iterator, bool) { return it, false }
func (it *Int64) Stats() graph.IteratorStats { func (it *Int64) Stats() graph.IteratorStats {
s, _ := it.Size() s, _ := it.Size()
return graph.IteratorStats{ return graph.IteratorStats{
CheckCost: 1, ContainsCost: 1,
NextCost: 1, NextCost: 1,
Size: s, Size: s,
} }
} }

View file

@ -6,11 +6,11 @@
// //
// It accomplishes this in one of two ways. If it is a Next()ed iterator (that // It accomplishes this in one of two ways. If it is a Next()ed iterator (that
// is, it is a top level iterator, or on the "Next() path", then it will Next() // is, it is a top level iterator, or on the "Next() path", then it will Next()
// it's primary iterator (helpfully, and.primary_it) and Check() the resultant // it's primary iterator (helpfully, and.primary_it) and Contains() the resultant
// value against it's other iterators. If it matches all of them, then it // value against it's other iterators. If it matches all of them, then it
// returns that value. Otherwise, it repeats the process. // returns that value. Otherwise, it repeats the process.
// //
// If it's on a Check() path, it merely Check()s every iterator, and returns the // If it's on a Contains() path, it merely Contains()s every iterator, and returns the
// logical AND of each result. // logical AND of each result.
package iterator package iterator
@ -86,7 +86,7 @@ func (it *And) Clone() graph.Iterator {
and.AddSubIterator(sub.Clone()) and.AddSubIterator(sub.Clone())
} }
if it.checkList != nil { if it.checkList != nil {
and.optimizeCheck() and.optimizeContains()
} }
return and return and
} }
@ -164,7 +164,7 @@ func (it *And) Next() (graph.Value, bool) {
if !exists { if !exists {
return graph.NextLogOut(it, nil, false) return graph.NextLogOut(it, nil, false)
} }
if it.checkSubIts(curr) { if it.subItsContain(curr) {
it.result = curr it.result = curr
return graph.NextLogOut(it, curr, true) return graph.NextLogOut(it, curr, true)
} }
@ -177,10 +177,10 @@ func (it *And) Result() graph.Value {
} }
// Checks a value against the non-primary iterators, in order. // Checks a value against the non-primary iterators, in order.
func (it *And) checkSubIts(val graph.Value) bool { func (it *And) subItsContain(val graph.Value) bool {
var subIsGood = true var subIsGood = true
for _, sub := range it.internalIterators { for _, sub := range it.internalIterators {
subIsGood = sub.Check(val) subIsGood = sub.Contains(val)
if !subIsGood { if !subIsGood {
break break
} }
@ -188,10 +188,10 @@ func (it *And) checkSubIts(val graph.Value) bool {
return subIsGood return subIsGood
} }
func (it *And) checkCheckList(val graph.Value) bool { func (it *And) checkContainsList(val graph.Value) bool {
ok := true ok := true
for _, c := range it.checkList { for _, c := range it.checkList {
ok = c.Check(val) ok = c.Contains(val)
if !ok { if !ok {
break break
} }
@ -199,25 +199,25 @@ func (it *And) checkCheckList(val graph.Value) bool {
if ok { if ok {
it.result = val it.result = val
} }
return graph.CheckLogOut(it, val, ok) return graph.ContainsLogOut(it, val, ok)
} }
// Check a value against the entire iterator, in order. // Check a value against the entire iterator, in order.
func (it *And) Check(val graph.Value) bool { func (it *And) Contains(val graph.Value) bool {
graph.CheckLogIn(it, val) graph.ContainsLogIn(it, val)
if it.checkList != nil { if it.checkList != nil {
return it.checkCheckList(val) return it.checkContainsList(val)
} }
mainGood := it.primaryIt.Check(val) mainGood := it.primaryIt.Contains(val)
if !mainGood { if !mainGood {
return graph.CheckLogOut(it, val, false) return graph.ContainsLogOut(it, val, false)
} }
othersGood := it.checkSubIts(val) othersGood := it.subItsContain(val)
if !othersGood { if !othersGood {
return graph.CheckLogOut(it, val, false) return graph.ContainsLogOut(it, val, false)
} }
it.result = val it.result = val
return graph.CheckLogOut(it, val, true) return graph.ContainsLogOut(it, val, true)
} }
// Returns the approximate size of the And iterator. Because we're dealing // Returns the approximate size of the And iterator. Because we're dealing

View file

@ -38,10 +38,10 @@ import (
// In short, tread lightly. // In short, tread lightly.
// Optimizes the And, by picking the most efficient way to Next() and // Optimizes the And, by picking the most efficient way to Next() and
// Check() its subiterators. For SQL fans, this is equivalent to JOIN. // Contains() its subiterators. For SQL fans, this is equivalent to JOIN.
func (it *And) Optimize() (graph.Iterator, bool) { func (it *And) Optimize() (graph.Iterator, bool) {
// First, let's get the slice of iterators, in order (first one is Next()ed, // First, let's get the slice of iterators, in order (first one is Next()ed,
// the rest are Check()ed) // the rest are Contains()ed)
old := it.SubIterators() old := it.SubIterators()
// And call Optimize() on our subtree, replacing each one in the order we // And call Optimize() on our subtree, replacing each one in the order we
@ -84,7 +84,7 @@ func (it *And) Optimize() (graph.Iterator, bool) {
// Move the tags hanging on us (like any good replacement). // Move the tags hanging on us (like any good replacement).
newAnd.tags.CopyFrom(it) newAnd.tags.CopyFrom(it)
newAnd.optimizeCheck() newAnd.optimizeContains()
// And close ourselves but not our subiterators -- some may still be alive in // And close ourselves but not our subiterators -- some may still be alive in
// the new And (they were unchanged upon calling Optimize() on them, at the // the new And (they were unchanged upon calling Optimize() on them, at the
@ -142,7 +142,7 @@ func optimizeOrder(its []graph.Iterator) []graph.Iterator {
// Find the iterator with the projected "best" total cost. // Find the iterator with the projected "best" total cost.
// Total cost is defined as The Next()ed iterator's cost to Next() out // Total cost is defined as The Next()ed iterator's cost to Next() out
// all of it's contents, and to Check() each of those against everyone // all of it's contents, and to Contains() each of those against everyone
// else. // else.
for _, it := range its { for _, it := range its {
if _, canNext := it.(graph.Nexter); !canNext { if _, canNext := it.(graph.Nexter); !canNext {
@ -159,7 +159,7 @@ func optimizeOrder(its []graph.Iterator) []graph.Iterator {
continue continue
} }
stats := f.Stats() stats := f.Stats()
cost += stats.CheckCost cost += stats.ContainsCost
} }
cost *= rootStats.Size cost *= rootStats.Size
if cost < bestCost { if cost < bestCost {
@ -169,7 +169,7 @@ func optimizeOrder(its []graph.Iterator) []graph.Iterator {
} }
// TODO(barakmich): Optimization of order need not stop here. Picking a smart // TODO(barakmich): Optimization of order need not stop here. Picking a smart
// Check() order based on probability of getting a false Check() first is // Contains() order based on probability of getting a false Contains() first is
// useful (fail faster). // useful (fail faster).
// Put the best iterator (the one we wish to Next()) at the front... // Put the best iterator (the one we wish to Next()) at the front...
@ -192,12 +192,12 @@ func optimizeOrder(its []graph.Iterator) []graph.Iterator {
type byCost []graph.Iterator type byCost []graph.Iterator
func (c byCost) Len() int { return len(c) } func (c byCost) Len() int { return len(c) }
func (c byCost) Less(i, j int) bool { return c[i].Stats().CheckCost < c[j].Stats().CheckCost } func (c byCost) Less(i, j int) bool { return c[i].Stats().ContainsCost < c[j].Stats().ContainsCost }
func (c byCost) Swap(i, j int) { c[i], c[j] = c[j], c[i] } func (c byCost) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
// optimizeCheck(l) creates an alternate check list, containing the same contents // optimizeContains() creates an alternate check list, containing the same contents
// but with a new ordering, however it wishes. // but with a new ordering, however it wishes.
func (it *And) optimizeCheck() { func (it *And) optimizeContains() {
// GetSubIterators allocates, so this is currently safe. // GetSubIterators allocates, so this is currently safe.
// TODO(kortschak) Reuse it.checkList if possible. // TODO(kortschak) Reuse it.checkList if possible.
// This involves providing GetSubIterators with a slice to fill. // This involves providing GetSubIterators with a slice to fill.
@ -298,21 +298,21 @@ func hasOneUsefulIterator(its []graph.Iterator) graph.Iterator {
// For now, however, it's pretty static. // For now, however, it's pretty static.
func (it *And) Stats() graph.IteratorStats { func (it *And) Stats() graph.IteratorStats {
primaryStats := it.primaryIt.Stats() primaryStats := it.primaryIt.Stats()
CheckCost := primaryStats.CheckCost ContainsCost := primaryStats.ContainsCost
NextCost := primaryStats.NextCost NextCost := primaryStats.NextCost
Size := primaryStats.Size Size := primaryStats.Size
for _, sub := range it.internalIterators { for _, sub := range it.internalIterators {
stats := sub.Stats() stats := sub.Stats()
NextCost += stats.CheckCost NextCost += stats.ContainsCost
CheckCost += stats.CheckCost ContainsCost += stats.ContainsCost
if Size > stats.Size { if Size > stats.Size {
Size = stats.Size Size = stats.Size
} }
} }
return graph.IteratorStats{ return graph.IteratorStats{
CheckCost: CheckCost, ContainsCost: ContainsCost,
NextCost: NextCost, NextCost: NextCost,
Size: Size, Size: Size,
} }
} }

View file

@ -121,18 +121,18 @@ func (it *Fixed) DebugString(indent int) string {
func (it *Fixed) Type() graph.Type { return graph.Fixed } func (it *Fixed) Type() graph.Type { return graph.Fixed }
// Check if the passed value is equal to one of the values stored in the iterator. // Check if the passed value is equal to one of the values stored in the iterator.
func (it *Fixed) Check(v graph.Value) bool { func (it *Fixed) Contains(v graph.Value) bool {
// Could be optimized by keeping it sorted or using a better datastructure. // Could be optimized by keeping it sorted or using a better datastructure.
// However, for fixed iterators, which are by definition kind of tiny, this // However, for fixed iterators, which are by definition kind of tiny, this
// isn't a big issue. // isn't a big issue.
graph.CheckLogIn(it, v) graph.ContainsLogIn(it, v)
for _, x := range it.values { for _, x := range it.values {
if it.cmp(x, v) { if it.cmp(x, v) {
it.result = x it.result = x
return graph.CheckLogOut(it, v, true) return graph.ContainsLogOut(it, v, true)
} }
} }
return graph.CheckLogOut(it, v, false) return graph.ContainsLogOut(it, v, false)
} }
// Return the next stored value from the iterator. // Return the next stored value from the iterator.
@ -181,12 +181,12 @@ func (it *Fixed) Size() (int64, bool) {
return int64(len(it.values)), true return int64(len(it.values)), true
} }
// As we right now have to scan the entire list, Next and Check are linear with the // As we right now have to scan the entire list, Next and Contains are linear with the
// size. However, a better data structure could remove these limits. // size. However, a better data structure could remove these limits.
func (it *Fixed) Stats() graph.IteratorStats { func (it *Fixed) Stats() graph.IteratorStats {
return graph.IteratorStats{ return graph.IteratorStats{
CheckCost: int64(len(it.values)), ContainsCost: int64(len(it.values)),
NextCost: int64(len(it.values)), NextCost: int64(len(it.values)),
Size: int64(len(it.values)), Size: int64(len(it.values)),
} }
} }

View file

@ -23,10 +23,10 @@ package iterator
// path. That's okay -- in reality, it can be viewed as returning the value for // path. That's okay -- in reality, it can be viewed as returning the value for
// a new triple, but to make logic much simpler, here we have the HasA. // a new triple, but to make logic much simpler, here we have the HasA.
// //
// Likewise, it's important to think about Check()ing a HasA. When given a // Likewise, it's important to think about Contains()ing a HasA. When given a
// value to check, it means "Check all predicates that have this value for your // value to check, it means "Check all predicates that have this value for your
// direction against the subiterator." This would imply that there's more than // direction against the subiterator." This would imply that there's more than
// one possibility for the same Check()ed value. While we could return the // one possibility for the same Contains()ed value. While we could return the
// number of options, it's simpler to return one, and then call NextResult() // number of options, it's simpler to return one, and then call NextResult()
// enough times to enumerate the options. (In fact, one could argue that the // enough times to enumerate the options. (In fact, one could argue that the
// raison d'etre for NextResult() is this iterator). // raison d'etre for NextResult() is this iterator).
@ -45,7 +45,7 @@ import (
// A HasA consists of a reference back to the graph.TripleStore that it references, // A HasA consists of a reference back to the graph.TripleStore that it references,
// a primary subiterator, a direction in which the triples for that subiterator point, // a primary subiterator, a direction in which the triples for that subiterator point,
// and a temporary holder for the iterator generated on Check(). // and a temporary holder for the iterator generated on Contains().
type HasA struct { type HasA struct {
uid uint64 uid uint64
tags graph.Tagger tags graph.Tagger
@ -140,9 +140,9 @@ func (it *HasA) DebugString(indent int) string {
// Check a value against our internal iterator. In order to do this, we must first open a new // Check a value against our internal iterator. In order to do this, we must first open a new
// iterator of "triples that have `val` in our direction", given to us by the triple store, // iterator of "triples that have `val` in our direction", given to us by the triple store,
// and then Next() values out of that iterator and Check() them against our subiterator. // and then Next() values out of that iterator and Contains() them against our subiterator.
func (it *HasA) Check(val graph.Value) bool { func (it *HasA) Contains(val graph.Value) bool {
graph.CheckLogIn(it, val) graph.ContainsLogIn(it, val)
if glog.V(4) { if glog.V(4) {
glog.V(4).Infoln("Id is", it.ts.NameOf(val)) glog.V(4).Infoln("Id is", it.ts.NameOf(val))
} }
@ -151,13 +151,13 @@ func (it *HasA) Check(val graph.Value) bool {
it.resultIt.Close() it.resultIt.Close()
} }
it.resultIt = it.ts.TripleIterator(it.dir, val) it.resultIt = it.ts.TripleIterator(it.dir, val)
return graph.CheckLogOut(it, val, it.GetCheckResult()) return graph.ContainsLogOut(it, val, it.NextContains())
} }
// GetCheckResult() is shared code between Check() and GetNextResult() -- calls next on the // NextContains() is shared code between Contains() and GetNextResult() -- calls next on the
// result iterator (a triple iterator based on the last checked value) and returns true if // result iterator (a triple iterator based on the last checked value) and returns true if
// another match is made. // another match is made.
func (it *HasA) GetCheckResult() bool { func (it *HasA) NextContains() bool {
for { for {
linkVal, ok := graph.Next(it.resultIt) linkVal, ok := graph.Next(it.resultIt)
if !ok { if !ok {
@ -166,7 +166,7 @@ func (it *HasA) GetCheckResult() bool {
if glog.V(4) { if glog.V(4) {
glog.V(4).Infoln("Quad is", it.ts.Quad(linkVal)) glog.V(4).Infoln("Quad is", it.ts.Quad(linkVal))
} }
if it.primaryIt.Check(linkVal) { if it.primaryIt.Contains(linkVal) {
it.result = it.ts.TripleDirection(linkVal, it.dir) it.result = it.ts.TripleDirection(linkVal, it.dir)
return true return true
} }
@ -178,17 +178,17 @@ func (it *HasA) GetCheckResult() bool {
func (it *HasA) NextResult() bool { func (it *HasA) NextResult() bool {
// Order here is important. If the subiterator has a NextResult, then we // Order here is important. If the subiterator has a NextResult, then we
// need do nothing -- there is a next result, and we shouldn't move forward. // need do nothing -- there is a next result, and we shouldn't move forward.
// However, we then need to get the next result from our last Check(). // However, we then need to get the next result from our last Contains().
// //
// The upshot is, the end of NextResult() bubbles up from the bottom of the // The upshot is, the end of NextResult() bubbles up from the bottom of the
// iterator tree up, and we need to respect that. // iterator tree up, and we need to respect that.
if it.primaryIt.NextResult() { if it.primaryIt.NextResult() {
return true return true
} }
return it.GetCheckResult() return it.NextContains()
} }
// Get the next result from this iterator. This is simpler than Check. We have a // Get the next result from this iterator. This is simpler than Contains. We have a
// subiterator we can get a value from, and we can take that resultant triple, // subiterator we can get a value from, and we can take that resultant triple,
// pull our direction out of it, and return that. // pull our direction out of it, and return that.
func (it *HasA) Next() (graph.Value, bool) { func (it *HasA) Next() (graph.Value, bool) {
@ -214,7 +214,7 @@ func (it *HasA) Result() graph.Value {
// GetStats() returns the statistics on the HasA iterator. This is curious. Next // GetStats() returns the statistics on the HasA iterator. This is curious. Next
// cost is easy, it's an extra call or so on top of the subiterator Next cost. // cost is easy, it's an extra call or so on top of the subiterator Next cost.
// CheckCost involves going to the graph.TripleStore, iterating out values, and hoping // ContainsCost involves going to the graph.TripleStore, iterating out values, and hoping
// one sticks -- potentially expensive, depending on fanout. Size, however, is // one sticks -- potentially expensive, depending on fanout. Size, however, is
// potentially smaller. we know at worst it's the size of the subiterator, but // potentially smaller. we know at worst it's the size of the subiterator, but
// if there are many repeated values, it could be much smaller in totality. // if there are many repeated values, it could be much smaller in totality.
@ -227,9 +227,9 @@ func (it *HasA) Stats() graph.IteratorStats {
nextConstant := int64(2) nextConstant := int64(2)
tripleConstant := int64(1) tripleConstant := int64(1)
return graph.IteratorStats{ return graph.IteratorStats{
NextCost: tripleConstant + subitStats.NextCost, NextCost: tripleConstant + subitStats.NextCost,
CheckCost: (fanoutFactor * nextConstant) * subitStats.CheckCost, ContainsCost: (fanoutFactor * nextConstant) * subitStats.ContainsCost,
Size: faninFactor * subitStats.Size, Size: faninFactor * subitStats.Size,
} }
} }

View file

@ -61,7 +61,7 @@ func (it *Null) TagResults(dst map[string]graph.Value) {
} }
} }
func (it *Null) Check(graph.Value) bool { func (it *Null) Contains(graph.Value) bool {
return false return false
} }

View file

@ -23,7 +23,7 @@ package iterator
// LinksTo is therefore sensitive to growing with a fanout. (A small-sized // LinksTo is therefore sensitive to growing with a fanout. (A small-sized
// subiterator could cause LinksTo to be large). // subiterator could cause LinksTo to be large).
// //
// Check()ing a LinksTo means, given a link, take the direction we care about // Contains()ing a LinksTo means, given a link, take the direction we care about
// and check if it's in our subiterator. Checking is therefore fairly cheap, and // and check if it's in our subiterator. Checking is therefore fairly cheap, and
// similar to checking the subiterator alone. // similar to checking the subiterator alone.
// //
@ -116,14 +116,14 @@ func (it *LinksTo) DebugString(indent int) string {
// If it checks in the right direction for the subiterator, it is a valid link // If it checks in the right direction for the subiterator, it is a valid link
// for the LinksTo. // for the LinksTo.
func (it *LinksTo) Check(val graph.Value) bool { func (it *LinksTo) Contains(val graph.Value) bool {
graph.CheckLogIn(it, val) graph.ContainsLogIn(it, val)
node := it.ts.TripleDirection(val, it.dir) node := it.ts.TripleDirection(val, it.dir)
if it.primaryIt.Check(node) { if it.primaryIt.Contains(node) {
it.result = val it.result = val
return graph.CheckLogOut(it, val, true) return graph.ContainsLogOut(it, val, true)
} }
return graph.CheckLogOut(it, val, false) return graph.ContainsLogOut(it, val, false)
} }
// Return a list containing only our subiterator. // Return a list containing only our subiterator.
@ -198,9 +198,9 @@ func (it *LinksTo) Stats() graph.IteratorStats {
checkConstant := int64(1) checkConstant := int64(1)
nextConstant := int64(2) nextConstant := int64(2)
return graph.IteratorStats{ return graph.IteratorStats{
NextCost: nextConstant + subitStats.NextCost, NextCost: nextConstant + subitStats.NextCost,
CheckCost: checkConstant + subitStats.CheckCost, ContainsCost: checkConstant + subitStats.ContainsCost,
Size: fanoutFactor * subitStats.Size, Size: fanoutFactor * subitStats.Size,
} }
} }

View file

@ -100,11 +100,11 @@ func (it *Optional) SubIterators() []graph.Iterator {
return nil return nil
} }
// Check() is the real hack of this iterator. It always returns true, regardless // Contains() is the real hack of this iterator. It always returns true, regardless
// of whether the subiterator matched. But we keep track of whether the subiterator // of whether the subiterator matched. But we keep track of whether the subiterator
// matched for results purposes. // matched for results purposes.
func (it *Optional) Check(val graph.Value) bool { func (it *Optional) Contains(val graph.Value) bool {
checked := it.subIt.Check(val) checked := it.subIt.Contains(val)
it.lastCheck = checked it.lastCheck = checked
it.result = val it.result = val
return true return true
@ -146,9 +146,9 @@ func (it *Optional) Optimize() (graph.Iterator, bool) {
func (it *Optional) Stats() graph.IteratorStats { func (it *Optional) Stats() graph.IteratorStats {
subStats := it.subIt.Stats() subStats := it.subIt.Stats()
return graph.IteratorStats{ return graph.IteratorStats{
CheckCost: subStats.CheckCost, ContainsCost: subStats.ContainsCost,
NextCost: int64(1 << 62), NextCost: int64(1 << 62),
Size: subStats.Size, Size: subStats.Size,
} }
} }

View file

@ -177,10 +177,10 @@ func (it *Or) Result() graph.Value {
} }
// Checks a value against the iterators, in order. // Checks a value against the iterators, in order.
func (it *Or) checkSubIts(val graph.Value) bool { func (it *Or) subItsContain(val graph.Value) bool {
var subIsGood = false var subIsGood = false
for i, sub := range it.internalIterators { for i, sub := range it.internalIterators {
subIsGood = sub.Check(val) subIsGood = sub.Contains(val)
if subIsGood { if subIsGood {
it.currentIterator = i it.currentIterator = i
break break
@ -190,14 +190,14 @@ func (it *Or) checkSubIts(val graph.Value) bool {
} }
// Check a value against the entire graph.iterator, in order. // Check a value against the entire graph.iterator, in order.
func (it *Or) Check(val graph.Value) bool { func (it *Or) Contains(val graph.Value) bool {
graph.CheckLogIn(it, val) graph.ContainsLogIn(it, val)
anyGood := it.checkSubIts(val) anyGood := it.subItsContain(val)
if !anyGood { if !anyGood {
return graph.CheckLogOut(it, val, false) return graph.ContainsLogOut(it, val, false)
} }
it.result = val it.result = val
return graph.CheckLogOut(it, val, true) return graph.ContainsLogOut(it, val, true)
} }
// Returns the approximate size of the Or graph.iterator. Because we're dealing // Returns the approximate size of the Or graph.iterator. Because we're dealing
@ -277,13 +277,13 @@ func (it *Or) Optimize() (graph.Iterator, bool) {
} }
func (it *Or) Stats() graph.IteratorStats { func (it *Or) Stats() graph.IteratorStats {
CheckCost := int64(0) ContainsCost := int64(0)
NextCost := int64(0) NextCost := int64(0)
Size := int64(0) Size := int64(0)
for _, sub := range it.internalIterators { for _, sub := range it.internalIterators {
stats := sub.Stats() stats := sub.Stats()
NextCost += stats.NextCost NextCost += stats.NextCost
CheckCost += stats.CheckCost ContainsCost += stats.ContainsCost
if it.isShortCircuiting { if it.isShortCircuiting {
if Size < stats.Size { if Size < stats.Size {
Size = stats.Size Size = stats.Size
@ -293,9 +293,9 @@ func (it *Or) Stats() graph.IteratorStats {
} }
} }
return graph.IteratorStats{ return graph.IteratorStats{
CheckCost: CheckCost, ContainsCost: ContainsCost,
NextCost: NextCost, NextCost: NextCost,
Size: Size, Size: Size,
} }
} }

View file

@ -66,13 +66,13 @@ func TestOrIteratorBasics(t *testing.T) {
} }
for _, v := range []int{2, 3, 21} { for _, v := range []int{2, 3, 21} {
if !or.Check(v) { if !or.Contains(v) {
t.Errorf("Failed to correctly check %d as true", v) t.Errorf("Failed to correctly check %d as true", v)
} }
} }
for _, v := range []int{22, 5, 0} { for _, v := range []int{22, 5, 0} {
if or.Check(v) { if or.Contains(v) {
t.Errorf("Failed to correctly check %d as false", v) t.Errorf("Failed to correctly check %d as false", v)
} }
} }
@ -125,12 +125,12 @@ func TestShortCircuitingOrBasics(t *testing.T) {
or.AddSubIterator(f1) or.AddSubIterator(f1)
or.AddSubIterator(f2) or.AddSubIterator(f2)
for _, v := range []int{2, 3, 21} { for _, v := range []int{2, 3, 21} {
if !or.Check(v) { if !or.Contains(v) {
t.Errorf("Failed to correctly check %d as true", v) t.Errorf("Failed to correctly check %d as true", v)
} }
} }
for _, v := range []int{22, 5, 0} { for _, v := range []int{22, 5, 0} {
if or.Check(v) { if or.Contains(v) {
t.Errorf("Failed to correctly check %d as false", v) t.Errorf("Failed to correctly check %d as false", v)
} }
} }

View file

@ -171,11 +171,11 @@ func (it *Comparison) SubIterators() []graph.Iterator {
return nil return nil
} }
func (it *Comparison) Check(val graph.Value) bool { func (it *Comparison) Contains(val graph.Value) bool {
if !it.doComparison(val) { if !it.doComparison(val) {
return false return false
} }
return it.subIt.Check(val) return it.subIt.Contains(val)
} }
// If we failed the check, then the subiterator should not contribute to the result // If we failed the check, then the subiterator should not contribute to the result

View file

@ -82,7 +82,7 @@ func TestValueComparison(t *testing.T) {
} }
} }
var vciCheckTests = []struct { var vciContainsTests = []struct {
message string message string
operator Operator operator Operator
check graph.Value check graph.Value
@ -114,10 +114,10 @@ var vciCheckTests = []struct {
}, },
} }
func TestVCICheck(t *testing.T) { func TestVCIContains(t *testing.T) {
for _, test := range vciCheckTests { for _, test := range vciContainsTests {
vc := NewComparison(simpleFixedIterator(), test.operator, int64(2), simpleStore) vc := NewComparison(simpleFixedIterator(), test.operator, int64(2), simpleStore)
if vc.Check(test.check) != test.expect { if vc.Contains(test.check) != test.expect {
t.Errorf("Failed to show %s", test.message) t.Errorf("Failed to show %s", test.message)
} }
} }

View file

@ -138,7 +138,7 @@ func (it *AllIterator) SubIterators() []graph.Iterator {
return nil return nil
} }
func (it *AllIterator) Check(v graph.Value) bool { func (it *AllIterator) Contains(v graph.Value) bool {
it.result = v it.result = v
return true return true
} }
@ -174,8 +174,8 @@ func (it *AllIterator) Optimize() (graph.Iterator, bool) {
func (it *AllIterator) Stats() graph.IteratorStats { func (it *AllIterator) Stats() graph.IteratorStats {
s, _ := it.Size() s, _ := it.Size()
return graph.IteratorStats{ return graph.IteratorStats{
CheckCost: 1, ContainsCost: 1,
NextCost: 2, NextCost: 2,
Size: s, Size: s,
} }
} }

View file

@ -215,7 +215,7 @@ func PositionOf(prefix []byte, d quad.Direction, qs *TripleStore) int {
panic("unreachable") panic("unreachable")
} }
func (it *Iterator) Check(v graph.Value) bool { func (it *Iterator) Contains(v graph.Value) bool {
val := v.([]byte) val := v.([]byte)
if val[0] == 'z' { if val[0] == 'z' {
return false return false
@ -262,8 +262,8 @@ func (it *Iterator) Optimize() (graph.Iterator, bool) {
func (it *Iterator) Stats() graph.IteratorStats { func (it *Iterator) Stats() graph.IteratorStats {
s, _ := it.Size() s, _ := it.Size()
return graph.IteratorStats{ return graph.IteratorStats{
CheckCost: 1, ContainsCost: 1,
NextCost: 2, NextCost: 2,
Size: s, Size: s,
} }
} }

View file

@ -251,14 +251,14 @@ func TestIterator(t *testing.T) {
} }
for _, pq := range expect { for _, pq := range expect {
if !it.Check(qs.ValueOf(pq)) { if !it.Contains(qs.ValueOf(pq)) {
t.Errorf("Failed to find and check %q correctly", pq) t.Errorf("Failed to find and check %q correctly", pq)
} }
} }
// FIXME(kortschak) Why does this fail? // FIXME(kortschak) Why does this fail?
/* /*
for _, pq := range []string{"baller"} { for _, pq := range []string{"baller"} {
if it.Check(qs.ValueOf(pq)) { if it.Contains(qs.ValueOf(pq)) {
t.Errorf("Failed to check %q correctly", pq) t.Errorf("Failed to check %q correctly", pq)
} }
} }

View file

@ -124,13 +124,13 @@ func (it *Iterator) Size() (int64, bool) {
return int64(it.tree.Len()), true return int64(it.tree.Len()), true
} }
func (it *Iterator) Check(v graph.Value) bool { func (it *Iterator) Contains(v graph.Value) bool {
graph.CheckLogIn(it, v) graph.ContainsLogIn(it, v)
if it.tree.Has(Int64(v.(int64))) { if it.tree.Has(Int64(v.(int64))) {
it.result = v it.result = v
return graph.CheckLogOut(it, v, true) return graph.ContainsLogOut(it, v, true)
} }
return graph.CheckLogOut(it, v, false) return graph.ContainsLogOut(it, v, false)
} }
func (it *Iterator) DebugString(indent int) string { func (it *Iterator) DebugString(indent int) string {
@ -156,8 +156,8 @@ func (it *Iterator) Optimize() (graph.Iterator, bool) {
func (it *Iterator) Stats() graph.IteratorStats { func (it *Iterator) Stats() graph.IteratorStats {
return graph.IteratorStats{ return graph.IteratorStats{
CheckCost: int64(math.Log(float64(it.tree.Len()))) + 1, ContainsCost: int64(math.Log(float64(it.tree.Len()))) + 1,
NextCost: 1, NextCost: 1,
Size: int64(it.tree.Len()), Size: int64(it.tree.Len()),
} }
} }

View file

@ -174,11 +174,11 @@ func (it *Iterator) SubIterators() []graph.Iterator {
return nil return nil
} }
func (it *Iterator) Check(v graph.Value) bool { func (it *Iterator) Contains(v graph.Value) bool {
graph.CheckLogIn(it, v) graph.ContainsLogIn(it, v)
if it.isAll { if it.isAll {
it.result = v it.result = v
return graph.CheckLogOut(it, v, true) return graph.ContainsLogOut(it, v, true)
} }
var offset int var offset int
switch it.dir { switch it.dir {
@ -194,9 +194,9 @@ func (it *Iterator) Check(v graph.Value) bool {
val := v.(string)[offset : it.qs.hasher.Size()*2+offset] val := v.(string)[offset : it.qs.hasher.Size()*2+offset]
if val == it.hash { if val == it.hash {
it.result = v it.result = v
return graph.CheckLogOut(it, v, true) return graph.ContainsLogOut(it, v, true)
} }
return graph.CheckLogOut(it, v, false) return graph.ContainsLogOut(it, v, false)
} }
func (it *Iterator) Size() (int64, bool) { func (it *Iterator) Size() (int64, bool) {
@ -229,8 +229,8 @@ func (it *Iterator) DebugString(indent int) string {
func (it *Iterator) Stats() graph.IteratorStats { func (it *Iterator) Stats() graph.IteratorStats {
size, _ := it.Size() size, _ := it.Size()
return graph.IteratorStats{ return graph.IteratorStats{
CheckCost: 1, ContainsCost: 1,
NextCost: 5, NextCost: 5,
Size: size, Size: size,
} }
} }