docMatchTree: compute document ids lazily
Instead of precomputing all document ids for a docMatchTree, we compute
them lazily based on a predicate.
Change-Id: I3acf414f6bb18fc1d71f2cde2bdc784c3dd984b3
diff --git a/matchtree.go b/matchtree.go
index 4c04779..66d9372 100644
--- a/matchtree.go
+++ b/matchtree.go
@@ -82,10 +82,20 @@
matches(cp *contentProvider, cost int, known map[matchTree]bool) (match bool, sure bool)
}
+// docMatchTree iterates over documents for which predicate(docID) returns true.
type docMatchTree struct {
+ // the number of documents in a shard.
+ numDocs uint32
+
+ predicate func(docID uint32) bool
+
+ // provides additional information about the reason why the docMatchTree was
+ // created.
+ reason string
+
// mutable
- docs []uint32
- current []uint32
+ firstDone bool
+ docID uint32
}
type bruteForceMatchTree struct {
@@ -157,15 +167,8 @@
}
func (t *docMatchTree) prepare(doc uint32) {
- for len(t.docs) > 0 && t.docs[0] < doc {
- t.docs = t.docs[1:]
- }
- i := 0
- for ; i < len(t.docs) && t.docs[i] == doc; i++ {
- }
-
- t.current = t.docs[:i]
- t.docs = t.docs[i:]
+ t.docID = doc
+ t.firstDone = true
}
func (t *andMatchTree) prepare(doc uint32) {
@@ -204,10 +207,16 @@
// nextDoc
func (t *docMatchTree) nextDoc() uint32 {
- if len(t.docs) == 0 {
- return maxUInt32
+ var start uint32
+ if t.firstDone {
+ start = t.docID + 1
}
- return t.docs[0]
+ for i := start; i < t.numDocs; i++ {
+ if t.predicate(i) {
+ return i
+ }
+ }
+ return maxUInt32
}
func (t *bruteForceMatchTree) nextDoc() uint32 {
@@ -264,7 +273,7 @@
}
func (t *docMatchTree) String() string {
- return fmt.Sprintf("docs%v", t.docs)
+ return fmt.Sprintf("doc(%s)", t.reason)
}
func (t *andMatchTree) String() string {
@@ -348,7 +357,7 @@
// all matches() methods.
func (t *docMatchTree) matches(cp *contentProvider, cost int, known map[matchTree]bool) (bool, bool) {
- return len(t.current) > 0, true
+ return t.predicate(cp.idx), true
}
func (t *bruteForceMatchTree) matches(cp *contentProvider, cost int, known map[matchTree]bool) (bool, bool) {
@@ -677,14 +686,12 @@
if !ok {
return &noMatchTree{"lang"}, nil
}
- docs := make([]uint32, 0, len(d.languages))
- for d, l := range d.languages {
- if l == code {
- docs = append(docs, uint32(d))
- }
- }
return &docMatchTree{
- docs: docs,
+ reason: "language",
+ numDocs: uint32(len(d.languages)),
+ predicate: func(docID uint32) bool {
+ return d.languages[docID] == code
+ },
}, nil
case *query.Symbol: