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 }