首页 > 解决方案 > 如何在 golang 中处理 Elasticsearch 回复的嵌套结构?

问题描述

我有一个用 Go 编写的 API 服务,使用 gin-gonic,它由 Elasticsearch 服务支持。查询命中 API,API 服务器查询 Elasticsearch,Elasticsearch 将搜索结果回复给 API,API 将结果返回给启动流程的一方。所有这些都“有效”,端到端,但有一个问题。

在 Elasticsearch 中,我有 20 个索引——每个索引都有数千个文档。当我使用 go-elasticsearch 通过 gin-gonic 查询 Elasticsearch 中的一个索引时,我得到了一个 Elasticsearch 结果,它被解组到这些结构中:

type esResult struct {
        Took     int        `json:"took"`
        Timedout bool       `json:"timed_out"`
        Shards   jsonShards `json:"_shards"`
        Hits     jsonHits   `json:"hits"`
}

type jsonShards struct {
        Total      int `json:"total"`
        Successful int `json:"successful"`
        Skipped    int `json:"skipped"`
        Failed     int `json:"failed"`
}

type jsonHits struct {
        Total    jsonTotal     `json:"total"`
        Maxscore float64       `json:"max_score"`
        Hitlist  []jsonHitlist `json:"hits"`
}

type jsonHitlist struct {
        Index string  `json:"_index"`
        Type  string  `json:"_type"`
        ID    string  `json:"_id"`
        Score float64 `json:"_score"`
        Source customForIndex `json:"_source"`
        //      Source []byte `json:"_source"`
}

我的问题是,当上面显示为“customForIndex”类型的结构的 esResult.Hits.Hitlist.Source 字段根据我查询的索引而有所不同时。

我想做的是:

                var esres esResult
                err := json.Unmarshal(resp, &esres)

这很好用,如果我使用 customForIndex,但如果我将 Source 设置为 string 或 []byte(以便我可以单独解组 Source),它似乎不起作用。

我知道的解决方法很糟糕,是定义重复的结构(一组,每个索引),但这很糟糕,因为它会导致许多 esResult 结构、许多 Hits 结构等等,这些都是重复的。

那么如何解组 Elasticsearch 回复,以便获得回复的自定义部分?

换一种说法,如果我从 Elasticsearch 获取回复,并直接将其传递给 API 服务器(进而传递给客户端),而不进行任何处理,那么它包含各种(与客户端无关的)Elasticsearch 信息。所以我的计划是去掉所有这些,只在 Elasticsearch 回复中包含来自 Source 对象的数据。但是如果我解组 esResult,esResult 本身在其他索引上是无效的,因为子结构不同。

想法?任何帮助,将不胜感激。基本上我的问题与在 golang 中解组嵌套结构有关,并且恰好出现在 Elasticsearch 用例中,因为大多数(但不是全部)结构在索引之间是重复的。

标签: goelasticsearchstructnestedgo-gin

解决方案


我正在阅读您的答案,我记得当我与弹性战斗只返回我需要的东西时。

真的我不知道您是如何进行查询的(如果您可以共享一些代码,那就太好了)

但是,就我而言, a 做了以下事情。

         "aggs": {
            "top_values": {
              "terms": {
                "field": "data.field_group.keyword"
              },
              "aggs": {
                "top_field_hits": {
                  "top_hits": {
                    "_source": {
                      "includes": [ "data.field1", "data.field2", "data.field3", "data.field4"]
                    }
                  }
                }
              }
            }
          }

之后,他们阅读了回复,阅读结果以:

for _, hit := range values["aggregations"].(map[string]interface{})["top_values"].(map[string]interface{})["buckets"].([]interface{})

在这个“FOR”语句中,我做了一个包含“hit”的结构的 Marshall,然后我用我的结构做了一个 unmarshal。

var totalValue MyStruct
marshalTotal, _ := json.Marshal(hit)
_ = json.Unmarshal(marshalTotal, &totalValue)

您需要在结构中使用与弹性结果相同的标签名称。

MyProperty string `json:"elasticNameField"`

另一方面,也许您可​​以使用 [Olivera] 1库,根据我的经验,它是一个很好的库,但我能够在查询的响应时间上发现一些差异。

我希望您可以使用此信息来解决您的问题。

问候,


推荐阅读