Move iterators into separate package
Also reduce API exposure and use standard library more - and fix bugs I previously introduces in mongo.
This commit is contained in:
parent
88be6bee37
commit
1768e593a8
62 changed files with 3240 additions and 3130 deletions
183
graph/iterator/linksto_iterator.go
Normal file
183
graph/iterator/linksto_iterator.go
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
// Copyright 2014 The Cayley Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package iterator
|
||||
|
||||
// Defines one of the base iterators, the LinksTo iterator. A LinksTo takes a
|
||||
// subiterator of nodes, and contains an iteration of links which "link to"
|
||||
// those nodes in a given direction.
|
||||
//
|
||||
// Next()ing a LinksTo is straightforward -- iterate through all links to //
|
||||
// things in the subiterator, and then advance the subiterator, and do it again.
|
||||
// LinksTo is therefore sensitive to growing with a fanout. (A small-sized
|
||||
// subiterator could cause LinksTo to be large).
|
||||
//
|
||||
// Check()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
|
||||
// similar to checking the subiterator alone.
|
||||
//
|
||||
// Can be seen as the dual of the HasA iterator.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/cayley/graph"
|
||||
)
|
||||
|
||||
// A LinksTo has a reference back to the graph.TripleStore (to create the iterators
|
||||
// for each node) the subiterator, and the direction the iterator comes from.
|
||||
// `next_it` is the tempoarary iterator held per result in `primary_it`.
|
||||
type LinksTo struct {
|
||||
Base
|
||||
ts graph.TripleStore
|
||||
primaryIt graph.Iterator
|
||||
dir graph.Direction
|
||||
nextIt graph.Iterator
|
||||
}
|
||||
|
||||
// Construct a new LinksTo iterator around a direction and a subiterator of
|
||||
// nodes.
|
||||
func NewLinksTo(ts graph.TripleStore, it graph.Iterator, d graph.Direction) *LinksTo {
|
||||
var lto LinksTo
|
||||
BaseInit(<o.Base)
|
||||
lto.ts = ts
|
||||
lto.primaryIt = it
|
||||
lto.dir = d
|
||||
lto.nextIt = &Null{}
|
||||
return <o
|
||||
}
|
||||
|
||||
func (it *LinksTo) Reset() {
|
||||
it.primaryIt.Reset()
|
||||
if it.nextIt != nil {
|
||||
it.nextIt.Close()
|
||||
}
|
||||
it.nextIt = &Null{}
|
||||
}
|
||||
|
||||
func (it *LinksTo) Clone() graph.Iterator {
|
||||
out := NewLinksTo(it.ts, it.primaryIt.Clone(), it.dir)
|
||||
out.CopyTagsFrom(it)
|
||||
return out
|
||||
}
|
||||
|
||||
// Return the direction under consideration.
|
||||
func (it *LinksTo) Direction() graph.Direction { return it.dir }
|
||||
|
||||
// Tag these results, and our subiterator's results.
|
||||
func (it *LinksTo) TagResults(out *map[string]graph.TSVal) {
|
||||
it.Base.TagResults(out)
|
||||
it.primaryIt.TagResults(out)
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
func (it *LinksTo) GetResultTree() *graph.ResultTree {
|
||||
tree := graph.NewResultTree(it.LastResult())
|
||||
tree.AddSubtree(it.primaryIt.GetResultTree())
|
||||
return tree
|
||||
}
|
||||
|
||||
// Print the iterator.
|
||||
func (it *LinksTo) DebugString(indent int) string {
|
||||
return fmt.Sprintf("%s(%s %d direction:%s\n%s)",
|
||||
strings.Repeat(" ", indent),
|
||||
it.Type(), it.GetUid(), it.dir, it.primaryIt.DebugString(indent+4))
|
||||
}
|
||||
|
||||
// If it checks in the right direction for the subiterator, it is a valid link
|
||||
// for the LinksTo.
|
||||
func (it *LinksTo) Check(val graph.TSVal) bool {
|
||||
CheckLogIn(it, val)
|
||||
node := it.ts.GetTripleDirection(val, it.dir)
|
||||
if it.primaryIt.Check(node) {
|
||||
it.Last = val
|
||||
return CheckLogOut(it, val, true)
|
||||
}
|
||||
return CheckLogOut(it, val, false)
|
||||
}
|
||||
|
||||
// Return a list containing only our subiterator.
|
||||
func (it *LinksTo) GetSubIterators() []graph.Iterator {
|
||||
return []graph.Iterator{it.primaryIt}
|
||||
}
|
||||
|
||||
// Optimize the LinksTo, by replacing it if it can be.
|
||||
func (it *LinksTo) Optimize() (graph.Iterator, bool) {
|
||||
newPrimary, changed := it.primaryIt.Optimize()
|
||||
if changed {
|
||||
it.primaryIt = newPrimary
|
||||
if it.primaryIt.Type() == "null" {
|
||||
it.nextIt.Close()
|
||||
return it.primaryIt, true
|
||||
}
|
||||
}
|
||||
// Ask the graph.TripleStore if we can be replaced. Often times, this is a great
|
||||
// optimization opportunity (there's a fixed iterator underneath us, for
|
||||
// example).
|
||||
newReplacement, hasOne := it.ts.OptimizeIterator(it)
|
||||
if hasOne {
|
||||
it.Close()
|
||||
return newReplacement, true
|
||||
}
|
||||
return it, false
|
||||
}
|
||||
|
||||
// Next()ing a LinksTo operates as described above.
|
||||
func (it *LinksTo) Next() (graph.TSVal, bool) {
|
||||
NextLogIn(it)
|
||||
val, ok := it.nextIt.Next()
|
||||
if !ok {
|
||||
// Subiterator is empty, get another one
|
||||
candidate, ok := it.primaryIt.Next()
|
||||
if !ok {
|
||||
// We're out of nodes in our subiterator, so we're done as well.
|
||||
return NextLogOut(it, 0, false)
|
||||
}
|
||||
it.nextIt.Close()
|
||||
it.nextIt = it.ts.GetTripleIterator(it.dir, candidate)
|
||||
// Recurse -- return the first in the next set.
|
||||
return it.Next()
|
||||
}
|
||||
it.Last = val
|
||||
return NextLogOut(it, val, ok)
|
||||
}
|
||||
|
||||
// Close our subiterators.
|
||||
func (it *LinksTo) Close() {
|
||||
it.nextIt.Close()
|
||||
it.primaryIt.Close()
|
||||
}
|
||||
|
||||
// We won't ever have a new result, but our subiterators might.
|
||||
func (it *LinksTo) NextResult() bool {
|
||||
return it.primaryIt.NextResult()
|
||||
}
|
||||
|
||||
// Register the LinksTo.
|
||||
func (it *LinksTo) Type() string { return "linksto" }
|
||||
|
||||
// Return a guess as to how big or costly it is to next the iterator.
|
||||
func (it *LinksTo) GetStats() *graph.IteratorStats {
|
||||
subitStats := it.primaryIt.GetStats()
|
||||
// TODO(barakmich): These should really come from the triplestore itself
|
||||
fanoutFactor := int64(20)
|
||||
checkConstant := int64(1)
|
||||
nextConstant := int64(2)
|
||||
return &graph.IteratorStats{
|
||||
NextCost: nextConstant + subitStats.NextCost,
|
||||
CheckCost: checkConstant + subitStats.CheckCost,
|
||||
Size: fanoutFactor * subitStats.Size,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue