Improve the performance of resoures microservice
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / serialization / engines / query / GraphTraversalQueryEngine.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *    http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.onap.aai.serialization.engines.query;
21
22
23 import static org.onap.aai.edges.enums.AAIDirection.IN;
24 import static org.onap.aai.edges.enums.AAIDirection.NONE;
25 import static org.onap.aai.edges.enums.AAIDirection.OUT;
26 import static org.onap.aai.edges.enums.EdgeField.PRIVATE;
27 import static org.onap.aai.edges.enums.EdgeProperty.CONTAINS;
28 import static org.onap.aai.edges.enums.EdgeProperty.DELETE_OTHER_V;
29
30 import java.util.List;
31 import java.util.Set;
32
33 import org.apache.tinkerpop.gremlin.process.traversal.Order;
34 import org.apache.tinkerpop.gremlin.process.traversal.P;
35 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
36 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
37 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
38 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
39 import org.apache.tinkerpop.gremlin.structure.Direction;
40 import org.apache.tinkerpop.gremlin.structure.Edge;
41 import org.apache.tinkerpop.gremlin.structure.Element;
42 import org.apache.tinkerpop.gremlin.structure.Vertex;
43 import org.onap.aai.db.props.AAIProperties;
44 import org.onap.aai.introspection.Loader;
45 import org.onap.aai.logging.StopWatch;
46
47 /*
48  * This class needs some big explanation despite its compact size.
49  * This controls all the queries performed by the CRUD API in A&AI.
50  * findParents, findChildren, and findDeletable require special attention
51  *   These methods use 'repeat'. You cannot use 'emit' with repeat currently
52  *   as it is extremely buggy as of tinkerpop-3.0.1-incubating. The way around
53  *   it (for now) is to sideEffect all the vertices we traverse into an ArrayList.
54  *
55  */
56 public class GraphTraversalQueryEngine extends QueryEngine {
57
58         /**
59          * Instantiates a new graph traversal query engine.
60          *
61          * @param graphEngine the graph engine
62          */
63         public GraphTraversalQueryEngine(GraphTraversalSource g) {
64                 super(g);
65         }
66
67         /**
68          * {@inheritDoc}
69          */
70         @Override
71         public List<Vertex> findParents(Vertex start) {
72                 try {
73                         StopWatch.conditionalStart();
74
75                         @SuppressWarnings("unchecked")
76                         final GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).emit(v -> true).repeat(__.union(__.inE().has(CONTAINS.toString(), OUT.toString()).outV(), __.outE().has(CONTAINS.toString(), IN.toString()).inV()));
77                         return pipe.toList();
78                 }
79                 finally {
80                         dbTimeMsecs += StopWatch.stopIfStarted();
81                 }
82         }
83
84     /**
85      * {@inheritDoc}
86      */
87     @Override
88     public List<Vertex> findParents(String[] uris) {
89         try {
90             StopWatch.conditionalStart();
91             final GraphTraversal<Vertex, Vertex> pipe = this.g.V()
92                 .has(AAIProperties.AAI_URI, P.within(uris))
93                 .order().by(AAIProperties.AAI_URI, Order.decr);
94             return pipe.toList();
95         }
96         finally {
97             dbTimeMsecs += StopWatch.stopIfStarted();
98         }
99     }
100
101         /**
102          * {@inheritDoc}
103          */
104         @Override
105         public List<Vertex> findAllChildren(Vertex start) {
106
107                 @SuppressWarnings("unchecked")
108                 GraphTraversal<Vertex, Vertex> pipe =  this.g
109                                 .V(start).emit(v -> true).repeat(__.union(__.outE().has(CONTAINS.toString(), OUT.toString()).inV(), __.inE().has(CONTAINS.toString(), IN.toString()).outV()));
110
111
112                 return pipe.toList();
113
114         }
115
116         /**
117          * {@inheritDoc}
118          */
119         @Override
120         public List<Vertex> findChildrenOfType(Vertex start, String type) {
121                 @SuppressWarnings("unchecked")
122                 GraphTraversal<Vertex, Vertex> pipe =  this.g.V(start).union(
123                                         __.outE().has(CONTAINS.toString(), OUT.toString()).inV(),
124                                         __.inE().has(CONTAINS.toString(), IN.toString()).outV()
125                                 ).has(AAIProperties.NODE_TYPE, type).dedup();
126
127                 return pipe.toList();
128         }
129
130         /**
131          * {@inheritDoc}
132          */
133         @Override
134         public List<Vertex> findChildren(Vertex start) {
135                 @SuppressWarnings("unchecked")
136                 GraphTraversal<Vertex, Vertex> pipe =  this.g.V(start).union(
137                                         __.outE().has(CONTAINS.toString(), OUT.toString()),
138                                         __.inE().has(CONTAINS.toString(), IN.toString())
139                                 ).otherV().dedup();
140
141                 return pipe.toList();
142         }
143
144         /**
145          * {@inheritDoc}
146          */
147         @Override
148         public List<Vertex> findDeletable(Vertex start) {
149                 @SuppressWarnings("unchecked")
150                 GraphTraversal<Vertex, Vertex> pipe = this.g
151                                 .V(start).emit(v -> true).repeat(
152                                         __.union(
153                                                 __.outE().has(DELETE_OTHER_V.toString(), OUT.toString()).inV(),
154                                                 __.inE().has(DELETE_OTHER_V.toString(), IN.toString()).outV()
155                                         )
156                                 ).dedup();
157
158                 return pipe.toList();
159         }
160
161         /**
162          * {@inheritDoc}
163          */
164         @Override
165         public List<Vertex> findRelatedVertices(Vertex start, Direction direction, String label, String nodeType) {
166                 GraphTraversal<Vertex, Vertex> pipe = this.g.V(start);
167                 switch (direction) {
168                         case OUT:
169                                 pipe.out(label);
170                                 break;
171                         case IN:
172                                 pipe.in(label);
173                                 break;
174                         case BOTH:
175                                 pipe.both(label);
176                                 break;
177                          default:
178                                 break;
179                 }
180
181                 pipe.has(AAIProperties.NODE_TYPE, nodeType).dedup();
182                 return pipe.toList();
183         }
184
185         @Override
186         public Tree<Element> findSubGraph(Vertex start, int iterations, boolean nodeOnly) {
187                 final GraphTraversal<Vertex, ?> t = this.g.V(start).emit(v -> true).times(iterations).repeat(
188                                 __.union(
189                                         __.outE().has(CONTAINS.toString(), OUT.toString()).inV(),
190                                         __.inE().has(CONTAINS.toString(), IN.toString()).outV())
191                                 );
192
193                 if (!nodeOnly) {
194                         t.union(
195                                         __.identity(),
196                                         __.bothE().has(CONTAINS.toString(), NONE.toString()).dedup().otherV()
197                         );
198                 }
199                 t.tree();
200                 if (t.hasNext()) {
201                         return (Tree)t.next();
202                 } else {
203                         return new Tree();
204                 }
205         }
206
207         @Override
208         public List<Edge> findEdgesForVersion(Vertex start, Loader loader) {
209             // From the given start vertex find both the
210                 // out edges that has property CONTAINS set to NONE
211                 // whose in vertexes has an object that is declared in the oxm
212                 // And do the same thing vice versa to get a list of edges
213                 // Then check that the edge should not have the property private set to true
214                 // and remove the duplicates and return the list of edges
215                 final Set<String> objects = loader.getAllObjects().keySet();
216                 GraphTraversal<Vertex, Edge> pipeline = this.g
217                         .V(start)
218                         .union(
219                                 __.inE().has(CONTAINS.toString(), NONE.toString()).where(__.outV().has(AAIProperties.NODE_TYPE, P.within(objects))),
220                                 __.outE().has(CONTAINS.toString(), NONE.toString()).where(__.inV().has(AAIProperties.NODE_TYPE, P.within(objects)))
221                         )
222                         .not(
223                                 __.has("private", true)
224                         )
225                         .dedup();
226
227                 return pipeline.toList();
228         }
229
230
231         @Override
232         public List<Vertex> findCousinVertices(Vertex start, String... labels) {
233             // Start at the given vertex
234                 // Do a union to copy the start vertex to be run against all
235                 // so for the start vertex it gets all of in edges that contains other v set to none
236                 // and also all the other out edges with contains other v set to none
237                 // And filter the edges based on the property private not set
238         // so that means it will be a regular edge
239                 // and find the other end of the vertex so if setup like this:
240                 // v2 -> e1 -> v3
241                 // It will return v3
242                 GraphTraversal<Vertex, Vertex> pipeline = this.g
243             .V(start)
244             .union(
245                 __.inE(labels).has(CONTAINS.toString(), NONE.toString()),
246                 __.outE(labels).has(CONTAINS.toString(), NONE.toString())
247             )
248                         .not(
249                                 __.has(PRIVATE.toString(), true)
250                         )
251                         .otherV()
252                         .dedup();
253
254                 return pipeline.toList();
255         }
256
257         public double getDBTimeMsecs() {
258                 return (dbTimeMsecs);
259         }
260 }
261