Elasticsearch: Fix multiple max depth flatten of multi-level objects (#70302)

This commit is contained in:
Shirley
2023-07-14 11:48:00 +02:00
committed by GitHub
parent 1cacc78eda
commit c1f6b91ea9
2 changed files with 118 additions and 30 deletions

View File

@@ -102,7 +102,7 @@ func processLogsResponse(res *es.SearchResponse, target *Query, configuredFields
for hitIdx, hit := range res.Hits.Hits {
var flattened map[string]interface{}
if hit["_source"] != nil {
flattened = flatten(hit["_source"].(map[string]interface{}))
flattened = flatten(hit["_source"].(map[string]interface{}), 10)
}
doc := map[string]interface{}{
@@ -174,7 +174,7 @@ func processRawDataResponse(res *es.SearchResponse, target *Query, configuredFie
for hitIdx, hit := range res.Hits.Hits {
var flattened map[string]interface{}
if hit["_source"] != nil {
flattened = flatten(hit["_source"].(map[string]interface{}))
flattened = flatten(hit["_source"].(map[string]interface{}), 10)
}
doc := map[string]interface{}{
@@ -1041,38 +1041,26 @@ func getErrorFromElasticResponse(response *es.SearchResponse) string {
}
// flatten flattens multi-level objects to single level objects. It uses dot notation to join keys.
func flatten(target map[string]interface{}) map[string]interface{} {
func flatten(target map[string]interface{}, maxDepth int) map[string]interface{} {
// On frontend maxDepth wasn't used but as we are processing on backend
// let's put a limit to avoid infinite loop. 10 was chosen arbitrary.
maxDepth := 10
currentDepth := 0
delimiter := ""
output := make(map[string]interface{})
step(0, maxDepth, target, "", output)
return output
}
var step func(object map[string]interface{}, prev string)
func step(currentDepth, maxDepth int, target map[string]interface{}, prev string, output map[string]interface{}) {
nextDepth := currentDepth + 1
for key, value := range target {
newKey := strings.Trim(prev+"."+key, ".")
step = func(object map[string]interface{}, prev string) {
for key, value := range object {
if prev == "" {
delimiter = ""
} else {
delimiter = "."
}
newKey := prev + delimiter + key
v, ok := value.(map[string]interface{})
shouldStepInside := ok && len(v) > 0 && currentDepth < maxDepth
if shouldStepInside {
currentDepth++
step(v, newKey)
} else {
output[newKey] = value
}
v, ok := value.(map[string]interface{})
if ok && len(v) > 0 && currentDepth < maxDepth {
step(nextDepth, maxDepth, v, newKey, output)
} else {
output[newKey] = value
}
}
step(target, "")
return output
}
// sortPropNames orders propNames so that timeField is first (if it exists), log message field is second