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  }