github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/segment/writer/segstream.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 writer
    18  
    19  import (
    20  	"github.com/siglens/siglens/pkg/config"
    21  	"github.com/siglens/siglens/pkg/segment/structs"
    22  	"github.com/siglens/siglens/pkg/segment/utils"
    23  	log "github.com/sirupsen/logrus"
    24  )
    25  
    26  /*
    27  Main function exported to check colWips against persistent queries during ingest
    28  
    29  Internally, updates the bitset with recNum for all queries that matched
    30  */
    31  func applyStreamingSearchToRecord(wipBlock WipBlock, psNode map[string]*structs.SearchNode,
    32  	recNum uint16) {
    33  
    34  	holderDte := &utils.DtypeEnclosure{}
    35  	tsKey := config.GetTimeStampKey()
    36  	for pqid, sNode := range psNode {
    37  		holderDte.Reset()
    38  		if applySearchSingleNode(wipBlock.colWips, sNode, holderDte, tsKey) {
    39  			wipBlock.addRecordToMatchedResults(recNum, pqid)
    40  		}
    41  	}
    42  }
    43  
    44  func applySearchSingleNode(colWips map[string]*ColWip, sNode *structs.SearchNode, holderDte *utils.DtypeEnclosure, tsKey string) bool {
    45  	retVal := false
    46  	if sNode.AndSearchConditions != nil {
    47  		andConditions := applySearchSingleCondition(colWips, sNode.AndSearchConditions, utils.And, holderDte, tsKey)
    48  		if !andConditions {
    49  			return false
    50  		}
    51  		retVal = true
    52  	}
    53  
    54  	// at least one must pass. If and conditions are defined, then this is a noop check
    55  	if sNode.OrSearchConditions != nil {
    56  		orConditions := applySearchSingleCondition(colWips, sNode.OrSearchConditions, utils.Or, holderDte, tsKey)
    57  		retVal = retVal || orConditions
    58  	}
    59  
    60  	if !retVal {
    61  		return retVal
    62  	}
    63  	// all must fail
    64  	if sNode.ExclusionSearchConditions != nil {
    65  		exclusionConditions := applySearchSingleCondition(colWips, sNode.ExclusionSearchConditions, utils.Exclusion, holderDte, tsKey)
    66  		if exclusionConditions {
    67  			return false
    68  		}
    69  	}
    70  	return true
    71  }
    72  
    73  func applySearchSingleCondition(colWips map[string]*ColWip, sCond *structs.SearchCondition, op utils.LogicalOperator,
    74  	holderDte *utils.DtypeEnclosure, tsKey string) bool {
    75  	orMatch := false
    76  	if sCond.SearchNode != nil {
    77  		for _, sNode := range sCond.SearchNode {
    78  			retVal := applySearchSingleNode(colWips, sNode, holderDte, tsKey)
    79  			if !retVal && op == utils.And {
    80  				return retVal
    81  			} else {
    82  				orMatch = orMatch || retVal
    83  			}
    84  		}
    85  	}
    86  	if sCond.SearchQueries != nil {
    87  		for _, query := range sCond.SearchQueries {
    88  			retVal := applySearchSingleQuery(colWips, query, op, holderDte, tsKey)
    89  			if !retVal && op == utils.And {
    90  				return retVal
    91  			} else {
    92  				orMatch = orMatch || retVal
    93  			}
    94  		}
    95  	}
    96  
    97  	if op == utils.And {
    98  		// previous false values would have returned already
    99  		return true
   100  	}
   101  	return orMatch
   102  }
   103  
   104  func applySearchSingleQuery(colWips map[string]*ColWip, sQuery *structs.SearchQuery, op utils.LogicalOperator,
   105  	holderDte *utils.DtypeEnclosure, tsKey string) bool {
   106  	switch sQuery.SearchType {
   107  	case structs.MatchAll:
   108  		return true
   109  	case structs.MatchWords:
   110  		rawVal, ok := colWips[sQuery.MatchFilter.MatchColumn]
   111  		if !ok {
   112  			return false
   113  		}
   114  		retVal, err := ApplySearchToMatchFilterRawCsg(sQuery.MatchFilter, rawVal.getLastRecord())
   115  		if err != nil {
   116  			log.Errorf("applySearchSingleQuery: failed to apply match words search! error: %v", err)
   117  			return false
   118  		}
   119  		return retVal
   120  	case structs.MatchWordsAllColumns:
   121  		for cname, colVal := range colWips {
   122  			if cname == tsKey {
   123  				continue
   124  			}
   125  			retVal, _ := ApplySearchToMatchFilterRawCsg(sQuery.MatchFilter, colVal.getLastRecord())
   126  			if retVal {
   127  				return true
   128  			}
   129  		}
   130  		return false
   131  	case structs.SimpleExpression:
   132  		rawVal, ok := colWips[sQuery.QueryInfo.ColName]
   133  		if !ok {
   134  			return false
   135  		}
   136  		retVal, err := ApplySearchToExpressionFilterSimpleCsg(sQuery.QueryInfo.QValDte, sQuery.ExpressionFilter.FilterOp, rawVal.getLastRecord(), false, holderDte)
   137  		if err != nil {
   138  			log.Errorf("applySearchSingleQuery: failed to apply simple expression search! error: %v", err)
   139  			return false
   140  		}
   141  		return retVal
   142  	case structs.RegexExpression:
   143  		rawVal, ok := colWips[sQuery.QueryInfo.ColName]
   144  		if !ok {
   145  			return false
   146  		}
   147  		retVal, err := ApplySearchToExpressionFilterSimpleCsg(sQuery.QueryInfo.QValDte, sQuery.ExpressionFilter.FilterOp, rawVal.getLastRecord(), true, holderDte)
   148  		if err != nil {
   149  			log.Errorf("applySearchSingleQuery: failed to apply wildcard expression search! error: %v", err)
   150  			return false
   151  		}
   152  		return retVal
   153  	case structs.RegexExpressionAllColumns:
   154  		for cname, colVal := range colWips {
   155  			if cname == tsKey {
   156  				continue
   157  			}
   158  			retVal, _ := ApplySearchToExpressionFilterSimpleCsg(sQuery.QueryInfo.QValDte, sQuery.ExpressionFilter.FilterOp, colVal.getLastRecord(), true, holderDte)
   159  			if retVal {
   160  				return true
   161  			}
   162  		}
   163  		return false
   164  	case structs.SimpleExpressionAllColumns:
   165  		for cname, colVal := range colWips {
   166  			if cname == tsKey {
   167  				continue
   168  			}
   169  			retVal, _ := ApplySearchToExpressionFilterSimpleCsg(sQuery.QueryInfo.QValDte, sQuery.ExpressionFilter.FilterOp, colVal.getLastRecord(), false, holderDte)
   170  			if retVal {
   171  				return true
   172  			}
   173  		}
   174  		return false
   175  	case structs.MatchDictArraySingleColumn:
   176  		rawVal, ok := colWips[sQuery.QueryInfo.ColName]
   177  		if !ok {
   178  			return false
   179  		}
   180  		retVal, err := ApplySearchToDictArrayFilter([]byte(sQuery.QueryInfo.ColName), sQuery.QueryInfo.QValDte, rawVal.getLastRecord(), sQuery.ExpressionFilter.FilterOp, true, holderDte)
   181  		if err != nil {
   182  			log.Errorf("ApplySearchToDictArrayFilter: failed to apply wildcard expression search! error: %v", err)
   183  			return false
   184  		}
   185  		return retVal
   186  	case structs.MatchDictArrayAllColumns:
   187  		for cname, colVal := range colWips {
   188  			if cname == tsKey {
   189  				continue
   190  			}
   191  			retVal, _ := ApplySearchToDictArrayFilter([]byte(sQuery.QueryInfo.ColName), sQuery.QueryInfo.QValDte, colVal.getLastRecord(), sQuery.ExpressionFilter.FilterOp, false, holderDte)
   192  			if retVal {
   193  				return true
   194  			}
   195  		}
   196  		return false
   197  	default:
   198  		log.Errorf("applySearchSingleQuery: unsupported query type! %+v", sQuery.SearchType)
   199  		return false
   200  	}
   201  }
   202  
   203  /*
   204  Adds recNum as a matched record in the current bitset based on pqid
   205  */
   206  func (wipBlock *WipBlock) addRecordToMatchedResults(recNum uint16, pqid string) {
   207  	pqMatch, ok := wipBlock.pqMatches[pqid]
   208  	if !ok {
   209  		log.Errorf("addRecordToMatchedResults: tried to match a record for a pqid that does not exist")
   210  		return
   211  	}
   212  	pqMatch.AddMatchedRecord(uint(recNum))
   213  }
   214  
   215  func (colWip *ColWip) getLastRecord() []byte {
   216  	return colWip.cbuf[colWip.cstartidx:colWip.cbufidx]
   217  }