Как обрабатывать вложенные структуры в golang для ответов Elasticsearch?

#go #elasticsearch #struct #nested #go-gin

# #Вперед #elasticsearch #структура #вложенный #go-gin

Вопрос:

У меня есть служба API, написанная на Go, с использованием gin-gonic, которая поддерживается службой Elasticsearch. Запросы попадают в API, сервер API запрашивает Elasticsearch, Elasticsearch отправляет результаты поиска в API, а API отправляет результаты обратно стороне, которая запустила процесс. Все это «работает», от начала до конца, но есть проблема.

В Elasticsearch у меня есть 20 индексов — каждый индекс содержит тысячи документов. Когда я использую go-elasticsearch для запроса одного из индексов в Elasticsearch через gin-gonic, я получаю результат 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"`
}
 

Моя проблема в том, что когда esResult.Попадает.Список попаданий.Исходное поле, показанное выше как структура типа ‘customForIndex’, отличается в зависимости от того, какой индекс я запрашиваю.

Что я хотел бы сделать, это:

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

Это работает нормально, если я использую customForIndex , но если я устанавливаю Source в string или []byte (чтобы я мог разобрать Source отдельно), похоже, это не работает.

Обходной путь, который, как я знаю, ужасен, заключается в определении повторяющихся структур (один набор для каждого индекса), но это ужасно, так как это приведет к появлению множества структур esResult, множества структур Hits и т. Д., Которые Все являются дубликатами.

Итак, как мне отменить сопоставление ответов Elasticsearch, чтобы я мог перейти к пользовательской части ответа?

Другими словами, если я беру ответ от Elasticsearch и передаю его непосредственно на сервер API (и, следовательно, клиенту) без какой-либо обработки, то он включает в себя все виды нерелевантных (для клиента) Информация об Elasticsearch. Итак, мой план состоял в том, чтобы убрать все это и включить только данные из исходного объекта в ответ Elasticsearch. Но если я отменяю esResult, сам esResult недействителен для других индексов, потому что дочерняя структура отличается.

Мысли? Любая помощь будет оценена. В основном мой вопрос относится к разархивированию вложенных структур в golang и просто появляется в вариантах использования Elasticsearch, потому что большинство (но не все) структур дублируют индексы.

Ответ №1:

Вы можете использовать «github.com/olivere/elastic/v7 » библиотека, которая помогает вам легко хранить данные в структуре SearchResult

 type SearchResult struct {
Header          http.Header          `json:"-"`
TookInMillis    int64                `json:"took,omitempty"`             // search time in milliseconds
TerminatedEarly bool                 `json:"terminated_early,omitempty"` // request terminated early
NumReducePhases int                  `json:"num_reduce_phases,omitempty"`
Clusters        *SearchResultCluster `json:"_clusters,omitempty"`    // 6.1.0 
ScrollId        string               `json:"_scroll_id,omitempty"`   // only used with Scroll and Scan operations
Hits            *SearchHits          `json:"hits,omitempty"`         // the actual search hits
Suggest         SearchSuggest        `json:"suggest,omitempty"`      // results from suggesters
Aggregations    Aggregations         `json:"aggregations,omitempty"` // results from aggregations
TimedOut        bool                 `json:"timed_out,omitempty"`    // true if the search timed out
Error           *ErrorDetails        `json:"error,omitempty"`        // only used in MultiGet
Profile         *SearchProfile       `json:"profile,omitempty"`      // profiling results, if optional Profile API was active for this search
Shards          *ShardsInfo          `json:"_shards,omitempty"`      // shard information
Status          int                  `json:"status,omitempty"`       // used in MultiSearch
 

}

Далее вы можете получить то, что хотите, используя

 for _, hit := range searchResult.Hits.Hits { //your logic here }
 

Ответ №2:

Я читал ваш ответ и помню, как я боролся с elastic, чтобы вернуть только то, что мне нужно.

На самом деле я не знаю, как вы делаете запросы (если вы можете поделиться некоторым кодом, это будет хорошо)

Но в моем случае 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», а затем я выполнил демарш с МОЕЙ структурой.

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

Вам нужно в вашей структуре то же имя тега, что и результат elastic.

 MyProperty string `json:"elasticNameField"`
 

С другой стороны, может быть, вы можете использовать библиотеку [Olivera] 1, по моему опыту, это хорошая библиотека, но я смог найти некоторую разницу во времени ответа в запросах.

Я бы хотел, чтобы вы могли использовать эту информацию для решения своей проблемы.

С уважением,