Published on :

Definition and Management of User-Defined CAS Actions

This code is also available in: Deutsch Español Français
Awaiting validation
Attention : This code requires administrator privileges.
This script uses `PROC CAS` and the CASL language to create a custom action set named 'tableSizeHuman'. This set contains three actions:
1. tableStats: Calculates the size and compression details of a CAS table (in KB, MB, GB, TB) and provides frequency counts of column data types using `table.tableInfo`, `table.tableDetails`, `table.fetch` with computed variables, `table.columnInfo`, and `simple.freq`.
2. profCols: Profiles selected columns of a CAS table via the `dataDiscovery.profile` action.
3. imageMelt: Combines image processing detections with cropped image data by performing `transpose.transpose` operations and a `fedsql.execdirect` join.
Furthermore, the script creates a new CASLIB named 'UDAS' pointing to a specific path (`/viyafiles/sasss1/userDefinedActionSets`) and persists the 'tableSizeHuman' action set as a `.sashdat` file within it, ensuring its availability for other CAS sessions.
Data Analysis

Type : MIXED


User-defined actions process existing CAS tables whose names and caslibs are passed as parameters (e.g., 'caslib' and 'table'). The script does not create raw source data, but it generates temporary tables in CAS for its intermediate calculations. The 'UDAS' CASLIB is created to store the action definitions themselves, not to store input data in the traditional sense. The commented code suggests the use of tables like 'baseball' that are assumed to exist in CAS.

