#r #post #rounding #precision #plumber
#r #Публикация #округление #точность #plumber
Вопрос:
Платформа: — Экземпляр AWS с 16 ядрами и 128 гигабайтами оперативной памяти. — Redhat Enterprise 7.5. — Сервер R. — RStudio. — Plumber API предоставляет функции R в качестве конечных точек веб-службы. — Клиентская сторона — Excel VBA.
Проблема: — Таблица данных с различными типами столбцов, включая double, целые числа и строковые данные. — Непосредственно перед тем, как функция конечной точки R отправляет ответ (таблицу), и когда я проверяю двойные данные в таблице данных, все записи имеют длину от 6 до 10 знаков после запятой. — Как только таблица поступает в формате JSON на стороне клиента, 99% двойных столбцов округляются до 4 знаков после запятой.
Есть идеи, в чем может быть проблема — почему двойные округляются и где происходит округление и как я могу это предотвратить? — Я пробовал разные настройки заголовка запроса, и это не сработало. — Я попытался отправить затронутые двойные столбцы в виде вектора или списка, но я получаю то же самое «принудительное» округление.
Заранее спасибо
Ответ №1:
Это было не очень хорошо документировано, но оказывается, что это результат использования значений по умолчанию в jsonlite::toJSON
сериализаторе ( digits = 4
). Здесь есть некоторые подробности:
https://www.rplumber.io/articles/rendering-output.html
Я не вижу, как передать аргумент в это из вашей параметризации, но вот обходной путь:
library(plumber)
#* @apiTitle A Test API
#* Run a simple function
#* @get /
function(req, res) {
x <- rnorm(1)
res$body <- jsonlite::toJSON(x, digits = NA)
res
}
# plumb("plumber_1.R")$run(port = 5762)
# Save this file as e.g. "plumber_1.R" and run the commented line
Тогда вы должны быть в состоянии получить ответ, подобный этому:
library(httr)
y <- GET("http://127.0.0.1:5762/")
content(y, as = "text")
[1] "[-0.982448323838634]"
Итак, каким бы ни был результат вашей функции, предварительно сериализуйте его с помощью jsonlite::toJSON(..., digits = NA)
и сохраните его непосредственно в теле ответа, затем верните объект response.
Оказывается, есть «правильный» способ сделать это, о котором я узнал, зарегистрировав это как проблему на GitHubhttps://github.com/trestletech/plumber/issues/403 . Однако, похоже, что эта версия еще не включена в CRAN, поэтому вы можете пока использовать исправление, приведенное выше.
В определении вашего API укажите сериализатор следующим образом:
#' @serializer json list(digits = 12)
или, в частности, для json
#' @json(digits = 12)
Комментарии:
1. Большое спасибо Брайану. Но есть ли лучший способ сделать это вместо того, чтобы сериализовать ответ самостоятельно? Например, есть ли настройка или какая-либо функция в Plumber API, которую я могу вызвать или манипулировать, чтобы получить 10 цифр?
2. Большое спасибо Брайану. Это не сработало. Я пробовал оба варианта, но они не сработали (#’ @serializer json list (digits = 12) или #’ @json (digits = 12)). Двойное значение по-прежнему округляется. Может ли это быть проблемой с версией? У меня есть Plumber 0.4.4
3. @Tiger Я думаю, что они были добавлены только в версии разработки 0.5.0, которой еще нет в CRAN.
4. Спасибо, Брайан. Последний вопрос, пока мы продолжаем тему. Иногда, когда я отправляю запрос на конечную точку Plumber, некоторые символы не проходят гладко сериализацию Plumber, и они приводят к тому, что конечная точка не видит тело запроса. Знакомы ли вы с проблемой, и если да, то какой подход был бы наилучшим?
5. Спасибо, Брайан. #’ список json @serializer (цифры = 12) работает в Plumber API 0.4.7
Ответ №2:
Если вы хотите установить это для всех маршрутов, вы также можете использовать следующее (в plumber.R
#* PI
#* @get /pi
function() {
pi
}
#* e
#* @get /e
function() {
exp(1)
}
# Below is "new" and solves this
#* @plumber
function(pr) {
pr <- pr |>
# Overwrite the default serializer to return more digits
pr_set_serializer(serializer_json(digits = 10))
}
Который возвращает
# print 10 digits
options(digits = 10)
# returned JSON has 10 digits
httr::content(httr::GET("http://127.0.0.1:8850/pi"), as = "text")
#> [1] "[3.1415926536]"
# automatically converting to R returns 10 digits
httr::content(httr::GET("http://127.0.0.1:8850/pi"))
#> [[1]]
#> [1] 3.1415926536