Skip to content

Commit 3075dad

Browse files
committed
Add scr batch JSON format
1 parent f19d261 commit 3075dad

File tree

4 files changed

+129
-16
lines changed

4 files changed

+129
-16
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: sasctl
22
Title: The sasctl package enables easy communication between the SAS Viya platform APIs and the R runtime
3-
Version: 0.7.4
3+
Version: 0.7.4.9000
44
Author: Eduardo Hellas
55
Authors@R: c(
66
person(given = "Eduardo",

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# sasctl (development version)
2+
3+
* Added `scr_batch` argument to `format_data_json`, allowing to have all data in a single json payload for Viya 2024.7 SCR batch scoring feature.
4+
15
# sasctl 0.7.4
26

37
* Added `verify_ssl` argument to `session` to be used in all api calls.

R/json_files.R

Lines changed: 98 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -279,20 +279,29 @@ write_fileMetadata_json <- function(scoreCodeName = "scoreCode.R",
279279
#'
280280
#' @param df data frame to be transformed in JSON format rows
281281
#' @param scr boolean, if `TRUE` will write the new json format with metadata
282+
#' @param scr_batch boolean, if `TRUE` will write the batch format JSON for SCR, metadata is ignored
282283
#' @param metadata_columns columns names to be used as metadata. If scr is set to `FALSE`, metatada_columns is ignored
283-
#' @return a vector of JSON strings
284+
#' @return a vector of JSON strings or a single json string when `scr_batch` is set to `TRUE`
284285
#' @examples
285286
#'
286287
#' json_output <- format_data_json(mtcars)
287288
#' json_output
288289
#'
290+
#' json_output <- format_data_json(mtcars, scr = TRUE)
291+
#' json_output
292+
#'
293+
#' json_output <- format_data_json(mtcars, scr_batch = TRUE)
294+
#' jsonlite::prettify(json_output)
295+
#'
289296
#' @export
290297
#'
291298

292299

293-
format_data_json <- function(df, scr = FALSE, metadata_columns = NULL){
294-
300+
format_data_json <- function(df, scr = FALSE, scr_batch = FALSE, metadata_columns = NULL){
295301

302+
if (scr_batch & scr) {
303+
stop("Only one of'scr' and 'scr_batch' can be set to TRUE")
304+
}
296305
## check is any is factor, otherwise print in write_json_row
297306
## will write factor as numeric string
298307

@@ -312,6 +321,8 @@ format_data_json <- function(df, scr = FALSE, metadata_columns = NULL){
312321
outs <- by(df, list(seq_len(nrow(df))), write_json_row_scr,
313322
metadata_columns = metadata_columns)
314323

324+
} else if (scr_batch) {
325+
outs <- write_json_batch_scr(df)
315326
} else {
316327

317328
outs <- by(df, list(seq_len(nrow(df))), write_json_row)
@@ -338,7 +349,6 @@ format_data_json <- function(df, scr = FALSE, metadata_columns = NULL){
338349
#'
339350
#' @noRd
340351

341-
342352
write_json_row <- function(row) {
343353

344354
### goal is to create a son in the following format
@@ -353,10 +363,10 @@ write_json_row <- function(row) {
353363
var_vect <- paste0('{"name": "', colnames(row), '"',
354364
ifelse(sapply(row, is.na), paste0(', "value": null'),
355365
ifelse(sapply(row, is.character), paste0(', "value": ', '"', row, '"'),
356-
## the "error" string output may give a silent error
366+
## the "\"CONVERSION_ERROR\"" string output may give a silent error
357367
## it is here for placeholder because if I add stop() it
358-
## will halt the function, even though it is never returning "error"
359-
ifelse(sapply(row, is.numeric), paste0(', "value": ', row), "error"))), ' }')
368+
## will halt the function, even though it is never returning "\"CONVERSION_ERROR\""
369+
ifelse(sapply(row, is.numeric), paste0(', "value": ', row), "\"CONVERSION_ERROR\""))), ' }')
360370

361371
out <- paste0('{"inputs": [ ', paste0(var_vect, collapse = ", "), '] }')
362372

@@ -378,7 +388,7 @@ write_json_row <- function(row) {
378388
#' @examples
379389
#'
380390
#' json_output <- write_json(mtcars[1,])
381-
#' json_output
391+
#' jsonlite::prettify(json_output)
382392
#'
383393
#' @noRd
384394
#'
@@ -415,26 +425,100 @@ write_json_row_scr <- function(row, metadata_columns = NULL) {
415425
meta_vect <- paste0('"', colnames(row_meta), '": ',
416426
ifelse(sapply(row_meta, is.na), paste0('null'),
417427
ifelse(sapply(row_meta, is.character), paste0('"', row_meta, '"'),
418-
## the "error" string output may give a silent error
428+
## the "\"CONVERSION_ERROR\"" string output may give a silent error
419429
## it is here for placeholder because if I add stop() it
420-
## will halt the function, even though it is never returning "error"
421-
ifelse(sapply(row_meta, is.numeric), paste0(row_meta), "error"))), '')
430+
## will halt the function, even though it is never returning "\"CONVERSION_ERROR\""
431+
ifelse(sapply(row_meta, is.numeric), paste0(row_meta), "\"CONVERSION_ERROR\""))), '')
422432
} else {
423433
meta_vect <- list()
424434
}
425435

426436
var_vect <- paste0('"', colnames(row), '": ',
427437
ifelse(sapply(row, is.na), paste0('null'),
428438
ifelse(sapply(row, is.character), paste0('"', row, '"'),
429-
## the "error" string output may give a silent error
439+
## the "\"CONVERSION_ERROR\"" string output may give a silent error
430440
## it is here for placeholder because if I add stop() it
431-
## will halt the function, even though it is never returning "error"
432-
ifelse(sapply(row, is.numeric), paste0(row), "error"))), ' ')
441+
## will halt the function, even though it is never returning "\"CONVERSION_ERROR\""
442+
ifelse(sapply(row, is.numeric), paste0(row), "\"CONVERSION_ERROR\""))), ' ')
433443

434444
out <- paste0('{"metadata": {', paste0(meta_vect, collapse = ", "), "}, " ,
435445

436446
'"data": {', paste0(var_vect, collapse = ", "), '} }')
447+
448+
return(out)
449+
450+
}
451+
452+
#' Helper to create SCR batch json
453+
#'
454+
#' Helper to be used on `write_json_batch_scr`
455+
#'
456+
#' @param row single row data.frame
457+
#' @param row_number row number
458+
#' @return pseudo JSON string
459+
#'
460+
#' @noRd
461+
462+
create_batch_vector <- function(row, row_number) {
463+
var_vect <- paste0("\"", colnames(row), "\": ", ifelse(sapply(row,
464+
is.na), paste0("null"), ifelse(sapply(row, is.character),
465+
paste0("\"", row, "\""), ifelse(sapply(row, is.numeric),
466+
paste0(row), "\"CONVERSION_ERROR\""))), " ")
467+
return(paste0("[",row_number,", {", paste0(var_vect, collapse = ", "), " } ]"))
468+
469+
}
470+
471+
#' Format row to SCR Batch json
472+
#'
473+
#' will create a single Json for a data.frame in a newer supported format (Viya 2024.7 or above)
474+
#' This is a vectorized version, without data manipulation
475+
#' Convert all factors columns to string otherwise `ifelse()` will coerce to integer
476+
#'
477+
#' @param df data.frame
478+
#' @return a JSON string
479+
#' @examples
480+
#'
481+
#' json_output <- write_json_batch_scr(mtcars)
482+
#' jsonlite::prettify(json_output)
483+
#'
484+
#' @noRd
485+
#'
486+
487+
write_json_batch_scr <- function(df) {
488+
489+
### goal is to create a json in the following format
490+
### SCR now has a special batch format
491+
### This is the new format since viya 2024.7
492+
# {
493+
# "data": [
494+
# [
495+
# 1,
496+
# {
497+
# "varnumeric1": 5.1,
498+
# "varnumeric2": 0.2,
499+
# "varcharacter": "setosa"
500+
# }
501+
# ],
502+
# [
503+
# 2,
504+
# {
505+
# "varnumeric1": 5.1,
506+
# "varnumeric2": 0.2,
507+
# "varcharacter": "setosa"
508+
# }
509+
# ]
510+
# ]
511+
# }
512+
513+
if (any(lapply(df, class) == "factor")) {
514+
stop("data.frame with factor class is not supported.")
515+
}
516+
517+
data <- split(df, seq(nrow(df)))
518+
519+
vect <- mapply(FUN = create_batch_vector, row = data, row_number = 1:length(data))
437520

521+
out <- paste0("{ \"data\": [", paste0(vect, collapse = ", "),"] }")
438522
return(out)
439523

440524
}

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,29 @@ payload for a MAS call, which doesn’t have a standard format.
323323
"<input3_name>": "string_value"
324324
}
325325
}
326+
327+
### Payload for SCR batch mode on Viya 2024.7 or higher
328+
329+
{
330+
"data": [
331+
[
332+
1,
333+
{
334+
"varnumeric1": 5.1,
335+
"varnumeric2": 0.2,
336+
"varcharacter": "string_value"
337+
}
338+
],
339+
[
340+
2,
341+
{
342+
"varnumeric1": 5.1,
343+
"varnumeric2": 0.2,
344+
"varcharacter": "string_value"
345+
}
346+
]
347+
]
348+
}
326349
```
327350

328351
There is a helper function that transform all the rows in a vector of
@@ -332,7 +355,9 @@ for batch scoring.
332355
``` r
333356
hmeq <- read.csv("https://support.sas.com/documentation/onlinedoc/viya/exampledatasets/hmeq.csv")
334357

335-
hmeq_json <- format_data_json(head(hmeq)) ## use argument scr = TRUE for newer format
358+
## Use argument scr = TRUE for SCR format
359+
## Use scr_batch = TRUE for single JSON for SCR batch
360+
hmeq_json <- format_data_json(head(hmeq))
336361

337362
jsonlite::prettify(hmeq_json[1])
338363
```

0 commit comments

Comments
 (0)