#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, по моему опыту, это хорошая библиотека, но я смог найти некоторую разницу во времени ответа в запросах.
Я бы хотел, чтобы вы могли использовать эту информацию для решения своей проблемы.
С уважением,