github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/segment/search/conditioncheck.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 search
    18  
    19  import (
    20  	"errors"
    21  
    22  	"github.com/siglens/siglens/pkg/segment/reader/segread"
    23  	. "github.com/siglens/siglens/pkg/segment/structs"
    24  	. "github.com/siglens/siglens/pkg/segment/utils"
    25  	"github.com/siglens/siglens/pkg/segment/writer"
    26  	log "github.com/sirupsen/logrus"
    27  )
    28  
    29  // TODO: support for complex expressions
    30  func ApplyColumnarSearchQuery(query *SearchQuery, multiColReader *segread.MultiColSegmentReader,
    31  	blockNum uint16, recordNum uint16, holderDte *DtypeEnclosure, qid uint64,
    32  	dictEncColNames map[string]bool, searchReq *SegmentSearchRequest,
    33  	cmiPassedCnames map[string]bool) (bool, error) {
    34  
    35  	switch query.SearchType {
    36  	case MatchAll:
    37  		// ts should have already been checked
    38  		return true, nil
    39  	case MatchWords:
    40  		rawColVal, err := multiColReader.ReadRawRecordFromColumnFile(query.QueryInfo.ColName,
    41  			blockNum, recordNum, qid)
    42  		if err != nil {
    43  			return false, err
    44  		}
    45  		return writer.ApplySearchToMatchFilterRawCsg(query.MatchFilter, rawColVal)
    46  	case MatchWordsAllColumns:
    47  		var atleastOneNonError bool
    48  		var finalErr error
    49  		for cname := range cmiPassedCnames {
    50  
    51  			// we skip rawsearching for columns that are dict encoded,
    52  			// since we already search for them in the prior call to applyColumnarSearchUsingDictEnc
    53  			_, ok := dictEncColNames[cname]
    54  			if ok {
    55  				continue
    56  			}
    57  
    58  			rawColVal, err := multiColReader.ReadRawRecordFromColumnFile(cname, blockNum, recordNum, qid)
    59  			if err != nil {
    60  				finalErr = err
    61  				continue
    62  			} else {
    63  				atleastOneNonError = true
    64  			}
    65  			retVal, _ := writer.ApplySearchToMatchFilterRawCsg(query.MatchFilter, rawColVal)
    66  			if retVal {
    67  				multiColReader.IncrementColumnUsage(cname)
    68  				return true, nil
    69  			}
    70  		}
    71  		if atleastOneNonError {
    72  			return false, nil
    73  		} else {
    74  			return false, finalErr
    75  		}
    76  	case SimpleExpression:
    77  		rawColVal, err := multiColReader.ReadRawRecordFromColumnFile(query.QueryInfo.ColName, blockNum, recordNum, qid)
    78  		if err != nil {
    79  			return false, err
    80  		}
    81  		return writer.ApplySearchToExpressionFilterSimpleCsg(query.QueryInfo.QValDte, query.ExpressionFilter.FilterOp, rawColVal, false, holderDte)
    82  	case RegexExpression:
    83  		rawColVal, err := multiColReader.ReadRawRecordFromColumnFile(query.QueryInfo.ColName, blockNum, recordNum, qid)
    84  		if err != nil {
    85  			return false, err
    86  		}
    87  		return writer.ApplySearchToExpressionFilterSimpleCsg(query.QueryInfo.QValDte, query.ExpressionFilter.FilterOp, rawColVal, true, holderDte)
    88  	case RegexExpressionAllColumns:
    89  		var atleastOneNonError bool
    90  		var finalErr error
    91  		for cname := range cmiPassedCnames {
    92  
    93  			// we skip rawsearching for columns that are dict encoded,
    94  			// since we already search for them in the prior call to applyColumnarSearchUsingDictEnc
    95  			_, ok := dictEncColNames[cname]
    96  			if ok {
    97  				continue
    98  			}
    99  
   100  			rawColVal, err := multiColReader.ReadRawRecordFromColumnFile(cname, blockNum, recordNum, qid)
   101  			if err != nil {
   102  				finalErr = err
   103  				continue
   104  			} else {
   105  				atleastOneNonError = true
   106  			}
   107  			retVal, _ := writer.ApplySearchToExpressionFilterSimpleCsg(query.QueryInfo.QValDte, query.ExpressionFilter.FilterOp, rawColVal, true, holderDte)
   108  			if retVal {
   109  				multiColReader.IncrementColumnUsage(cname)
   110  				return true, nil
   111  			}
   112  		}
   113  		if atleastOneNonError {
   114  			return false, nil
   115  		} else {
   116  			return false, finalErr
   117  		}
   118  	case SimpleExpressionAllColumns:
   119  		var atleastOneNonError bool
   120  		var finalErr error
   121  		for cname := range cmiPassedCnames {
   122  
   123  			// we skip rawsearching for columns that are dict encoded,
   124  			// since we already search for them in the prior call to applyColumnarSearchUsingDictEnc
   125  			_, ok := dictEncColNames[cname]
   126  			if ok {
   127  				continue
   128  			}
   129  
   130  			rawColVal, err := multiColReader.ReadRawRecordFromColumnFile(cname, blockNum, recordNum, qid)
   131  			if err != nil {
   132  				finalErr = err
   133  				continue
   134  			} else {
   135  				atleastOneNonError = true
   136  			}
   137  			retVal, _ := writer.ApplySearchToExpressionFilterSimpleCsg(query.QueryInfo.QValDte, query.ExpressionFilter.FilterOp, rawColVal, false, holderDte)
   138  			if retVal {
   139  				multiColReader.IncrementColumnUsage(cname)
   140  				return true, nil
   141  			}
   142  		}
   143  		if atleastOneNonError {
   144  			return false, nil
   145  		} else {
   146  			return false, finalErr
   147  		}
   148  	case MatchDictArraySingleColumn:
   149  		rawColVal, err := multiColReader.ReadRawRecordFromColumnFile(query.QueryInfo.ColName, blockNum, recordNum, qid)
   150  		if err != nil {
   151  			return false, err
   152  		}
   153  		return writer.ApplySearchToDictArrayFilter(query.QueryInfo.KValDte, query.QueryInfo.QValDte, rawColVal, Equals, true, holderDte)
   154  	case MatchDictArrayAllColumns:
   155  		var atleastOneNonError bool
   156  		var finalErr error
   157  		for _, colInfo := range multiColReader.AllColums {
   158  
   159  			// we skip rawsearching for columns that are dict encoded,
   160  			// since we already search for them in the prior call to applyColumnarSearchUsingDictEnc
   161  			_, ok := dictEncColNames[colInfo.ColumnName]
   162  			if ok {
   163  				continue
   164  			}
   165  
   166  			rawColVal, err := multiColReader.ReadRawRecordFromColumnFile(colInfo.ColumnName, blockNum, recordNum, qid)
   167  			if err != nil {
   168  				finalErr = err
   169  				continue
   170  			} else {
   171  				atleastOneNonError = true
   172  			}
   173  			retVal, _ := writer.ApplySearchToDictArrayFilter(query.QueryInfo.KValDte, query.QueryInfo.QValDte, rawColVal, query.ExpressionFilter.FilterOp, true, holderDte)
   174  			if retVal {
   175  				multiColReader.IncrementColumnUsage(colInfo.ColumnName)
   176  				return true, nil
   177  			}
   178  		}
   179  		if atleastOneNonError {
   180  			return false, nil
   181  		} else {
   182  			return false, finalErr
   183  		}
   184  	// case ComplexExpression:
   185  	//	return // match complex exp
   186  	default:
   187  		log.Errorf("qid=%d, ApplySearchQuery: unsupported query type! %+v", qid, query.SearchType)
   188  		return false, errors.New("unsupported query type")
   189  	}
   190  }
   191  
   192  /*
   193  returns doRecLevelSearch, error
   194  if it determines that this query can be fully satisfied by looking at the dict encoded, then
   195  will return doRecLevelSearch=false.
   196  */
   197  func applyColumnarSearchUsingDictEnc(sq *SearchQuery, mcr *segread.MultiColSegmentReader,
   198  	blockNum uint16, qid uint64, bri *BlockRecordIterator, bsh *BlockSearchHelper,
   199  	searchReq *SegmentSearchRequest, cmiPassedCnames map[string]bool) (bool, map[string]bool, error) {
   200  
   201  	dictEncColNames := make(map[string]bool)
   202  
   203  	switch sq.SearchType {
   204  	case MatchAll:
   205  		for i := uint(0); i < uint(bri.AllRecLen); i++ {
   206  			bsh.AddMatchedRecord(i)
   207  		}
   208  		return false, dictEncColNames, nil
   209  
   210  	case MatchWords:
   211  		isDict, err := mcr.IsBlkDictEncoded(sq.QueryInfo.ColName, blockNum)
   212  		if err != nil {
   213  			return true, dictEncColNames, err
   214  		}
   215  
   216  		if !isDict {
   217  			return true, dictEncColNames, nil
   218  		}
   219  
   220  		found, err := mcr.ApplySearchToMatchFilterDictCsg(sq.MatchFilter, bsh, sq.QueryInfo.ColName)
   221  		if err != nil {
   222  			log.Errorf("applyColumnarSearchUsingDictEnc: matchwords dict search failed, err=%v", err)
   223  			return false, dictEncColNames, err
   224  		}
   225  		return found, dictEncColNames, err
   226  
   227  	case MatchWordsAllColumns:
   228  		for cname := range cmiPassedCnames {
   229  
   230  			isDict, err := mcr.IsBlkDictEncoded(cname, blockNum)
   231  			if err != nil {
   232  				continue
   233  			}
   234  
   235  			if !isDict {
   236  				continue
   237  			}
   238  
   239  			dictEncColNames[cname] = true
   240  			found, err := mcr.ApplySearchToMatchFilterDictCsg(sq.MatchFilter, bsh, cname)
   241  			if err != nil {
   242  				continue
   243  			}
   244  			if found {
   245  				mcr.IncrementColumnUsage(cname)
   246  			}
   247  		}
   248  		return true, dictEncColNames, nil
   249  
   250  	case SimpleExpression, RegexExpression:
   251  
   252  		isDict, err := mcr.IsBlkDictEncoded(sq.QueryInfo.ColName, blockNum)
   253  		if err != nil {
   254  			return true, dictEncColNames, err
   255  		}
   256  
   257  		if !isDict {
   258  			return true, dictEncColNames, nil
   259  		}
   260  
   261  		var regex bool
   262  		if sq.SearchType == RegexExpression {
   263  			regex = true
   264  		}
   265  
   266  		found, err := mcr.ApplySearchToExpressionFilterDictCsg(sq.QueryInfo.QValDte,
   267  			sq.ExpressionFilter.FilterOp, regex, bsh, sq.QueryInfo.ColName)
   268  		if err != nil {
   269  			log.Errorf("applyColumnarSearchUsingDictEnc: simpleexp/wildrexp dict search failed, err=%v", err)
   270  			return false, dictEncColNames, err
   271  		}
   272  		return found, dictEncColNames, err
   273  
   274  	case RegexExpressionAllColumns:
   275  		for cname := range cmiPassedCnames {
   276  
   277  			isDict, err := mcr.IsBlkDictEncoded(cname, blockNum)
   278  			if err != nil {
   279  				continue
   280  			}
   281  
   282  			if !isDict {
   283  				continue
   284  			}
   285  
   286  			dictEncColNames[cname] = true
   287  			found, err := mcr.ApplySearchToExpressionFilterDictCsg(sq.QueryInfo.QValDte,
   288  				sq.ExpressionFilter.FilterOp, true, bsh, cname)
   289  			if err != nil {
   290  				continue
   291  			}
   292  			if found {
   293  				mcr.IncrementColumnUsage(cname)
   294  			}
   295  		}
   296  		return true, dictEncColNames, nil
   297  
   298  	case SimpleExpressionAllColumns:
   299  		for cname := range cmiPassedCnames {
   300  
   301  			isDict, err := mcr.IsBlkDictEncoded(cname, blockNum)
   302  			if err != nil {
   303  				continue
   304  			}
   305  
   306  			if !isDict {
   307  				continue
   308  			}
   309  
   310  			dictEncColNames[cname] = true
   311  			found, err := mcr.ApplySearchToExpressionFilterDictCsg(sq.QueryInfo.QValDte,
   312  				sq.ExpressionFilter.FilterOp, false, bsh, cname)
   313  			if err != nil {
   314  				continue
   315  			}
   316  			if found {
   317  				mcr.IncrementColumnUsage(cname)
   318  			}
   319  		}
   320  		return true, dictEncColNames, nil
   321  	case MatchDictArraySingleColumn, MatchDictArrayAllColumns:
   322  		return true, dictEncColNames, nil
   323  	// case ComplexExpression:
   324  	//	return // match complex exp
   325  	default:
   326  		log.Errorf("qid=%d, applyColumnarSearchUsingDictEnc: unsupported query type! %+v", qid, sq.SearchType)
   327  		return true, dictEncColNames, errors.New("unsupported query type")
   328  	}
   329  }