# #go #amazon-athena
Вопрос:
Есть ли простой способ преобразовать структуру из athena.GetQueryResultsOutput
структуры в определяемую пользователем структуру в Go?
Вот фрагмент того, чего я хочу достичь:
const testSql = `
select
id,
name,
count(source_id) as aggregate_count,
array_agg(source_id) as aggregate_source_ids,
array_agg(source_name) as aggregate_source_names
from my_glue_catalog_table
group by id, name
`
type myModel struct {
id int64
name string
aggregateCount int
aggregateSourceIDs []int64
aggregateSourceNames []string
}
queryResultOutput, err = awsAthenaClient.GetQueryResults(ctx, amp;queryResultInput)
// var mapped []myModel = mapper.FromGetQueryResultsOutput(queryResultOutput.ResultSet)
И вот структура queryResultOutput.ResultSet
:
ResultSet: {
ResultSetMetadata: {
ColumnInfo: [
{
CaseSensitive: false,
CatalogName: "hive",
Label: "id",
Name: "id",
Nullable: "UNKNOWN",
Precision: 10,
Scale: 0,
SchemaName: "",
TableName: "",
Type: "integer"
},
{
CaseSensitive: true,
CatalogName: "hive",
Label: "name",
Name: "name",
Nullable: "UNKNOWN",
Precision: 2147483647,
Scale: 0,
SchemaName: "",
TableName: "",
Type: "varchar"
},
{
CaseSensitive: false,
CatalogName: "hive",
Label: "aggregate_count",
Name: "aggregate_count",
Nullable: "UNKNOWN",
Precision: 19,
Scale: 0,
SchemaName: "",
TableName: "",
Type: "bigint"
},
{
CaseSensitive: false,
CatalogName: "hive",
Label: "aggregate_source_ids",
Name: "aggregate_source_ids",
Nullable: "UNKNOWN",
Precision: 0,
Scale: 0,
SchemaName: "",
TableName: "",
Type: "array"
},
{
CaseSensitive: false,
CatalogName: "hive",
Label: "aggregate_source_names",
Name: "aggregate_source_names",
Nullable: "UNKNOWN",
Precision: 0,
Scale: 0,
SchemaName: "",
TableName: "",
Type: "array"
}
]
},
Rows: [{
// first row data (from page 1 of results) is header, we can ignore this
Data: [
VarCharValue: "id" },
VarCharValue: "name" },
VarCharValue: "aggregate_count" },
VarCharValue: "aggregate_source_ids" },
VarCharValue: "aggregate_source_names" }
]
},
// all subsequent rows are data values:
{
Data: [
VarCharValue: "920000" },
VarCharValue: "mydata1" },
VarCharValue: "2" },
VarCharValue: "[52800, 113000]" },
VarCharValue: "[sourcedata1, sourcedata2]" }
]
}
]
}
Полный пример кода, который я написал: суть
Если нет лучшей альтернативы, я подумываю написать пакет конвертеров, подобный следующему. Основным предостережением будет надежное преобразование массивов, хотя одно из строковых значений в массиве может содержать запятую. И я считаю, что мы можем вернуться только []interface{}
потому, что Go не поддерживает дженерики (на сегодняшний день)?
// myModel defines a schema that corresponds with testSql above
type myModel struct {
id int `athenaconv:"id"`
name string `athenaconv:"name"`
aggregateCount int64 `athenaconv:"aggregate_count"`
aggregateSourceIDs []int64 `athenaconv:"aggregate_source_ids"`
aggregateSourceNames []string `athenaconv:"aggregate_source_names"`
}
mapper := athenaconv.MapperFor(reflect.TypeOf(myModel))
var mapped []interface{} = mapper.FromAthenaResultSet(queryResultOutput.ResultSet)
Комментарии:
1. пожалуйста, перепишите, чтобы сначала представить API Athena, текущий результат, который вы получаете, желаемый результат, а затем описать сложность разрыва.
2. @mh-cbon Я думаю, я надеялся на более простую альтернативу для преобразования набора результатов Athena, который в основном представляет собой 2D-массив строк отдельные метаданные, в строго типизированную модель в golang. В итоге я создал свой собственный пакет, чтобы добиться этого с помощью отражения.
Ответ №1:
Поскольку я не смог найти лучшей альтернативы и работаю с большим количеством наборов данных для анализа, я написал свою собственную библиотеку пакетов, чтобы выяснить сопоставление столбцов и преобразовать типы athena в типы данных go. Это поможет нам привязать афину ResultSet
к фрагменту строго типизированной модели.
Я сделал его с открытым исходным кодом под athenaconv. Оставляю в качестве ответа на случай, если это поможет кому-то другому.
Иди и возьми его
go get github.com/kent-id/athenaconv
Использование
mapper, err := athenaconv.NewMapperFor(reflect.TypeOf(MyModel{}))
if err != nil {
handleError(err)
}
var mapped []interface{}
mapped, err = mapper.FromAthenaResultSetV2(ctx, queryResultOutput.ResultSet)
if err != nil {
handleError(err)
}
for _, mappedItem := range mapped {
mappedItemModel := mappedItem.(*MyModel)
fmt.Printf("% vn", *mappedItemModel)
}
Комментарии:
1. избегайте бесполезного распределения github.com/kent-id/athenaconv/blob/main/mapper.go#L59 на и используйте длину, доступную из среза строк github.com/aws/aws-sdk-go-v2/blob/main/service/athena/types/…
2. @mh-cbon — да, вы правы, я удалю бесполезное выделение. Если у вас есть дополнительные отзывы, пожалуйста, дайте мне знать либо через GitHub предложение по выпуску/DM. Я на ранней стадии погружения в мир голанга, поэтому очень ценю ваши отзывы 🙂