github.com/m3db/m3@v1.5.0/src/query/functions/binary/or.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package binary 22 23 import ( 24 "math" 25 26 "github.com/m3db/m3/src/query/block" 27 "github.com/m3db/m3/src/query/executor/transform" 28 "github.com/m3db/m3/src/query/models" 29 ) 30 31 // OrType uses all values from left hand side, and appends values from the 32 // right hand side which do not have corresponding tags on the right. 33 const OrType = "or" 34 35 func makeOrBlock( 36 queryCtx *models.QueryContext, 37 lMeta, rMeta block.Metadata, 38 lIter, rIter block.StepIter, 39 controller *transform.Controller, 40 matching VectorMatching, 41 ) (block.Block, error) { 42 if !matching.Set { 43 return nil, errNoMatching 44 } 45 46 lSeriesMetas := lIter.SeriesMeta() 47 lMeta, lSeriesMetas = removeNameTags(lMeta, lSeriesMetas) 48 lMeta, lSeriesMetas = removeNameTags(lMeta, lSeriesMetas) 49 50 rSeriesMetas := rIter.SeriesMeta() 51 rMeta, rSeriesMetas = removeNameTags(rMeta, rSeriesMetas) 52 53 meta, lSeriesMetas, rSeriesMetas, err := combineMetaAndSeriesMeta( 54 lMeta, 55 rMeta, 56 lSeriesMetas, 57 rSeriesMetas, 58 ) 59 60 if err != nil { 61 return nil, err 62 } 63 64 indices, combinedSeriesMeta := mergeIndices( 65 matching, 66 lSeriesMetas, 67 rSeriesMetas, 68 ) 69 70 builder, err := controller.BlockBuilder(queryCtx, meta, combinedSeriesMeta) 71 if err != nil { 72 return nil, err 73 } 74 75 if err = builder.AddCols(lIter.StepCount()); err != nil { 76 return nil, err 77 } 78 79 values := make([]float64, len(combinedSeriesMeta)) 80 for index := 0; lIter.Next(); index++ { 81 if !rIter.Next() { 82 return nil, errRExhausted 83 } 84 85 lStep := lIter.Current() 86 lValues := lStep.Values() 87 copy(values, lValues) 88 rStep := rIter.Current() 89 rValues := rStep.Values() 90 for iterIndex, valueIndex := range indices { 91 if valueIndex >= len(lValues) { 92 values[valueIndex] = rValues[iterIndex] 93 } else if math.IsNaN(values[valueIndex]) { 94 values[valueIndex] = rValues[iterIndex] 95 } 96 } 97 98 if err := builder.AppendValues(index, values); err != nil { 99 return nil, err 100 } 101 } 102 103 if err = lIter.Err(); err != nil { 104 return nil, err 105 } 106 107 if rIter.Next() { 108 return nil, errLExhausted 109 } 110 111 if err = rIter.Err(); err != nil { 112 return nil, err 113 } 114 115 return builder.Build(), nil 116 } 117 118 // mergeIndices returns a slice that maps rhs series to lhs series. 119 // 120 // NB(arnikola): if the series in the rhs does not exist in the lhs, it is 121 // added after all lhs series have been added. 122 // This function also combines the series metadatas for the entire block. 123 func mergeIndices( 124 matching VectorMatching, 125 lhs, rhs []block.SeriesMeta, 126 ) ([]int, []block.SeriesMeta) { 127 idFunction := hashFunc(matching.On, matching.MatchingLabels...) 128 // The set of signatures for the left-hand side. 129 leftSigs := make(map[uint64]int, len(lhs)) 130 for i, meta := range lhs { 131 l := idFunction(meta.Tags) 132 leftSigs[l] = i 133 } 134 135 rIndices := make([]int, len(rhs)) 136 rIndex := len(lhs) 137 for i, meta := range rhs { 138 // If there's no matching entry in the left-hand side Vector, 139 // add the sample. 140 r := idFunction(meta.Tags) 141 if matchingIndex, ok := leftSigs[r]; !ok { 142 rIndices[i] = rIndex 143 rIndex++ 144 lhs = append(lhs, meta) 145 } else { 146 rIndices[i] = matchingIndex 147 } 148 } 149 150 return rIndices, lhs 151 }