github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/rowexec/inverted_expr_evaluator.go (about)

     1  // Copyright 2020 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package rowexec
    12  
    13  import (
    14  	"bytes"
    15  	"sort"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/sql/opt/invertedexpr"
    18  )
    19  
    20  // The abstractions in this file help with evaluating (batches of)
    21  // invertedexpr.SpanExpression. The spans in a SpanExpression represent spans
    22  // of an inverted index, which consists of an inverted column followed by the
    23  // primary key of the table. The set expressions involve union and
    24  // intersection over operands. The operands are sets of primary keys contained
    25  // in the corresponding span. Callers should use batchedInvertedExprEvaluator.
    26  // This evaluator does not do the actual scan -- it is fed the set elements as
    27  // the inverted index is scanned, and routes a set element to all the sets to
    28  // which it belongs (since spans can be overlapping). Once the scan is
    29  // complete, the expressions are evaluated.
    30  
    31  // KeyIndex is used as a set element. It is already de-duped.
    32  type KeyIndex = int
    33  
    34  // setContainer is a set of key indexes in increasing order.
    35  type setContainer []KeyIndex
    36  
    37  func (s setContainer) Len() int {
    38  	return len(s)
    39  }
    40  
    41  func (s setContainer) Less(i, j int) bool {
    42  	return s[i] < s[j]
    43  }
    44  
    45  func (s setContainer) Swap(i, j int) {
    46  	s[i], s[j] = s[j], s[i]
    47  }
    48  
    49  func unionSetContainers(a, b setContainer) setContainer {
    50  	if len(a) == 0 {
    51  		return b
    52  	}
    53  	if len(b) == 0 {
    54  		return a
    55  	}
    56  	var out setContainer
    57  	var i, j int
    58  	for i < len(a) && j < len(b) {
    59  		if a[i] < b[j] {
    60  			out = append(out, a[i])
    61  			i++
    62  		} else if a[i] > b[j] {
    63  			out = append(out, b[j])
    64  			j++
    65  		} else {
    66  			out = append(out, a[i])
    67  			i++
    68  			j++
    69  		}
    70  	}
    71  	for ; i < len(a); i++ {
    72  		out = append(out, a[i])
    73  	}
    74  	for ; j < len(b); j++ {
    75  		out = append(out, b[j])
    76  	}
    77  	return out
    78  }
    79  
    80  func intersectSetContainers(a, b setContainer) setContainer {
    81  	var out setContainer
    82  	var i, j int
    83  	// TODO(sumeer): when one set is much larger than the other
    84  	// it is more efficient to iterate over the smaller set
    85  	// and seek into the larger set.
    86  	for i < len(a) && j < len(b) {
    87  		if a[i] < b[j] {
    88  			i++
    89  		} else if a[i] > b[j] {
    90  			j++
    91  		} else {
    92  			out = append(out, a[i])
    93  			i++
    94  			j++
    95  		}
    96  	}
    97  	return out
    98  }
    99  
   100  // setExpression follows the structure of SpanExpression.
   101  type setExpression struct {
   102  	op invertedexpr.SetOperator
   103  	// The index in invertedExprEvaluator.sets
   104  	unionSetIndex int
   105  	left          *setExpression
   106  	right         *setExpression
   107  }
   108  
   109  type invertedSpan = invertedexpr.SpanExpressionProto_Span
   110  type spanExpression = invertedexpr.SpanExpressionProto_Node
   111  
   112  // The spans in a SpanExpression.FactoredUnionSpans and the corresponding index
   113  // in invertedExprEvaluator.sets. Only populated when FactoredUnionsSpans is
   114  // non-empty.
   115  type spansAndSetIndex struct {
   116  	spans    []invertedSpan
   117  	setIndex int
   118  }
   119  
   120  // invertedExprEvaluator evaluates a single expression. It should not be directly
   121  // used -- see batchedInvertedExprEvaluator.
   122  type invertedExprEvaluator struct {
   123  	setExpr *setExpression
   124  	// These are initially populated by calls to addIndexRow() as
   125  	// the inverted index is scanned.
   126  	sets []setContainer
   127  
   128  	spansIndex []spansAndSetIndex
   129  }
   130  
   131  func newInvertedExprEvaluator(expr *spanExpression) *invertedExprEvaluator {
   132  	eval := &invertedExprEvaluator{}
   133  	eval.setExpr = eval.initSetExpr(expr)
   134  	return eval
   135  }
   136  
   137  func (ev *invertedExprEvaluator) initSetExpr(expr *spanExpression) *setExpression {
   138  	// Assign it an index even if FactoredUnionSpans is empty, since we will
   139  	// need it when evaluating.
   140  	i := len(ev.sets)
   141  	ev.sets = append(ev.sets, nil)
   142  	sx := &setExpression{op: expr.Operator, unionSetIndex: i}
   143  	if len(expr.FactoredUnionSpans) > 0 {
   144  		ev.spansIndex = append(ev.spansIndex,
   145  			spansAndSetIndex{spans: expr.FactoredUnionSpans, setIndex: i})
   146  	}
   147  	if expr.Left != nil {
   148  		sx.left = ev.initSetExpr(expr.Left)
   149  	}
   150  	if expr.Right != nil {
   151  		sx.right = ev.initSetExpr(expr.Right)
   152  	}
   153  	return sx
   154  }
   155  
   156  // getSpansAndSetIndex returns the spans and corresponding set indexes for
   157  // this expression. The spans are not in sorted order and can be overlapping.
   158  func (ev *invertedExprEvaluator) getSpansAndSetIndex() []spansAndSetIndex {
   159  	return ev.spansIndex
   160  }
   161  
   162  // Adds a row to the given set. KeyIndexes are not added in increasing order,
   163  // nor do they represent any ordering of the primary key of the table whose
   164  // inverted index is being read. Also, the same KeyIndex could be added
   165  // repeatedly to a set.
   166  func (ev *invertedExprEvaluator) addIndexRow(setIndex int, keyIndex KeyIndex) {
   167  	// If duplicates in a set become a memory problem in this build phase, we
   168  	// could do periodic de-duplication as we go. For now, we simply append to
   169  	// the slice and de-dup at the start of evaluate().
   170  	ev.sets[setIndex] = append(ev.sets[setIndex], keyIndex)
   171  }
   172  
   173  // Evaluates the expression. The return value is in increasing order
   174  // of KeyIndex.
   175  func (ev *invertedExprEvaluator) evaluate() []KeyIndex {
   176  	// Sort and de-dup the sets so that we can efficiently do set operations.
   177  	for i, c := range ev.sets {
   178  		if len(c) == 0 {
   179  			continue
   180  		}
   181  		sort.Sort(c)
   182  		// De-duplicate
   183  		set := c[:0]
   184  		for j := range c {
   185  			if len(set) > 0 && c[j] == set[len(set)-1] {
   186  				continue
   187  			}
   188  			set = append(set, c[j])
   189  		}
   190  		ev.sets[i] = set
   191  	}
   192  	return ev.evaluateSetExpr(ev.setExpr)
   193  }
   194  
   195  func (ev *invertedExprEvaluator) evaluateSetExpr(sx *setExpression) setContainer {
   196  	var left, right setContainer
   197  	if sx.left != nil {
   198  		left = ev.evaluateSetExpr(sx.left)
   199  	}
   200  	if sx.right != nil {
   201  		right = ev.evaluateSetExpr(sx.right)
   202  	}
   203  	var childrenSet setContainer
   204  	switch sx.op {
   205  	case invertedexpr.SetUnion:
   206  		childrenSet = unionSetContainers(left, right)
   207  	case invertedexpr.SetIntersection:
   208  		childrenSet = intersectSetContainers(left, right)
   209  	}
   210  	return unionSetContainers(ev.sets[sx.unionSetIndex], childrenSet)
   211  }
   212  
   213  // Supporting struct for invertedSpanRoutingInfo.
   214  type exprAndSetIndex struct {
   215  	// An index into batchedInvertedExprEvaluator.exprEvals.
   216  	exprIndex int
   217  	// An index into batchedInvertedExprEvaluator.exprEvals[exprIndex].sets.
   218  	setIndex int
   219  }
   220  
   221  // invertedSpanRoutingInfo contains the list of exprAndSetIndex pairs that
   222  // need rows from the inverted index span. A []invertedSpanRoutingInfo with
   223  // spans that are sorted and non-overlapping is used to route an added row to
   224  // all the expressions and sets that need that row.
   225  type invertedSpanRoutingInfo struct {
   226  	span                invertedSpan
   227  	exprAndSetIndexList []exprAndSetIndex
   228  }
   229  
   230  // batchedInvertedExprEvaluator is for evaluating one or more expressions. The
   231  // batched evaluator can be reused by calling reset(). In the build phase,
   232  // append expressions directly to exprs. A nil expression is permitted, and is
   233  // just a placeholder that will result in a nil []KeyIndex in evaluate().
   234  // init() must be called before calls to addIndexRow() -- it builds the
   235  // fragmentedSpans used for routing the added rows.
   236  type batchedInvertedExprEvaluator struct {
   237  	exprs []*invertedexpr.SpanExpressionProto
   238  	// The evaluators for all the exprs.
   239  	exprEvals []*invertedExprEvaluator
   240  	// Spans here are in sorted order and non-overlapping.
   241  	fragmentedSpans []invertedSpanRoutingInfo
   242  
   243  	// Temporary state used for constructing fragmentedSpans. All spans here
   244  	// have the same start key. They are not sorted by end key.
   245  	pendingSpans []invertedSpanRoutingInfo
   246  }
   247  
   248  // Helper used in building fragmentedSpans using pendingSpans. pendingSpans
   249  // contains spans with the same start key. This fragments and removes all
   250  // spans up to end key fragmentUntil (or all spans if fragmentUntil == nil).
   251  //
   252  // Example 1:
   253  // pendingSpans contains
   254  //    c---g
   255  //    c-----i
   256  //    c--e
   257  //
   258  // And fragmentUntil = i. Since end keys are exclusive we can fragment and
   259  // remove all spans in pendingSpans. These will be:
   260  //    c-e-g
   261  //    c-e-g-i
   262  //    c-e
   263  //
   264  // For the c-e span, all the exprAndSetIndexList slices for these spans are
   265  // appended since any row in that span needs to be routed to all these
   266  // expressions and sets. For the e-g span only the exprAndSetIndexList slices
   267  // for the top two spans are unioned.
   268  //
   269  // Example 2:
   270  //
   271  // Same pendingSpans, and fragmentUntil = f. The fragments that are generated
   272  // for fragmentedSpans and the remaining spans in pendingSpans are:
   273  //
   274  //    fragments        remaining
   275  //    c-e-f            f-g
   276  //    c-e-f            f-i
   277  //    c-e
   278  func (b *batchedInvertedExprEvaluator) fragmentPendingSpans(
   279  	fragmentUntil invertedexpr.EncInvertedVal,
   280  ) {
   281  	// The start keys are the same, so this only sorts in increasing
   282  	// order of end keys.
   283  	sort.Slice(b.pendingSpans, func(i, j int) bool {
   284  		return bytes.Compare(b.pendingSpans[i].span.End, b.pendingSpans[j].span.End) < 0
   285  	})
   286  	for len(b.pendingSpans) > 0 {
   287  		if fragmentUntil != nil && bytes.Compare(fragmentUntil, b.pendingSpans[0].span.Start) <= 0 {
   288  			break
   289  		}
   290  		// The prefix of pendingSpans that will be completely consumed when
   291  		// the next fragment is constructed.
   292  		var removeSize int
   293  		// The end of the next fragment.
   294  		var end invertedexpr.EncInvertedVal
   295  		// The start of the fragment after the next fragment.
   296  		var nextStart invertedexpr.EncInvertedVal
   297  		if fragmentUntil != nil && bytes.Compare(fragmentUntil, b.pendingSpans[0].span.End) < 0 {
   298  			// Can't completely remove any spans from pendingSpans, but a prefix
   299  			// of these spans will be removed
   300  			removeSize = 0
   301  			end = fragmentUntil
   302  			nextStart = end
   303  		} else {
   304  			// We can remove all spans whose end key is the same as span[0].
   305  			// The end of span[0] is also the end key of this fragment.
   306  			removeSize = b.pendingLenWithSameEnd()
   307  			end = b.pendingSpans[0].span.End
   308  			nextStart = end
   309  		}
   310  		// The next span to be added to fragmentedSpans.
   311  		nextSpan := invertedSpanRoutingInfo{
   312  			span: invertedSpan{
   313  				Start: b.pendingSpans[0].span.Start,
   314  				End:   end,
   315  			},
   316  		}
   317  		for i := 0; i < len(b.pendingSpans); i++ {
   318  			if i >= removeSize {
   319  				// This span is not completely removed so adjust its start.
   320  				b.pendingSpans[i].span.Start = nextStart
   321  			}
   322  			// All spans in pendingSpans contribute to exprAndSetIndexList.
   323  			nextSpan.exprAndSetIndexList =
   324  				append(nextSpan.exprAndSetIndexList, b.pendingSpans[i].exprAndSetIndexList...)
   325  		}
   326  		b.fragmentedSpans = append(b.fragmentedSpans, nextSpan)
   327  		b.pendingSpans = b.pendingSpans[removeSize:]
   328  		if removeSize == 0 {
   329  			// fragmentUntil was earlier than the smallest End key in the pending
   330  			// spans, so cannot fragment any more.
   331  			break
   332  		}
   333  	}
   334  }
   335  
   336  func (b *batchedInvertedExprEvaluator) pendingLenWithSameEnd() int {
   337  	length := 1
   338  	for i := 1; i < len(b.pendingSpans); i++ {
   339  		if !bytes.Equal(b.pendingSpans[0].span.End, b.pendingSpans[i].span.End) {
   340  			break
   341  		}
   342  		length++
   343  	}
   344  	return length
   345  }
   346  
   347  // init fragments the spans for later routing of rows and returns spans
   348  // representing a union of all the spans (for executing the scan).
   349  func (b *batchedInvertedExprEvaluator) init() []invertedSpan {
   350  	if cap(b.exprEvals) < len(b.exprs) {
   351  		b.exprEvals = make([]*invertedExprEvaluator, len(b.exprs))
   352  	} else {
   353  		b.exprEvals = b.exprEvals[:len(b.exprs)]
   354  	}
   355  	// Initial spans fetched from all expressions.
   356  	var routingSpans []invertedSpanRoutingInfo
   357  	for i, expr := range b.exprs {
   358  		if expr == nil {
   359  			b.exprEvals[i] = nil
   360  			continue
   361  		}
   362  		b.exprEvals[i] = newInvertedExprEvaluator(&expr.Node)
   363  		exprSpans := b.exprEvals[i].getSpansAndSetIndex()
   364  		for _, spans := range exprSpans {
   365  			for _, span := range spans.spans {
   366  				routingSpans = append(routingSpans,
   367  					invertedSpanRoutingInfo{
   368  						span:                span,
   369  						exprAndSetIndexList: []exprAndSetIndex{{exprIndex: i, setIndex: spans.setIndex}},
   370  					},
   371  				)
   372  			}
   373  		}
   374  	}
   375  	if len(routingSpans) == 0 {
   376  		return nil
   377  	}
   378  
   379  	// Sort the routingSpans in increasing order of start key, and for equal
   380  	// start keys in increasing order of end key.
   381  	sort.Slice(routingSpans, func(i, j int) bool {
   382  		cmp := bytes.Compare(routingSpans[i].span.Start, routingSpans[j].span.Start)
   383  		if cmp == 0 {
   384  			cmp = bytes.Compare(routingSpans[i].span.End, routingSpans[j].span.End)
   385  		}
   386  		return cmp < 0
   387  	})
   388  
   389  	// The union of the spans, which is returned from this function.
   390  	var coveringSpans []invertedSpan
   391  	currentCoveringSpan := routingSpans[0].span
   392  	b.pendingSpans = append(b.pendingSpans, routingSpans[0])
   393  	// This loop does both the union of the routingSpans and fragments the
   394  	// routingSpans.
   395  	for i := 1; i < len(routingSpans); i++ {
   396  		span := routingSpans[i]
   397  		if bytes.Compare(b.pendingSpans[0].span.Start, span.span.Start) < 0 {
   398  			b.fragmentPendingSpans(span.span.Start)
   399  			if bytes.Compare(currentCoveringSpan.End, span.span.Start) < 0 {
   400  				coveringSpans = append(coveringSpans, currentCoveringSpan)
   401  				currentCoveringSpan = span.span
   402  			} else if bytes.Compare(currentCoveringSpan.End, span.span.End) < 0 {
   403  				currentCoveringSpan.End = span.span.End
   404  			}
   405  		} else if bytes.Compare(currentCoveringSpan.End, span.span.End) < 0 {
   406  			currentCoveringSpan.End = span.span.End
   407  		}
   408  		// Add this span to the pending list.
   409  		b.pendingSpans = append(b.pendingSpans, span)
   410  	}
   411  	b.fragmentPendingSpans(nil)
   412  	coveringSpans = append(coveringSpans, currentCoveringSpan)
   413  	return coveringSpans
   414  }
   415  
   416  // TODO(sumeer): if this will be called in non-decreasing order of enc,
   417  // use that to optimize the binary search.
   418  func (b *batchedInvertedExprEvaluator) addIndexRow(
   419  	enc invertedexpr.EncInvertedVal, keyIndex KeyIndex,
   420  ) {
   421  	i := sort.Search(len(b.fragmentedSpans), func(i int) bool {
   422  		return bytes.Compare(b.fragmentedSpans[i].span.Start, enc) > 0
   423  	})
   424  	i--
   425  	for _, elem := range b.fragmentedSpans[i].exprAndSetIndexList {
   426  		b.exprEvals[elem.exprIndex].addIndexRow(elem.setIndex, keyIndex)
   427  	}
   428  }
   429  
   430  func (b *batchedInvertedExprEvaluator) evaluate() [][]KeyIndex {
   431  	result := make([][]KeyIndex, len(b.exprs))
   432  	for i := range b.exprEvals {
   433  		if b.exprEvals[i] == nil {
   434  			continue
   435  		}
   436  		result[i] = b.exprEvals[i].evaluate()
   437  	}
   438  	return result
   439  }
   440  
   441  func (b *batchedInvertedExprEvaluator) reset() {
   442  	b.exprs = b.exprs[:0]
   443  	b.exprEvals = b.exprEvals[:0]
   444  	b.fragmentedSpans = b.fragmentedSpans[:0]
   445  	b.pendingSpans = b.pendingSpans[:0]
   446  }