github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/segment/segexecution.go (about) 1 /* 2 Copyright 2023. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package segment 18 19 import ( 20 "encoding/json" 21 "errors" 22 "math" 23 "time" 24 25 dtu "github.com/siglens/siglens/pkg/common/dtypeutils" 26 rutils "github.com/siglens/siglens/pkg/readerUtils" 27 agg "github.com/siglens/siglens/pkg/segment/aggregations" 28 "github.com/siglens/siglens/pkg/segment/query" 29 "github.com/siglens/siglens/pkg/segment/query/summary" 30 "github.com/siglens/siglens/pkg/segment/results/mresults" 31 "github.com/siglens/siglens/pkg/segment/structs" 32 "github.com/siglens/siglens/pkg/segment/utils" 33 34 log "github.com/sirupsen/logrus" 35 ) 36 37 func ExecuteMetricsQuery(mQuery *structs.MetricsQuery, timeRange *dtu.MetricsTimeRange, qid uint64) *mresults.MetricsResult { 38 querySummary := summary.InitQuerySummary(summary.METRICS, qid) 39 defer querySummary.LogMetricsQuerySummary(mQuery.OrgId) 40 _, err := query.StartQuery(qid, false) 41 if err != nil { 42 log.Errorf("ExecuteAsyncQuery: Error initializing query status! %+v", err) 43 return &mresults.MetricsResult{ 44 ErrList: []error{err}, 45 } 46 } 47 res := query.ApplyMetricsQuery(mQuery, timeRange, qid, querySummary) 48 query.DeleteQuery(qid) 49 querySummary.IncrementNumResultSeries(res.GetNumSeries()) 50 return res 51 } 52 53 func ExecuteMultipleMetricsQuery(hashList []uint64, mQueries []*structs.MetricsQuery, queryOps []structs.QueryArithmetic, timeRange *dtu.MetricsTimeRange, qid uint64) *mresults.MetricsResult { 54 resMap := make(map[uint64]*mresults.MetricsResult) 55 for index, mQuery := range mQueries { 56 querySummary := summary.InitQuerySummary(summary.METRICS, qid) 57 defer querySummary.LogMetricsQuerySummary(mQuery.OrgId) 58 _, err := query.StartQuery(qid, false) 59 if err != nil { 60 log.Errorf("ExecuteAsyncQuery: Error initializing query status! %+v", err) 61 return &mresults.MetricsResult{ 62 ErrList: []error{err}, 63 } 64 } 65 res := query.ApplyMetricsQuery(mQuery, timeRange, qid, querySummary) 66 query.DeleteQuery(qid) 67 querySummary.IncrementNumResultSeries(res.GetNumSeries()) 68 qid = rutils.GetNextQid() 69 resMap[hashList[index]] = res 70 if len(mQueries) == 1 && len(queryOps) == 0 { 71 return res 72 } 73 } 74 75 return helperQueryArithmetic(queryOps, resMap) 76 } 77 78 func helperQueryArithmetic(queryOps []structs.QueryArithmetic, resMap map[uint64]*mresults.MetricsResult) *mresults.MetricsResult { 79 finalResult := make(map[string]map[uint32]float64) 80 for _, queryOp := range queryOps { 81 resultLHS := resMap[queryOp.LHS] 82 resultRHS := resMap[queryOp.RHS] 83 swapped := false 84 if queryOp.ConstantOp { 85 resultLHS, ok := resMap[queryOp.LHS] 86 valueRHS := queryOp.Constant 87 if !ok { //this means the rhs is a vector result 88 swapped = true 89 resultLHS = resMap[queryOp.RHS] 90 } 91 92 for groupID, tsLHS := range resultLHS.Results { 93 finalResult[groupID] = make(map[uint32]float64) 94 for timestamp, valueLHS := range tsLHS { 95 switch queryOp.Operation { 96 case utils.Add: 97 finalResult[groupID][timestamp] = valueLHS + valueRHS 98 case utils.Divide: 99 if valueRHS == 0 { 100 continue 101 } 102 if swapped { 103 valueRHS = 1 / valueRHS 104 } 105 finalResult[groupID][timestamp] = valueLHS / valueRHS 106 case utils.Multiply: 107 finalResult[groupID][timestamp] = valueLHS * valueRHS 108 case utils.Subtract: 109 val := valueLHS - valueRHS 110 if swapped { 111 val = val * -1 112 } 113 finalResult[groupID][timestamp] = val 114 } 115 } 116 } 117 118 } else { 119 for groupID, tsLHS := range resultLHS.Results { 120 if _, ok := resultRHS.Results[groupID]; !ok { 121 continue 122 } //Entries for which no matching entry in the right-hand vector are dropped 123 finalResult[groupID] = make(map[uint32]float64) 124 for timestamp, valueLHS := range tsLHS { 125 valueRHS := resultRHS.Results[groupID][timestamp] 126 switch queryOp.Operation { 127 case utils.Add: 128 finalResult[groupID][timestamp] = valueLHS + valueRHS 129 case utils.Divide: 130 if valueRHS == 0 { 131 continue 132 } 133 finalResult[groupID][timestamp] = valueLHS / valueRHS 134 case utils.Multiply: 135 finalResult[groupID][timestamp] = valueLHS * valueRHS 136 case utils.Subtract: 137 finalResult[groupID][timestamp] = valueLHS - valueRHS 138 } 139 } 140 } 141 } 142 } 143 144 return &mresults.MetricsResult{Results: finalResult, State: mresults.AGGREGATED} 145 } 146 147 func ExecuteQuery(root *structs.ASTNode, aggs *structs.QueryAggregators, qid uint64, qc *structs.QueryContext) *structs.NodeResult { 148 149 rQuery, err := query.StartQuery(qid, false) 150 if err != nil { 151 log.Errorf("ExecuteQuery: Error initializing query status! %+v", err) 152 return &structs.NodeResult{ 153 ErrList: []error{err}, 154 } 155 } 156 res := executeQueryInternal(root, aggs, qid, qc, rQuery) 157 res.ApplyScroll(qc.Scroll) 158 res.TotalRRCCount, err = query.GetNumMatchedRRCs(qid) 159 160 if err != nil { 161 log.Errorf("qid=%d, ExecuteQuery: failed to get number of RRCs for qid! Error: %v", qid, err) 162 } 163 164 query.DeleteQuery(qid) 165 166 return res 167 } 168 169 // The caller of this function is responsible for calling query.DeleteQuery(qid) to remove the qid info from memory. 170 // Returns a channel that will have events for query status or any error. An error means the query was not successfully started 171 func ExecuteAsyncQuery(root *structs.ASTNode, aggs *structs.QueryAggregators, qid uint64, qc *structs.QueryContext) (chan *query.QueryStateChanData, error) { 172 rQuery, err := query.StartQuery(qid, true) 173 if err != nil { 174 log.Errorf("ExecuteAsyncQuery: Error initializing query status! %+v", err) 175 return nil, err 176 } 177 178 go func() { 179 _ = executeQueryInternal(root, aggs, qid, qc, rQuery) 180 }() 181 return rQuery.StateChan, nil 182 } 183 184 func executeQueryInternal(root *structs.ASTNode, aggs *structs.QueryAggregators, qid uint64, 185 qc *structs.QueryContext, rQuery *query.RunningQueryState) *structs.NodeResult { 186 187 startTime := time.Now() 188 189 if qc.GetNumTables() == 0 { 190 log.Infof("qid=%d, ExecuteQuery: empty array of Index Names provided", qid) 191 return &structs.NodeResult{ 192 ErrList: []error{errors.New("empty array of Index Names provided")}, 193 } 194 } 195 if qc.SizeLimit == math.MaxUint64 { 196 qc.SizeLimit = math.MaxInt64 // temp Fix: Will debug and remove it. 197 } 198 // if query aggregations exist, get all results then truncate after 199 nodeRes := query.ApplyFilterOperator(root, root.TimeRange, aggs, qid, qc) 200 if aggs != nil { 201 numTotalSegments, err := query.GetTotalSegmentsToSearch(qid) 202 if err != nil { 203 log.Errorf("executeQueryInternal: failed to get number of total segments for qid! Error: %v", err) 204 } 205 nodeRes = agg.PostQueryBucketCleaning(nodeRes, aggs, nil, nil, nil, numTotalSegments, false) 206 } 207 // truncate final results after running post aggregations 208 if uint64(len(nodeRes.AllRecords)) > qc.SizeLimit { 209 nodeRes.AllRecords = nodeRes.AllRecords[0:qc.SizeLimit] 210 } 211 log.Infof("qid=%d, Finished execution in %+v", qid, time.Since(startTime)) 212 213 if rQuery.IsAsync() && aggs != nil && aggs.Next != nil { 214 err := query.SetFinalStatsForQid(qid, nodeRes) 215 if err != nil { 216 log.Errorf("executeQueryInternal: failed to set final stats: %v", err) 217 } 218 rQuery.SendQueryStateComplete() 219 } 220 return nodeRes 221 } 222 223 func LogSearchNode(prefix string, sNode *structs.SearchNode, qid uint64) { 224 225 sNodeJSON, _ := json.Marshal(sNode) 226 log.Infof("qid=%d, SearchNode for %v: %v", qid, prefix, string(sNodeJSON)) 227 } 228 229 func LogASTNode(prefix string, astNode *structs.ASTNode, qid uint64) { 230 231 fullASTNodeJSON, _ := json.Marshal(astNode) 232 log.Infof("qid=%d, ASTNode for %v: %v", qid, prefix, string(fullASTNodeJSON)) 233 } 234 235 func LogNode(prefix string, node any, qid uint64) { 236 237 nodeJSON, _ := json.Marshal(node) 238 log.Infof("qid=%d, Raw value for %v: %v", qid, prefix, string(nodeJSON)) 239 } 240 241 func LogQueryAggsNode(prefix string, node *structs.QueryAggregators, qid uint64) { 242 243 nodeval, _ := json.Marshal(node) 244 log.Infof("qid=%d, QueryAggregators for %v: %v", qid, prefix, string(nodeval)) 245 } 246 247 func LogMetricsQuery(prefix string, mQRequest *structs.MetricsQueryRequest, qid uint64) { 248 mQRequestJSON, _ := json.Marshal(mQRequest) 249 log.Infof("qid=%d, mQRequest for %v: %v", qid, prefix, string(mQRequestJSON)) 250 } 251 252 func LogQueryContext(qc *structs.QueryContext, qid uint64) { 253 fullQueryContextJSON, _ := json.Marshal(qc) 254 log.Infof("qid=%d,Query context: %v", qid, string(fullQueryContextJSON)) 255 }