github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/es/query/queryresponse.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 "time" 22 23 "github.com/nqd/flat" 24 "github.com/siglens/siglens/pkg/scroll" 25 "github.com/siglens/siglens/pkg/segment/reader/record" 26 "github.com/siglens/siglens/pkg/segment/structs" 27 "github.com/valyala/fasthttp" 28 29 "github.com/siglens/siglens/pkg/utils" 30 log "github.com/sirupsen/logrus" 31 ) 32 33 func checkScrollSize(offset uint64, size uint64, total uint64) uint64 { 34 if offset+size >= total { 35 size = total - offset 36 } 37 return size 38 } 39 40 func GetQueryResponseJsonScroll(indexName string, queryStart time.Time, sizeLimit uint64, 41 scrollRecord *scroll.Scroll, qid uint64) utils.HttpServerESResponseScroll { 42 var httpRespOuter utils.HttpServerESResponseOuter 43 var httpResp utils.HttpServerESResponseScroll 44 var subset []utils.Hits 45 if scroll.IsScrollIdValid(scrollRecord.Scroll_id) { 46 resultLen := scrollRecord.Results.Hits.GetHits() 47 scrollRecord.Size = checkScrollSize(scrollRecord.Offset, scrollRecord.Size, resultLen) 48 subset = scrollRecord.Results.Hits.Hits[scrollRecord.Offset : scrollRecord.Offset+scrollRecord.Size] 49 scrollRecord.Offset = scrollRecord.Offset + scrollRecord.Size 50 scroll.SetScrollRecord(scrollRecord.Scroll_id, scrollRecord) 51 err := scrollRecord.FlushScrollContextToFile() 52 if err != nil { 53 log.Errorf("qid=%d, GetQueryResponseJsonScroll: error flushing scroll result for id %+v Err: %v", qid, scrollRecord.Scroll_id, err) 54 } 55 if len(subset) > 0 { 56 err := scrollRecord.WriteScrollResultToFile() 57 if err != nil { 58 log.Errorf("qid=%d, GetQueryResponseJsonScroll: error writing scroll result %v", qid, err) 59 } 60 } 61 httpResp.Hits.Hits = subset 62 httpResp.Took = time.Since(queryStart).Milliseconds() 63 log.Infof("qid=%d, Scroll Query Took %+v ms", qid, httpRespOuter.Took) 64 httpResp.Hits.Total = scrollRecord.Results.Hits.Total 65 httpResp.Timed_out = false 66 httpResp.StatusCode = 200 67 httpResp.Scroll_id = scrollRecord.Scroll_id 68 } else { 69 httpResp.StatusCode = fasthttp.StatusBadRequest 70 httpResp.Hits.Hits = []utils.Hits{} 71 log.Errorf("qid=%d, Scroll Timeout %v : Invalid Search context", qid, scrollRecord.Scroll_id) 72 } 73 return httpResp 74 75 } 76 77 func GetQueryResponseJson(nodeResult *structs.NodeResult, indexName string, queryStart time.Time, sizeLimit uint64, qid uint64, aggs *structs.QueryAggregators) utils.HttpServerESResponseOuter { 78 var httpRespOuter utils.HttpServerESResponseOuter 79 var httpResp utils.HttpServerESResponse 80 81 // aggs exist, so just return aggregations instead of all results 82 httpRespOuter.Aggs = make(map[string]utils.BucketWrapper) 83 for aggName, aggRes := range nodeResult.Histogram { 84 allBuckets := make([]map[string]interface{}, len(aggRes.Results)) 85 for idx, hist := range aggRes.Results { 86 res := make(map[string]interface{}) 87 res["key"] = hist.BucketKey 88 res["doc_count"] = hist.ElemCount 89 if aggRes.IsDateHistogram { 90 res["key_as_string"] = fmt.Sprintf("%v", hist.BucketKey) 91 } 92 for name, value := range hist.StatRes { 93 res[name] = utils.StatResponse{ 94 Value: value.CVal, 95 } 96 } 97 98 allBuckets[idx] = res 99 } 100 httpRespOuter.Aggs[aggName] = utils.BucketWrapper{Bucket: allBuckets} 101 } 102 103 if sizeLimit == 0 || len(nodeResult.AllRecords) == 0 { 104 httpResp.Hits = make([]utils.Hits, 0) 105 } else { 106 var _id string 107 allJsons, _, err := record.GetJsonFromAllRrc(nodeResult.AllRecords, true, qid, nodeResult.SegEncToKey, aggs) 108 if err != nil { 109 log.Errorf("qid=%d, GetQueryResponseJson: failed to get allrecords from rrc, err=%v", qid, err) 110 return httpRespOuter 111 } 112 for _, jsonSource := range allJsons { 113 if val, pres := jsonSource["_id"]; pres { 114 _id = val.(string) 115 } else { 116 _id = "" 117 } 118 var idxToPut string 119 if val, pres := jsonSource["_index"]; pres { 120 idxToPut = val.(string) 121 } else { 122 idxToPut = indexName 123 } 124 var docTypeToPut string 125 if val, pres := jsonSource["_type"]; pres { 126 docTypeToPut = val.(string) 127 } else { 128 docTypeToPut = "unknown" 129 } 130 131 finalSrc, err := flat.Unflatten(jsonSource, nil) 132 if err != nil { 133 log.Errorf("qid=%d, GetQueryResponseJson: Failed to unflatten, src=[%v], err=%v", qid, jsonSource, err) 134 return httpRespOuter 135 } 136 137 jsonMap := utils.Hits{Index: idxToPut, Type: docTypeToPut, Id: _id, Version: 1, Score: 1, Source: finalSrc} 138 139 httpResp.Hits = append(httpResp.Hits, jsonMap) 140 } 141 } 142 143 httpResp.Total = convertQueryCountToESResponse(nodeResult.TotalResults) 144 httpResp.Max_score = 0 145 httpRespOuter.Hits = httpResp 146 httpRespOuter.Took = time.Since(queryStart).Milliseconds() 147 log.Infof("qid=%d, Query Took %+v ms", qid, httpRespOuter.Took) 148 149 httpRespOuter.Timed_out = false 150 httpRespOuter.StatusCode = 200 151 152 shards := make(map[string]interface{}) 153 shards["total"] = 1 154 shards["successful"] = 1 155 shards["skipped"] = 0 156 shards["failed"] = 0 157 158 httpRespOuter.Shards = shards 159 return httpRespOuter 160 } 161 162 func convertQueryCountToESResponse(qc *structs.QueryCount) interface{} { 163 if qc == nil { 164 return 0 165 } 166 167 if !qc.EarlyExit { 168 return qc.TotalCount 169 } 170 171 return utils.HitsCount{Value: qc.TotalCount, Relation: qc.Op.ToString()} 172 }