Одна из тем, которую мы затронули лишь вкратце, - это работа с полезными нагрузками JSON. Клиент, как упоминалось в одном из предыдущих постов, представляет тело запроса и ответа как io.Reader, оставляя любое кодирование и декодирование вызывающему коду. Рассмотрим различные подходы, начиная с декодирования (десериализации) тела ответа.
Самый простой вариант - просто использовать пакет encoding/json из стандартной библиотеки для декодирования ответа в map[string]interface{} или настраиваемый тип структуры:
var r map[string]interface{}
res, _ := es.Search(es.Search.WithTrackTotalHits(true))
json.NewDecoder(res.Body).Decode(&r)
fmt.Printf(
"[%s] %d hits; took: %dms\n",
res.Status(),
int(r["hits"].(map[string]interface{})["total"].(map[string]interface{})["value"].(float64)),
int(r["took"].(float64)),
)
// => [200 OK] 1 hits; took: 10ms
Несмотря на простоту, этот вариант далеко не самый удобный или эффективный: обратите внимание, как вам нужно преобразовать каждую часть структуры, чтобы сделать значение полезным в вашем коде. Есть способы получше.
Если все, что вас интересует, это получение пары значений из ответа и их использование или отображение, привлекательным вариантом является использование пакета tidwall/gjson. Это позволяет вам использовать "точечную нотацию", чтобы легко и более эффективно "извлекать" значения из ответа:
var b bytes.Buffer
res, _ := es.Search(es.Search.WithTrackTotalHits(true))
b.ReadFrom(res.Body)
values := gjson.GetManyBytes(b.Bytes(), "hits.total.value", "took")
fmt.Printf(
"[%s] %d hits; took: %dms\n",
res.Status(),
values[0].Int(),
values[1].Int(),
)
// => [200 OK] 1 hits; took: 10ms
Еще один вариант, особенно для более сложной кодовой базы, - использовать такой пакет, как mailru/easyjson, который использует генерацию кода для эффективного кодирования и декодирования полезной нагрузки JSON в настраиваемые типы структур - соответствующий пример и связанную с ним папку модели.
Примечание. Запустите бенчмарки в своей собственной среде, чтобы сравнить производительность различных пакетов JSON.
Когда дело доходит до кодирования (сериализации) тела запроса, самый простой вариант - использовать тип, поддерживающий интерфейс io.Reader, например bytes.Buffer:
var b bytes.Buffer
b.WriteString(`{"title" : "`)
b.WriteString("Test")
b.WriteString(`"}`)
res, _ := es.Index("test", &b)
fmt.Println(res)
// => [201 Created] {"_index":"test","_id":"uFeRWXQBeb...
Поскольку структуры кодирования или значения map[string]interface{} встречаются очень часто, пакет esutil предоставляет помощник, который выполняет сериализацию и преобразование в io.Reader, поэтому эквивалент приведенного выше кода будет выглядеть следующим образом:
type MyDocument struct {
Title string `json:"title"`
}
doc := MyDocument{Title: "Test"}
res, _ := es.Index("test", esutil.NewJSONReader(&doc))
fmt.Println(res)
// [201 Created] {"_index":"test","_id":"wleUWXQBe...
Примечание. Помощник хорошо работает с пользовательскими кодировщиками JSON. Если тип реализует интерфейс esutil.JSONEncoder, автоматически используется метод EncodeJSON(); в противном случае он возвращается к стандартной библиотеке.
Чтобы понять, как использовать клиент в обычном приложении, потратьте некоторое время на ознакомление с исчерпывающим примером xkcdsearch. Он индексирует информацию из JSON API и позволяет искать ее в командной строке и в браузере. Он демонстрирует несколько методов, таких как встраивание клиента в собственный тип, построение запросов, анализ ответов, выделение совпадающих фраз в результатах, имитация клиента для тестов и многое другое. Вы можете предварительно просмотреть приложение в Интернете.
Читайте также:
- Клиент Go для Elasticsearch
- Клиент Go для Elasticsearch: пакет esapi
- Клиент Go для Elasticsearch: пакет estransport
- Клиент Go для Elasticsearch: конфигурация и кастомизация
- Клиент Go для Elasticsearch: массовая индексация
Комментариев нет:
Отправить комментарий