github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/segment/query/segqueryhelpers.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 query 18 19 import ( 20 "fmt" 21 22 dtu "github.com/siglens/siglens/pkg/common/dtypeutils" 23 "github.com/siglens/siglens/pkg/config" 24 "github.com/siglens/siglens/pkg/querytracker" 25 "github.com/siglens/siglens/pkg/segment/query/summary" 26 "github.com/siglens/siglens/pkg/segment/search" 27 "github.com/siglens/siglens/pkg/segment/structs" 28 "github.com/siglens/siglens/pkg/segment/utils" 29 log "github.com/sirupsen/logrus" 30 ) 31 32 // Holder struct for all query information 33 type queryInformation struct { 34 sNode *structs.SearchNode 35 aggs *structs.QueryAggregators 36 queryRange *dtu.TimeRange 37 colsToSearch map[string]bool 38 indexInfo *structs.TableInfo 39 sizeLimit uint64 40 pqid string 41 parallelismPerFile int64 42 dqs *DistributedQueryService 43 persistentQuery bool 44 qid uint64 45 sNodeType structs.SearchNodeType 46 qType structs.QueryType 47 orgId uint64 48 } 49 50 type querySegmentRequest struct { 51 queryInformation 52 segKey string 53 segKeyTsRange *dtu.TimeRange 54 tableName string 55 sType structs.SegType 56 blkTracker *structs.BlockTracker 57 HasMatchedRrc bool 58 } 59 60 /* 61 Returns a holder struct with query information 62 63 # This contains DistributedQueryService, which will be used to send grpcs to other nodes as needed 64 65 The caller is responsible for calling qs.Wait() to wait for all grpcs to finish 66 */ 67 func InitQueryInformation(s *structs.SearchNode, aggs *structs.QueryAggregators, queryRange *dtu.TimeRange, 68 indexInfo *structs.TableInfo, sizeLimit uint64, parallelismPerFile int64, qid uint64, 69 dqs *DistributedQueryService, orgid uint64) (*queryInformation, error) { 70 colsToSearch, _, _ := search.GetAggColsAndTimestamp(aggs) 71 isQueryPersistent, err := querytracker.IsQueryPersistent(indexInfo.GetQueryTables(), s) 72 if err != nil { 73 log.Errorf("InitQueryInformation: failed to check if query is persistent! Err %v", err) 74 return &queryInformation{}, err 75 } 76 pqid := querytracker.GetHashForQuery(s) 77 sNodeType, qType := getQueryType(s, aggs) 78 return &queryInformation{ 79 sNode: s, 80 aggs: aggs, 81 queryRange: queryRange, 82 colsToSearch: colsToSearch, 83 indexInfo: indexInfo, 84 sizeLimit: sizeLimit, 85 pqid: pqid, 86 parallelismPerFile: parallelismPerFile, 87 dqs: dqs, 88 persistentQuery: isQueryPersistent, 89 qid: qid, 90 sNodeType: sNodeType, 91 qType: qType, 92 orgId: orgid, 93 }, nil 94 } 95 96 // waits and closes the distributed query service 97 func (qi *queryInformation) Wait(querySummary *summary.QuerySummary) error { 98 return qi.dqs.Wait(qi.qid, querySummary) 99 } 100 101 // returns map[table] -> map[segKey] -> blkTracker to pass into MicroIndexCheck and ExtractSSRFromSearchNode 102 // Returns error if qsr.blkTracker is nil 103 func (qsr *querySegmentRequest) GetMicroIndexFilter() (map[string]map[string]*structs.BlockTracker, error) { 104 if qsr.blkTracker == nil { 105 log.Errorf("GetMicroIndexFilter: qsr.blkTracker is nil! Cannot construct keys & blocks to filter") 106 return nil, fmt.Errorf("GetMicroIndexFilter: qsr.blkTracker is nil! Cannot construct keys & blocks to filter") 107 } 108 retVal := make(map[string]map[string]*structs.BlockTracker) 109 retVal[qsr.tableName] = make(map[string]*structs.BlockTracker) 110 retVal[qsr.tableName][qsr.segKey] = qsr.blkTracker 111 return retVal, nil 112 } 113 114 // returns map[table] -> map[segKey] -> entire file block tracker to pass into MicroIndexCheck and ExtractSSRFromSearchNode 115 func (qsr *querySegmentRequest) GetEntireFileMicroIndexFilter() map[string]map[string]*structs.BlockTracker { 116 retVal := make(map[string]map[string]*structs.BlockTracker) 117 retVal[qsr.tableName] = make(map[string]*structs.BlockTracker) 118 retVal[qsr.tableName][qsr.segKey] = structs.InitEntireFileBlockTracker() 119 return retVal 120 } 121 122 func ConvertASTNodeToSearchNode(node *structs.ASTNode, qid uint64) *structs.SearchNode { 123 currNode := &structs.SearchNode{} 124 if node.AndFilterCondition != nil { 125 currNode.AndSearchConditions = convertASTConditionToSearchCondition(node.AndFilterCondition, qid) 126 } 127 128 if node.OrFilterCondition != nil { 129 currNode.OrSearchConditions = convertASTConditionToSearchCondition(node.OrFilterCondition, qid) 130 } 131 // for exclusion, only join the column info for files that exist and not the actual search request info 132 // exclusion conditions should not influence raw blocks to search 133 if node.ExclusionFilterCondition != nil { 134 currNode.ExclusionSearchConditions = convertASTConditionToSearchCondition(node.ExclusionFilterCondition, qid) 135 } 136 currNode.AddQueryInfoForNode() 137 return currNode 138 } 139 140 func convertASTConditionToSearchCondition(condition *structs.Condition, qid uint64) *structs.SearchCondition { 141 currSearch := &structs.SearchCondition{} 142 if condition.FilterCriteria != nil && len(condition.FilterCriteria) > 0 { 143 currSearch.SearchQueries = convertFilterCriteraToSearchQuery(condition.FilterCriteria, qid) 144 } 145 146 if condition.NestedNodes != nil && len(condition.NestedNodes) > 0 { 147 for _, node := range condition.NestedNodes { 148 searchNodes := ConvertASTNodeToSearchNode(node, qid) 149 150 if currSearch.SearchNode == nil { 151 currSearch.SearchNode = make([]*structs.SearchNode, 0) 152 } 153 currSearch.SearchNode = append(currSearch.SearchNode, searchNodes) 154 } 155 } 156 return currSearch 157 } 158 159 func convertFilterCriteraToSearchQuery(conditions []*structs.FilterCriteria, qid uint64) []*structs.SearchQuery { 160 finalSearchQueries := make([]*structs.SearchQuery, 0) 161 for _, filter := range conditions { 162 currQuery := structs.GetSearchQueryFromFilterCriteria(filter, qid) 163 finalSearchQueries = append(finalSearchQueries, currQuery) 164 } 165 return finalSearchQueries 166 } 167 168 // put this in segwriter -> raw search unrotated 169 func ExtractSSRFromSearchNode(node *structs.SearchNode, filesToSearch map[string]map[string]*structs.BlockTracker, timeRange *dtu.TimeRange, 170 indexNames []string, querySummary *summary.QuerySummary, qid uint64, isQueryPersistent bool, pqid string) map[string]*structs.SegmentSearchRequest { 171 // todo: better joining of intermediate results of block summaries 172 finalList := make(map[string]*structs.SegmentSearchRequest) 173 if node.AndSearchConditions != nil { 174 andSegmentFiles := extractSSRFromCondition(node.AndSearchConditions, utils.And, 175 filesToSearch, timeRange, indexNames, querySummary, qid, isQueryPersistent, pqid) 176 for fileName, searchReq := range andSegmentFiles { 177 if _, ok := finalList[fileName]; !ok { 178 finalList[fileName] = searchReq 179 continue 180 } 181 finalList[fileName].JoinRequest(searchReq, utils.And) 182 } 183 } 184 185 if node.OrSearchConditions != nil { 186 orSegmentFiles := extractSSRFromCondition(node.OrSearchConditions, utils.Or, 187 filesToSearch, timeRange, indexNames, querySummary, qid, isQueryPersistent, pqid) 188 for fileName, searchReq := range orSegmentFiles { 189 if _, ok := finalList[fileName]; !ok { 190 finalList[fileName] = searchReq 191 continue 192 } 193 finalList[fileName].JoinRequest(searchReq, utils.Or) 194 } 195 } 196 // for exclusion, only join the column info for files that exist and not the actual search request info 197 // exclusion conditions should not influence raw blocks to search 198 if node.ExclusionSearchConditions != nil { 199 exclustionSegmentFiles := extractSSRFromCondition(node.ExclusionSearchConditions, utils.And, 200 filesToSearch, timeRange, indexNames, querySummary, qid, isQueryPersistent, pqid) 201 for fileName, searchReq := range exclustionSegmentFiles { 202 if _, ok := finalList[fileName]; !ok { 203 continue 204 } 205 finalList[fileName].JoinColumnInfo(searchReq) 206 } 207 } 208 209 return finalList 210 } 211 212 func extractSSRFromCondition(condition *structs.SearchCondition, op utils.LogicalOperator, filesToSearch map[string]map[string]*structs.BlockTracker, 213 timeRange *dtu.TimeRange, indexNames []string, querySummary *summary.QuerySummary, qid uint64, isQueryPersistent bool, pqid string) map[string]*structs.SegmentSearchRequest { 214 finalSegFiles := make(map[string]*structs.SegmentSearchRequest) 215 if condition.SearchQueries != nil { 216 for _, query := range condition.SearchQueries { 217 segFiles, err := MicroIndexCheck(query, filesToSearch, timeRange, indexNames, querySummary, qid, isQueryPersistent, pqid) 218 if err != nil { 219 log.Errorf("qid=%d, error when checking micro indices: %+v", qid, err) 220 } 221 for fileName, searchReq := range segFiles { 222 if _, ok := finalSegFiles[fileName]; !ok { 223 finalSegFiles[fileName] = searchReq 224 } else { 225 finalSegFiles[fileName].JoinRequest(searchReq, op) 226 } 227 } 228 } 229 } 230 231 if condition.SearchNode != nil { 232 for _, node := range condition.SearchNode { 233 segmentFiles := ExtractSSRFromSearchNode(node, filesToSearch, timeRange, indexNames, querySummary, qid, isQueryPersistent, pqid) 234 235 for fileName, searchReq := range segmentFiles { 236 if _, ok := finalSegFiles[fileName]; !ok { 237 finalSegFiles[fileName] = searchReq 238 continue 239 } 240 finalSegFiles[fileName].JoinRequest(searchReq, op) 241 } 242 } 243 } 244 return finalSegFiles 245 } 246 247 // todo: better and more generic node types. 248 // Right now, we just assume if its not ColumnValue, then it has to be TimeRangeQuery 249 func GetNodeTypeFromNode(node *structs.SearchNode) structs.SearchNodeType { 250 var s structs.SearchNodeType 251 if node.AndSearchConditions != nil { 252 nodeType := GetNodeTypeFromCondition(node.AndSearchConditions) 253 if nodeType == structs.ColumnValueQuery { 254 return structs.ColumnValueQuery 255 } 256 } 257 258 if node.OrSearchConditions != nil { 259 nodeType := GetNodeTypeFromCondition(node.OrSearchConditions) 260 if nodeType == structs.ColumnValueQuery { 261 return structs.ColumnValueQuery 262 } 263 } 264 265 if node.ExclusionSearchConditions != nil { 266 nodeType := GetNodeTypeFromCondition(node.ExclusionSearchConditions) 267 if nodeType == structs.ColumnValueQuery { 268 return structs.ColumnValueQuery 269 } 270 } 271 return s 272 } 273 274 func GetNodeTypeFromCondition(searchCond *structs.SearchCondition) structs.SearchNodeType { 275 if searchCond.SearchNode != nil { 276 for _, search := range searchCond.SearchNode { 277 nodeType := GetNodeTypeFromNode(search) 278 if nodeType == structs.ColumnValueQuery { 279 return structs.ColumnValueQuery 280 } 281 } 282 } 283 if searchCond.SearchQueries != nil { 284 for _, search := range searchCond.SearchQueries { 285 nodeType := GetNodeTypeFromQuery(search) 286 if nodeType == structs.ColumnValueQuery { 287 return structs.ColumnValueQuery 288 } 289 } 290 } 291 return structs.MatchAllQuery 292 } 293 294 func GetNodeTypeFromQuery(query *structs.SearchQuery) structs.SearchNodeType { 295 if query.ExpressionFilter != nil { 296 if !query.ExpressionFilter.IsTimeRangeFilter() { 297 return structs.ColumnValueQuery 298 } 299 } else { 300 if query.MatchFilter.MatchColumn == "*" { 301 return structs.MatchAllQuery 302 } 303 if query.MatchFilter.MatchColumn != config.GetTimeStampKey() { 304 return structs.ColumnValueQuery 305 } 306 } 307 return structs.MatchAllQuery 308 }