1 Code Block
PROC CAS
Explanation :
This block initializes a CAS session and assigns all existing CAS libraries. It then defines a custom CAS action set named 'tableSizeHuman' containing three actions: 'tableStats' to calculate table sizes and data type frequencies, 'profCols' to profile columns, and 'imageMelt' to merge detection and image data. Each action uses CASL functions and native CAS actions (`table.tableInfo`, `table.tableDetails`, `table.fetch`, `table.columnInfo`, `simple.freq`, `dataDiscovery.profile`, `transpose.transpose`, `fedsql.execdirect`) to accomplish its task. These actions are written in CASL and are executed within PROC CAS.
Copied!
1cas;
2caslib _all_ assign;
3/* Orginal code authored by Chris Ricciardi */
4/* TB, compressedKB,compressedMB,compressedGB,compressedTB added by Steven Sober */
5/* You must modify the path in the CASLIB USDA at the bottom of the code */
6 
7PROC CAS;
8 BUILTINS.defineActionSet /
9 name="tableSizeHuman"
10 actions={
11 {
12 name="tableStats"
13 desc="Multiple Table actions with calculation of CAS table size and datatype frequency count"
14 parms={
15 {name="caslib" type="string" required=TRUE}
16 {name="table" type="string" required=TRUE}
17 {name="level" type="string" required=FALSE default="sum"}
18 }
19 definition = "
20 table.tableInfo result=r status=s /
21 caslib=caslib
22 name=table;
23 if 0 != s.severity then do;
24 send_response(s);
25 end;
26 send_response(r);
27 run;
28 
29 table.tableDetails result=r status=s /
30 caslib=caslib
31 name=table
32 level=level;
33 if 0 != s.severity then do;
34 send_response(s);
35 end;
36 send_response(r);
37 run;
38 
39 details = findTable(r);
40 saveresult details caslib=caslib casout='casdatasize' replace;
41 
42 table.fetch result=r status=s /
43 table={caslib=caslib name='casdatasize'
44 computedVars={name='KB',name='MB',name='GB',name='TB',
45 name='compressedKB',name='compressedMB',name='compressedGB',name='compressedTB'}
46 computedVarsProgram='
47 KB=round(DataSize / (1024),0.01);
48 MB=round(DataSize / (1024*1024),0.01);
49 GB=round(DataSize / (1024*1024*1024),0.01);
50 TB=round(DataSize / (1024*1024*1024*1024),0.01);
51 compressedKB=round(CompressedSize / (1024),0.01);
52 compressedMB=round(CompressedSize / (1024*1024),0.01);
53 compressedGB=round(CompressedSize / (1024*1024*1024),0.01);
54 compressedTB=round(CompressedSize / (1024*1024*1024*1024),0.01);
55 '}
56 fetchVars={'DataSize', 'VardataSize', 'KB', 'MB', 'GB', 'TB',
57 'CompressedSize', 'compressedKB', 'compressedMB', 'compressedGB', 'compressedTB'};
58
59 if 0 != s.severity then do;
60 send_response(s);
61 end;
62 send_response(r);
63 run;
64 
65 /*size = round((details[1,6] + details[1,7]) / (1024*1024),0.01);
66 print (string)size || 'MB';
67 run;*/
68 
69 table.columnInfo result=r status=s /
70 table={caslib=caslib name=table};
71 if 0 != s.severity then do;
72 send_response(s);
73 end;
74 send_response(r);
75 run;
76 
77 columns = findTable(r);
78 saveresult columns caslib=caslib casout='cascolumns' replace;
79 
80 simple.freq result=r status=s /
81 table={caslib=caslib name='cascolumns'}
82 inputs={{name='type'}};
83 if 0 != s.severity then do;
84 send_response(s);
85 end;
86 send_response(r);
87 run;
88 "
89 },
90 {
91 name="profCols"
92 desc="Profile selected columns"
93 parms={
94 {name="caslib" type="string" required=TRUE}
95 {name="table" type="string" required=TRUE}
96 {name="col" type="string" unkeyedList=TRUE required=TRUE}
97 }
98 definition = "
99 dataDiscovery.profile result=r status=s /
100 table={name=table, caslib=caslib},
101 casOut={caslib=caslib, name='profcols', replication=0, replace=True},
102 columns=col,
103 frequencies=2,
104 minmax=2;
105 if 0 != s.severity then do;
106 send_response(s);
107 end;
108 send_response(r);
109 "
110 },
111 {
112 name="imageMelt"
113 desc="Combine image processing detections with cropped images"
114 parms={
115 {name="caslib" type="string" required=TRUE}
116 {name="detections" type="string" required=TRUE}
117 {name="cropped" type="string" required=TRUE}
118 {name="casout" type="string" required=TRUE}
119 }
120 definition = "
121 table.columnInfo result=r /
122 table={name=detections caslib=caslib};
123 col_info = findTable(r);
124 varlist = {};
125 do colname over col_info;
126 if length(colname.Column) ge 7 then do;
127 obj = substr(colname.Column,1,7);
128 end;
129 if obj = '_Object' then do;
130 tempVar=colname.Column;
131 varlist = varlist + {tempVar};
132 end;
133 end;
134 run;
135 
136 /*print varlist;
137 run;*/
138 
139 transpose.transpose / table ={name=detections caslib=caslib groupBy = {'_id_', '_filename_0', '_nObjects_'}
140 computedVars={name='idvalue'}
141 computedVarsProgram='idvalue=""Values""'}
142 casout = {name='obj_melted' caslib=caslib replace=true replication=0}
143 id = {'idvalue'}
144 let = 0
145 transpose = varlist
146 name = 'ColName';
147 run;
148 
149 transpose.transpose / table={name='obj_melted' caslib=caslib groupby={'_id_', 'object', '_filename_0', '_nObjects_'}
150 computedVars={{name='object'},{name='type'}}
151 computedVarsProgram=""object=substr(ColName,8,(index(substr(ColName,2),'_')-7));
152 if type = substr(ColName,(index(substr(ColName,2),'_')+2)) = ''
153 then type = 'objname';
154 else type = substr(ColName,(index(substr(ColName,2),'_')+2));""}
155 casout={name='obj_melted2' caslib=caslib replace=true replication=0}
156 id={'type'}
157 transpose = {'Values'}
158 let = False;
159 run;
160 
161 table.tableInfo result=r /
162 name=cropped;
163 tinfo = findTable(r);
164 crop = tinfo[1,1];
165 /*print 'crop is ' crop;*/
166 clib = tinfo[1,18];
167 /*print 'clib is ' clib;*/
168 run;
169 
170 qstring = 'create TABLE ' || clib || '.' || casout || ' {options replace=true replication=0} as select
171 t1.*, t2._filename_0, t2._nObjects_, /*cast(t2.object as double) as object,*/ t2.objname,
172 cast(t2.height as double) as height, cast(t2.width as double) as width,
173 cast(t2.x as double) as x, cast(t2.y as double) as y
174 from ' || clib || '.' || crop || ' t1 left join ' || clib || '.obj_melted2 t2
175 on (t1._parentId_ = t2._id_ and t1._id_ = cast(t2.object as double))';
176 /*print qstring;*/
177 run;
178 
179 fedsql.execdirect /
180 query=qstring;
181 run;
182 
183 table.tableInfo result=r status=s /
184 caslib=caslib
185 name='obj_joined';
186 if 0 != s.severity then do;
187 send_response(s);
188 end;
189 send_response(r);
190 run;
191 
192 table.dropTable / caslib=caslib name='obj_melted';
193 run;
194 table.dropTable / caslib=caslib name='obj_melted2';
195 run;
196 "
197 }
198 }
199 ;
200RUN;
201QUIT;
2 Code Block
PROC CAS Data
Explanation :
This block adds a new CAS library (CASLIB) named 'UDAS' that points to a specific system path (`/viyafiles/sasss1/userDefinedActionSets`). The purpose of this CASLIB is to store persistent files for user-defined actions. Then, it uses the `builtins.actionSetToTable` action to convert the previously defined 'tableSizeHuman' action set into a persistent CAS table within the 'UDAS' CASLIB. Finally, the `table.save` action is used to save this CAS table as a `tableSizeHuman.sashdat` file on the CAS controller, making the user-defined action set available for future CAS sessions.
Copied!
1PROC CAS;
2 TABLE.addCaslib /
3 caslib='UDAS'
4 dataSource={srctype='path'}
5 path="/viyafiles/sasss1/userDefinedActionSets";
6RUN;
7QUIT;
8 
9PROC CAS;
10 BUILTINS.actionSetToTable /
11 actionSet="tableSizeHuman"
12 casOut={caslib="UDAS" name="tableSizeHuman" replace=True};
13RUN;
14 TABLE.save /
15 caslib="UDAS"
16 TABLE="tableSizeHuman"
17 name="tableSizeHuman.sashdat"
18 replace=True;
19QUIT;
This material is provided "as is" by We Are Cas. There are no warranties, expressed or implied, as to merchantability or fitness for a particular purpose regarding the materials or code contained herein. We Are Cas is not responsible for errors in this material as it now exists or will exist, nor does We Are Cas provide technical support for it.
Copyright Info : Copyright © 2021, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. SPDX-License-Identifier: Apache-2.0