1919
2020package org .apache .geaflow .dsl .udf .graph ;
2121
22- import java .lang .reflect .InvocationTargetException ;
23- import java .lang .reflect .Method ;
24- import java .util .ArrayList ;
2522import java .util .Collections ;
2623import java .util .Iterator ;
2724import java .util .List ;
25+ import java .util .Objects ;
2826import java .util .Optional ;
27+ import org .apache .geaflow .common .config .ConfigHelper ;
28+ import org .apache .geaflow .common .config .Configuration ;
29+ import org .apache .geaflow .common .config .InferConfigHelper ;
30+ import org .apache .geaflow .common .config .keys .FrameworkConfigKeys ;
31+ import org .apache .geaflow .common .exception .GeaflowRuntimeException ;
2932import org .apache .geaflow .common .type .Types ;
3033import org .apache .geaflow .dsl .common .algo .AlgorithmRuntimeContext ;
3134import org .apache .geaflow .dsl .common .algo .AlgorithmUserFunction ;
35+ import org .apache .geaflow .dsl .common .algo .DynamicVertexRuntimeContext ;
3236import org .apache .geaflow .dsl .common .algo .IncrementalAlgorithmUserFunction ;
3337import org .apache .geaflow .dsl .common .data .Row ;
34- import org .apache .geaflow .dsl .common .data .RowEdge ;
3538import org .apache .geaflow .dsl .common .data .RowVertex ;
3639import org .apache .geaflow .dsl .common .data .impl .ObjectRow ;
3740import org .apache .geaflow .dsl .common .function .Description ;
3841import org .apache .geaflow .dsl .common .types .ArrayType ;
3942import org .apache .geaflow .dsl .common .types .GraphSchema ;
4043import org .apache .geaflow .dsl .common .types .StructType ;
4144import org .apache .geaflow .dsl .common .types .TableField ;
45+ import org .apache .geaflow .dsl .udf .graph .gcn .AbstractGCNSubgraphAdapter ;
4246import org .apache .geaflow .dsl .udf .graph .gcn .GCNConfig ;
4347import org .apache .geaflow .dsl .udf .graph .gcn .GCNFeatureCollector ;
4448import org .apache .geaflow .dsl .udf .graph .gcn .GCNInferPayload ;
4549import org .apache .geaflow .dsl .udf .graph .gcn .GCNInferResult ;
4650import org .apache .geaflow .dsl .udf .graph .gcn .GCNResultParser ;
4751import org .apache .geaflow .dsl .udf .graph .gcn .GCNSubgraphBuilder ;
52+ import org .apache .geaflow .infer .InferContext ;
4853import org .apache .geaflow .model .graph .edge .EdgeDirection ;
54+ import org .apache .geaflow .model .graph .edge .IEdge ;
4955
5056@ Description (name = "gcn" , description = "built-in udga for GCN inference" )
5157public class GCN implements AlgorithmUserFunction <Object , Object >, IncrementalAlgorithmUserFunction {
5258
5359 private AlgorithmRuntimeContext <Object , Object > context ;
60+ private DynamicVertexRuntimeContext <Object , Object > dynamicContext ;
5461 private GCNConfig config ;
5562 private GCNSubgraphBuilder subgraphBuilder ;
63+ private InferContext <Object > localInferContext ;
5664 private final GCNFeatureCollector featureCollector = new GCNFeatureCollector ();
5765 private final GCNResultParser resultParser = new GCNResultParser ();
5866
5967 @ Override
6068 public void init (AlgorithmRuntimeContext <Object , Object > context , Object [] params ) {
6169 this .context = context ;
70+ this .dynamicContext = context instanceof DynamicVertexRuntimeContext
71+ ? (DynamicVertexRuntimeContext <Object , Object >) context : null ;
6272 this .config = parseConfig (params );
6373 this .subgraphBuilder = new GCNSubgraphBuilder (config );
74+ this .localInferContext = createLocalInferContext (context .getConfig ());
6475 }
6576
6677 @ Override
@@ -69,13 +80,17 @@ public void process(RowVertex vertex, Optional<Row> updatedValues, Iterator<Obje
6980 return ;
7081 }
7182 GCNInferPayload payload = subgraphBuilder .build (vertex .getId (), new DynamicGraphAdapter (vertex ));
72- Object rawResult = context . infer (payload );
83+ Object rawResult = infer (payload );
7384 GCNInferResult result = resultParser .parse (vertex .getId (), rawResult );
7485 context .take (ObjectRow .create (result .toRowValues ()));
7586 }
7687
7788 @ Override
7889 public void finish (RowVertex graphVertex , Optional <Row > updatedValues ) {
90+ if (localInferContext != null ) {
91+ localInferContext .close ();
92+ localInferContext = null ;
93+ }
7994 }
8095
8196 @ Override
@@ -102,65 +117,88 @@ private GCNConfig parseConfig(Object[] params) {
102117 return new GCNConfig (numHops , numSamplesPerHop , className );
103118 }
104119
105- private class DynamicGraphAdapter implements GCNSubgraphBuilder .GraphAdapter {
120+ private Object infer (GCNInferPayload payload ) {
121+ if (localInferContext == null ) {
122+ return context .infer (payload );
123+ }
124+ try {
125+ return localInferContext .infer (payload );
126+ } catch (Exception e ) {
127+ throw new GeaflowRuntimeException ("GCN local infer failed" , e );
128+ }
129+ }
130+
131+ private InferContext <Object > createLocalInferContext (Configuration baseConfig ) {
132+ if (!ConfigHelper .getBooleanOrDefault (baseConfig .getConfigMap (),
133+ FrameworkConfigKeys .INFER_ENV_ENABLE .getKey (), false )) {
134+ return null ;
135+ }
136+ String globalClassName = InferConfigHelper .getTransformClassName (baseConfig );
137+ if (Objects .equals (config .getPythonTransformClassName (), globalClassName )) {
138+ return null ;
139+ }
140+ return createInferContext (InferConfigHelper .buildInferConfiguration (baseConfig ,
141+ config .getPythonTransformClassName ()));
142+ }
143+
144+ protected InferContext <Object > createInferContext (Configuration configuration ) {
145+ return new InferContext <>(configuration );
146+ }
147+
148+ private class DynamicGraphAdapter extends AbstractGCNSubgraphAdapter <RowVertex > {
106149
107150 private final GraphSchema graphSchema = context .getGraphSchema ();
108- private final RowVertex rootVertex ;
151+ private final Object rootId ;
109152
110153 DynamicGraphAdapter (RowVertex rootVertex ) {
111- this .rootVertex = rootVertex ;
154+ super (rootVertex .getId (), rootVertex , config .getFeatureDimLimit ());
155+ this .rootId = rootVertex .getId ();
112156 }
113157
114158 @ Override
115- public List <Object > loadNeighbors (Object nodeId ) {
159+ protected List <? extends IEdge < Object , ?>> loadEdges (Object nodeId ) {
116160 RowVertex current = switchVertex (nodeId );
117- if (current == null ) {
118- restoreVertex (rootVertex .getId ());
119- return Collections .emptyList ();
120- }
121- List <RowEdge > edges = context .loadEdges (EdgeDirection .BOTH );
122- List <Object > neighbors = new ArrayList <>(edges .size ());
123- for (RowEdge edge : edges ) {
124- Object neighborId = nodeId .equals (edge .getSrcId ()) ? edge .getTargetId ()
125- : edge .getSrcId ();
126- neighbors .add (neighborId );
161+ try {
162+ if (current == null ) {
163+ return Collections .emptyList ();
164+ }
165+ return context .loadEdges (EdgeDirection .BOTH );
166+ } finally {
167+ restoreVertex ();
127168 }
128- restoreVertex (rootVertex .getId ());
129- return neighbors ;
130169 }
131170
132171 @ Override
133- public double [] loadFeatures (Object nodeId ) {
134- RowVertex vertex = nodeId . equals ( rootVertex . getId ()) ? rootVertex : switchVertex (nodeId );
172+ protected RowVertex loadNode (Object nodeId ) {
173+ RowVertex vertex = switchVertex (nodeId );
135174 try {
136- return vertex == null ? new double [config .getFeatureDimLimit ()]
137- : featureCollector .collectFromRowVertex (vertex , graphSchema ,
138- config .getFeatureDimLimit ());
175+ return vertex ;
139176 } finally {
140- restoreVertex (rootVertex . getId () );
177+ restoreVertex ();
141178 }
142179 }
143180
181+ @ Override
182+ protected double [] extractFeatures (RowVertex vertex ) {
183+ return featureCollector .collectFromRowVertex (vertex , graphSchema ,
184+ config .getFeatureDimLimit ());
185+ }
186+
144187 private RowVertex switchVertex (Object nodeId ) {
145- try {
146- Method setVertexId = context .getClass ().getMethod ("setVertexId" , Object .class );
147- setVertexId .invoke (context , nodeId );
148- Method loadVertex = context .getClass ().getMethod ("loadVertex" );
149- return (RowVertex ) loadVertex .invoke (context );
150- } catch (NoSuchMethodException e ) {
151- throw new IllegalStateException ("GCN requires dynamic runtime context with loadVertex support" , e );
152- } catch (IllegalAccessException | InvocationTargetException e ) {
153- throw new IllegalStateException ("Failed to switch runtime context vertex" , e );
188+ if (dynamicContext == null ) {
189+ throw new IllegalStateException (
190+ "GCN requires DynamicVertexRuntimeContext to load sampled vertices" );
154191 }
192+ dynamicContext .setVertexId (nodeId );
193+ return dynamicContext .loadVertex ();
155194 }
156195
157- private void restoreVertex (Object rootId ) {
158- try {
159- Method setVertexId = context .getClass ().getMethod ("setVertexId" , Object .class );
160- setVertexId .invoke (context , rootId );
161- } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e ) {
162- throw new IllegalStateException ("Failed to restore runtime context vertex" , e );
196+ private void restoreVertex () {
197+ if (dynamicContext == null ) {
198+ throw new IllegalStateException (
199+ "GCN requires DynamicVertexRuntimeContext to restore sampled vertices" );
163200 }
201+ dynamicContext .setVertexId (rootId );
164202 }
165203 }
166204}
0 commit comments