Oracle R Enterprise (#3)
Oracle R Enterprise étant en place, je peux reprendre les tests de comptage la ou je les avais laissé dans un article précédent…
> library(ORE)
Loading required package: OREbase
Loading required package: OREcommon
Attaching package: ‘OREbase’
The following objects are masked from ‘package:base’:
cbind, data.frame, eval, interaction, order, paste, pmax, pmin, rbind, table
Loading required package: OREembed
Loading required package: OREstats
Loading required package: MASS
Loading required package: OREgraphics
Loading required package: OREeda
Loading required package: OREmodels
Loading required package: OREdm
Loading required package: lattice
Loading required package: OREpredict
Loading required package: ORExml
>
> ore.connect(user="c##raf", password="Password1#", conn_string="//clorai2-scan:1521/pdb_iotst04")
A ce stade, on voit une session connectée à la base:
SQL> column username format a8 SQL> column sql_id format a13 SQL> column sql_text format a90 SQL> SQL> SELECT username, 2 a.sql_id, 3 b.sql_text 4 FROM v$session a, v$sql b 5 WHERE a.program = 'rsession.exe' AND a.sql_id = b.sql_id(+); USERNAME SQL_ID SQL_TEXT -------- ------------- ------------------------------------------------------------------------------------------ C##RAF SQL>
A l’aide d’ore.sync, on peut alors créer des structures « proxy » pour accéder aux tables de la base (dans cet exemple, je précise l’unique table qui m’intéresse: LOG_CONTRIBS). Ces dernières sont de type ore.frame et se manipulent comme des data.frame:
> ore.attach() > ore.sync(table="LOG_CONTRIBS") > > class(LOG_CONTRIBS) [1] "ore.frame" attr(,"package") [1] "OREbase" >
Ainsi, pour faire un comptage exact du nombre de contributeurs distincts à Wikipedia, je peut utiliser la formule R length(unique(<df>)).
> system.time(NB_DISTINCT <- length(unique(LOG_CONTRIBS$UNAME))) user system elapsed 0.00 0.00 50.39 > NB_DISTINCT [1] 28839445 >
Etant donné que LOG_CONTRIBS est un proxy pour la table de même nom, la formule est automatiquement convertie en code SQL. On peut facilement le vérifier à l’aide de la même requête que celle exécutée plus haut:
SQL> SELECT username,
2 a.sql_id,
3 b.sql_text
4 FROM v$session a, v$sql b
5 WHERE a.program = 'rsession.exe' AND a.sql_id = b.sql_id(+);
USERNAME SQL_ID SQL_TEXT
-------- ------------- ------------------------------------------------------------------------------------------
C##RAF cq264yx9bt1fp with OBJ31_1 as ( select /*+ no_merge(t) */ "ID" VAL001,"TMSTAMP" VAL002,"UNAME" VAL003,"
LOGTYPE" VAL004,"LOGACTION" VAL005 from "C##RAF"."LOG_CONTRIBS" t ),OBJ31_2 as ( select /
*+ no_merge(t) */ "UNAME" VAL001 from "C##RAF"."LOG_CONTRIBS" t ) , LEV31_2 as ( select
row_number() over (order by to_char(VAL001)) id, to_char(VAL001) name from OBJ31_2 where V
AL001 is not null group by to_char(VAL001) ),OBJ31_3 as ( select VAL001 NAME001, VAL001 f
rom OBJ31_2 group by VAL001 ) , LEV31_3 as ( select id, name from LEV31_2 ),OBJ31_4 as (
select /*+ no_merge(t) */ 1 NAME001, count(*) VAL001 from OBJ31_3 t ) select * from
OBJ31_4 t order by NAME001
SQL>
Le résultat du comptage est restitué en 50 secondes, ce qui correspond à la durée que nous avions obtenu directement en SQL.
Pour le comptage approximatif, je n’ai pas trouvé de package R implémentant l’algorithme d’HyperLogLog. Ici, j’utilise donc directement une requète SQL au sein d’un bloc ore.doEval.
Cette construction est relativement lourde mais elle permet de montrer l’opération de connexion implicite à l’aide de l’appel « dbConnect(Extproc()) ».
> ore.doEval(function() {
+ ore.disconnect()
+ library(tictoc)
+ tic()
+ con1 <- dbConnect(Extproc())
+ res1 <- dbGetQuery(con1, "select approx_count_distinct(UNAME) from LOG_CONTRIBS")
+ dbDisconnect(con1)
+ exectime <- toc()
+ exectime <- exectime$toc - exectime$tic
+ print(paste("Count distinct: ", res1, " - Duree :", exectime, "secondes"))
+ }, ore.connect = TRUE)
[1] "Count distinct: 30284800 - Duree : 12.18 secondes"
>
> ore.disconnect()
>
On notera aussi la référence au package tictoc (qui offre des fonctions de timing). Pour pouvoir utiliser ce dernier dans des appels ORE, il faut que son chargement soit mentionné explicitement dans le bloc (« library(tictoc) »). De plus, le package doit avoir été préalablement ajouté à la distribution R coté serveur:
oracle@psu888: /home/oracle [IOSHR88D1_2]# ORE CMD INSTALL /home/oracle/ORE/tictoc_1.0.tar.gz
* installing to library ‘/soft/oracle/product/rdbms/12.2.0.1/R/library’
* installing *source* package ‘tictoc’ ...
** package ‘tictoc’ successfully unpacked and MD5 sums checked
** R
** inst
** preparing package for lazy loading
** help
*** installing help indices
converting help for package ‘tictoc’
finding HTML links ... done
Stack html
tic html
tictoc html
** building package indices
** testing if installed package can be loaded
* DONE (tictoc)
oracle@psu888: /home/oracle [IOSHR88D1_2]#
Bien sûr, ici , on aurait plutôt tout intérêt à utiliser une exécution SQL directe via ROracle plutôt qu’un bloc ore.doEval!