From dd9283594fc433b123f5aad3c2690db3e6ca2dc2 Mon Sep 17 00:00:00 2001 From: "tom4tomato@gmail.com" Date: Tue, 31 Dec 2019 15:37:27 +0200 Subject: [PATCH] add ontology support for primitive (properties) search types explicit declaration add cursor pattern printing for AssignmentResults for all cursors available Add runCypher with cursor type as parameter --- .../fuse/dispatcher/cursor/CursorFactory.java | 2 +- .../fuse/dispatcher/driver/QueryDriver.java | 2 + .../dispatcher/driver/QueryDriverBase.java | 31 +- .../Dragons/ontology/OntologyStructure.json | 50 +++ .../dragons/driver/ExtensionQueryDriver.java | 1 + .../DragonsExtensionQueryController.java | 5 + .../dispatcher/driver/MockDriver.java | 5 + .../Knowledge/ontology/OntologyStructure.json | 49 +++ ...nowledgeGraphHierarchyTraversalCursor.java | 9 +- .../KnowledgeExtensionQueryController.java | 5 + .../fuse/core/driver/StandardQueryDriver.java | 3 + .../GraphHierarchyTraversalCursor.java | 6 + .../cursor/discrete/GraphTraversalCursor.java | 4 + .../NewGraphHierarchyTraversalCursor.java | 6 +- .../cursor/discrete/PathsTraversalCursor.java | 1 + .../yangdb/fuse/model/ontology/Ontology.java | 1 + .../yangdb/fuse/model/ontology/Property.java | 65 +++- .../com/yangdb/fuse/model/OntologyTest.java | 190 ++---------- .../Dragons_Ontology_search_type.json | 293 ++++++++++++++++++ .../QueryControllerRegistrar.java | 5 +- .../services/controllers/QueryController.java | 13 + .../controllers/StandardQueryController.java | 8 + .../logging/LoggingQueryController.java | 19 ++ .../public/assets/swagger/swagger.json | 6 +- 24 files changed, 594 insertions(+), 185 deletions(-) create mode 100644 fuse-domain/fuse-domain-dragons/fuse-domain-dragons-assembly/resources/assembly/Dragons/ontology/OntologyStructure.json create mode 100644 fuse-domain/fuse-domain-knowledge/fuse-domain-knowledge-assembly/resources/assembly/Knowledge/ontology/OntologyStructure.json create mode 100644 fuse-model/src/test/resources/OntologyJsons/Dragons_Ontology_search_type.json diff --git a/fuse-core/src/main/java/com/yangdb/fuse/dispatcher/cursor/CursorFactory.java b/fuse-core/src/main/java/com/yangdb/fuse/dispatcher/cursor/CursorFactory.java index c02833ca0..fb30b6dff 100644 --- a/fuse-core/src/main/java/com/yangdb/fuse/dispatcher/cursor/CursorFactory.java +++ b/fuse-core/src/main/java/com/yangdb/fuse/dispatcher/cursor/CursorFactory.java @@ -75,7 +75,7 @@ public CreateCursorRequest getCursorRequest() { * @return */ static Class resolve(String cursorTypeName) { - Reflections reflections = new Reflections("com.yangdb.fuse"); + Reflections reflections = new Reflections(CreateCursorRequest.class.getPackage().getName()); Set> allClasses = reflections.getSubTypesOf(CreateCursorRequest.class); Optional> cursorType = allClasses.stream().filter(clazz -> { try { diff --git a/fuse-core/src/main/java/com/yangdb/fuse/dispatcher/driver/QueryDriver.java b/fuse-core/src/main/java/com/yangdb/fuse/dispatcher/driver/QueryDriver.java index 99c898650..fde2d1eca 100644 --- a/fuse-core/src/main/java/com/yangdb/fuse/dispatcher/driver/QueryDriver.java +++ b/fuse-core/src/main/java/com/yangdb/fuse/dispatcher/driver/QueryDriver.java @@ -57,6 +57,8 @@ public interface QueryDriver { Optional run(String cypher, String ontology); + Optional run(String cypher, String ontology, int pageSize, String cursorType); + Optional getNextPageData(String queryId, Optional cursorId,int pageSize, boolean deleteCurrentPage); Optional getInfo(); diff --git a/fuse-core/src/main/java/com/yangdb/fuse/dispatcher/driver/QueryDriverBase.java b/fuse-core/src/main/java/com/yangdb/fuse/dispatcher/driver/QueryDriverBase.java index 0af78c6e4..dd31b1442 100644 --- a/fuse-core/src/main/java/com/yangdb/fuse/dispatcher/driver/QueryDriverBase.java +++ b/fuse-core/src/main/java/com/yangdb/fuse/dispatcher/driver/QueryDriverBase.java @@ -54,15 +54,13 @@ import javaslang.control.Option; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; -import java.lang.reflect.InvocationTargetException; import java.util.*; import java.util.stream.Collectors; import static com.yangdb.fuse.dispatcher.cursor.CursorFactory.request; -import static com.yangdb.fuse.dispatcher.cursor.CursorFactory.resolve; import static com.yangdb.fuse.model.Utils.getOrCreateId; import static com.yangdb.fuse.model.asgQuery.AsgCompositeQuery.hasInnerQuery; -import static com.yangdb.fuse.model.transport.CreateQueryRequestMetadata.QueryType.*; +import static com.yangdb.fuse.model.transport.CreateQueryRequestMetadata.QueryType.parameterized; import static java.util.Collections.EMPTY_LIST; /** @@ -120,10 +118,10 @@ public Optional run(Query query, int pageSize, String cursorType) { } @Override - public Optional run(String cypher, String ontology) { + public Optional run(String cypher, String ontology, int pageSize, String cursorType) { String id = UUID.randomUUID().toString(); try { - CreateJsonQueryRequest queryRequest = createJsonQueryRequest(cypher, ontology, id); + CreateJsonQueryRequest queryRequest = new CreateJsonQueryRequest(id, id, cypher, ontology, request(cursorType,new CreatePageRequest(pageSize))); Optional resourceInfo = create(queryRequest); if (!resourceInfo.isPresent()) return Optional.empty(); @@ -132,14 +130,33 @@ public Optional run(String cypher, String ontology) { return Optional.of(resourceInfo.get().getError()); return Optional.of(resourceInfo.get()); + } catch (Throwable e) { + return Optional.of(new QueryResourceInfo().error( + new FuseError(Query.class.getSimpleName(), "failed building the cursor request " + cursorType))); + } finally { //remove stateless query // delete(id); } } - protected CreateJsonQueryRequest createJsonQueryRequest(String cypher, String ontology, String id) { - return new CreateJsonQueryRequest(id, id, cypher, ontology, new LogicalGraphCursorRequest(new CreatePageRequest())); + @Override + public Optional run(String cypher, String ontology) { + String id = UUID.randomUUID().toString(); + try { + CreateJsonQueryRequest queryRequest = new CreateJsonQueryRequest(id, id, cypher, ontology, new LogicalGraphCursorRequest(new CreatePageRequest())); + Optional resourceInfo = create(queryRequest); + if (!resourceInfo.isPresent()) + return Optional.empty(); + + if (resourceInfo.get().getError() != null) + return Optional.of(resourceInfo.get().getError()); + + return Optional.of(resourceInfo.get()); + } finally { + //remove stateless query +// delete(id); + } } diff --git a/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-assembly/resources/assembly/Dragons/ontology/OntologyStructure.json b/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-assembly/resources/assembly/Dragons/ontology/OntologyStructure.json new file mode 100644 index 000000000..cc1a34958 --- /dev/null +++ b/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-assembly/resources/assembly/Dragons/ontology/OntologyStructure.json @@ -0,0 +1,50 @@ +{ + "structure": [ + { + "type":"quantifier", + "typeOptionals": [ + { "op":"some"}, + { "op":"all"} + ] + }, + { + "type":"entity", + "typeOptionals": [ + { "op":"concrete"}, + { "op":"typed"}, + { "op":"untyped"} + ] + }, + { + "type":"relation", + "typeOptionals": [ + { "op":"typed"}, + { "op":"untyped"} + ] + } + ], + "primitives": ["string","int","date","text","float","array","geo_point","datetime"], + "operators": { + "empty": ["string","int","date","text","float","array","geo_point","datetime"], + "notEmpty": ["string","int","date","text","float","array","geo_point","datetime"], + + "eq": ["string","int","date","text","float","array","geo_point","datetime"], + "ne": ["string","int","date","text","float","array","geo_point","datetime"], + "gt": ["string","int","date","text","float","datetime"], + "ge": ["string","int","date","text","float","datetime"], + "lt": ["string","int","date","text","float","datetime"], + "le": ["string","int","date","text","float","datetime"], + + "contains": ["string","text"], + "like": ["string","text"], + "likeAny": ["string","text"], + + "inSet": ["string","int","date","text","float","array","geo_point","datetime"], + "notInSet": ["string","int","date","text","float","array","geo_point","datetime"], + + "inRange": ["datetime","int","float","date"], + "notInRange": ["datetime","int","float","date"] + } + + + } \ No newline at end of file diff --git a/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-ext/src/main/java/com/yangdb/dragons/driver/ExtensionQueryDriver.java b/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-ext/src/main/java/com/yangdb/dragons/driver/ExtensionQueryDriver.java index d914874e7..385b67764 100644 --- a/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-ext/src/main/java/com/yangdb/dragons/driver/ExtensionQueryDriver.java +++ b/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-ext/src/main/java/com/yangdb/dragons/driver/ExtensionQueryDriver.java @@ -118,4 +118,5 @@ protected CreateQueryRequest createQueryRequest(Query query, String id) { //endregion private QueryTransformer transformer; + } diff --git a/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-ext/src/main/java/com/yangdb/dragons/services/DragonsExtensionQueryController.java b/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-ext/src/main/java/com/yangdb/dragons/services/DragonsExtensionQueryController.java index 585935060..78098a292 100644 --- a/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-ext/src/main/java/com/yangdb/dragons/services/DragonsExtensionQueryController.java +++ b/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-ext/src/main/java/com/yangdb/dragons/services/DragonsExtensionQueryController.java @@ -70,6 +70,11 @@ public ContentResponse run(Query query, int pageSize, String cursorType) return controller.run(query,pageSize,cursorType); } + @Override + public ContentResponse run(String cypher, String ontology, int pageSize, String cursorType) { + return controller.run(cypher, ontology, pageSize, cursorType); + } + @Override public ContentResponse validate(Query query) { return controller.validate(query); diff --git a/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-test/src/test/java/com/yangdb/fuse/services/dispatcher/driver/MockDriver.java b/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-test/src/test/java/com/yangdb/fuse/services/dispatcher/driver/MockDriver.java index be555975b..9cd911759 100644 --- a/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-test/src/test/java/com/yangdb/fuse/services/dispatcher/driver/MockDriver.java +++ b/fuse-domain/fuse-domain-dragons/fuse-domain-dragons-test/src/test/java/com/yangdb/fuse/services/dispatcher/driver/MockDriver.java @@ -63,6 +63,11 @@ public Optional run(String cypher, String ontology) { return Optional.empty(); } + @Override + public Optional run(String cypher, String ontology, int pageSize, String cursorType) { + return Optional.empty(); + } + @Override public Optional traversal(com.yangdb.fuse.model.query.Query query) { return Optional.empty(); diff --git a/fuse-domain/fuse-domain-knowledge/fuse-domain-knowledge-assembly/resources/assembly/Knowledge/ontology/OntologyStructure.json b/fuse-domain/fuse-domain-knowledge/fuse-domain-knowledge-assembly/resources/assembly/Knowledge/ontology/OntologyStructure.json new file mode 100644 index 000000000..9750ab8b0 --- /dev/null +++ b/fuse-domain/fuse-domain-knowledge/fuse-domain-knowledge-assembly/resources/assembly/Knowledge/ontology/OntologyStructure.json @@ -0,0 +1,49 @@ +{ + "structure": [ + { + "type":"quantifier", + "typeOptionals": [ + { "op":"some"}, + { "op":"all"} + ] + }, + { + "type":"entity", + "typeOptionals": [ + { "op":"concrete"}, + { "op":"typed"}, + { "op":"untyped"} + ] + }, + { + "type":"relation", + "typeOptionals": [ + { "op":"typed"}, + { "op":"untyped"} + ] + } + ], + "primitives": ["string","int","date","text","float","array","geo_point","datetime"], + "operators": { + "empty": ["string","int","date","text","float","array","geo_point","datetime"], + "notEmpty": ["string","int","date","text","float","array","geo_point","datetime"], + + "eq": ["string","int","date","text","float","array","geo_point","datetime"], + "ne": ["string","int","date","text","float","array","geo_point","datetime"], + "gt": ["string","int","date","text","float","datetime"], + "ge": ["string","int","date","text","float","datetime"], + "lt": ["string","int","date","text","float","datetime"], + "le": ["string","int","date","text","float","datetime"], + + "contains": ["string","text"], + "like": ["string","text"], + "likeAny": ["string","text"], + + "inSet": ["string","int","date","text","float","array","geo_point","datetime"], + "notInSet": ["string","int","date","text","float","array","geo_point","datetime"], + + "inRange": ["datetime","int","float","date"], + "notInRange": ["datetime","int","float","date"] + } + + } \ No newline at end of file diff --git a/fuse-domain/fuse-domain-knowledge/fuse-domain-knowledge-ext/src/main/java/com/yangdb/fuse/assembly/knowledge/cursor/KnowledgeGraphHierarchyTraversalCursor.java b/fuse-domain/fuse-domain-knowledge/fuse-domain-knowledge-ext/src/main/java/com/yangdb/fuse/assembly/knowledge/cursor/KnowledgeGraphHierarchyTraversalCursor.java index 9b475e1bc..fc1bce1ba 100644 --- a/fuse-domain/fuse-domain-knowledge/fuse-domain-knowledge-ext/src/main/java/com/yangdb/fuse/assembly/knowledge/cursor/KnowledgeGraphHierarchyTraversalCursor.java +++ b/fuse-domain/fuse-domain-knowledge/fuse-domain-knowledge-ext/src/main/java/com/yangdb/fuse/assembly/knowledge/cursor/KnowledgeGraphHierarchyTraversalCursor.java @@ -29,6 +29,7 @@ import com.yangdb.fuse.model.execution.plan.entity.EntityOp; import com.yangdb.fuse.model.execution.plan.relation.RelationOp; import com.yangdb.fuse.model.ontology.Ontology; +import com.yangdb.fuse.model.query.Query; import com.yangdb.fuse.model.query.Rel; import com.yangdb.fuse.model.query.entity.EEntityBase; import com.yangdb.fuse.model.results.*; @@ -152,9 +153,6 @@ public QueryResultBase getNextResults(int numResults) { } Assignment.Builder builder = Assignment.Builder.instance(); - - - for(Map.Entry>> idVertexEtagsEntry : idVertexEtagsMap.entrySet()) { Vertex mergedVertex = mergeVertices(Stream.ofAll(idVertexEtagsEntry.getValue().keySet()).toJavaList()); if(this.idsScore.containsKey(mergedVertex.id())) { @@ -178,7 +176,10 @@ public QueryResultBase getNextResults(int numResults) { Assignment assignment = compose(builder); - return AssignmentsQueryResult.Builder.instance().withAssignment(assignment).build(); + final Query pattern = getContext().getQueryResource().getQuery(); + return AssignmentsQueryResult.Builder.instance() + .withPattern(pattern) + .withAssignment(assignment).build(); } protected Assignment compose(Assignment.Builder builder) { diff --git a/fuse-domain/fuse-domain-knowledge/fuse-domain-knowledge-ext/src/main/java/com/yangdb/fuse/services/KnowledgeExtensionQueryController.java b/fuse-domain/fuse-domain-knowledge/fuse-domain-knowledge-ext/src/main/java/com/yangdb/fuse/services/KnowledgeExtensionQueryController.java index f58ea6798..795b3bda0 100644 --- a/fuse-domain/fuse-domain-knowledge/fuse-domain-knowledge-ext/src/main/java/com/yangdb/fuse/services/KnowledgeExtensionQueryController.java +++ b/fuse-domain/fuse-domain-knowledge/fuse-domain-knowledge-ext/src/main/java/com/yangdb/fuse/services/KnowledgeExtensionQueryController.java @@ -80,6 +80,11 @@ public ContentResponse run(String cypher, String ontology) { return controller.run(cypher,ontology); } + @Override + public ContentResponse run(String cypher, String ontology, int pageSize, String cursorType) { + return controller.run(cypher,ontology,pageSize,cursorType); + } + @Override public ContentResponse createAndFetch(CreateQueryRequest request) { return controller.createAndFetch(request); diff --git a/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/core/driver/StandardQueryDriver.java b/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/core/driver/StandardQueryDriver.java index 2f91a4857..ba8de44b1 100644 --- a/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/core/driver/StandardQueryDriver.java +++ b/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/core/driver/StandardQueryDriver.java @@ -42,6 +42,8 @@ import com.yangdb.fuse.model.transport.CreateQueryRequestMetadata; import com.yangdb.fuse.model.validation.ValidationResult; +import java.util.Optional; + import static com.yangdb.fuse.model.transport.CreateQueryRequestMetadata.QueryType.concrete; /** @@ -99,5 +101,6 @@ protected AsgQuery rewrite(AsgQuery asgQuery) { private PlanSearcher planSearcher; + //endregion } diff --git a/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/GraphHierarchyTraversalCursor.java b/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/GraphHierarchyTraversalCursor.java index 653a0dcbc..be43e5fd7 100644 --- a/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/GraphHierarchyTraversalCursor.java +++ b/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/GraphHierarchyTraversalCursor.java @@ -23,6 +23,7 @@ import com.yangdb.fuse.dispatcher.cursor.Cursor; import com.yangdb.fuse.dispatcher.cursor.CursorFactory; import com.yangdb.fuse.executor.cursor.TraversalCursorContext; +import com.yangdb.fuse.model.query.Query; import com.yangdb.fuse.model.results.Assignment; import com.yangdb.fuse.model.results.AssignmentsQueryResult; import com.yangdb.fuse.model.results.Entity; @@ -33,6 +34,8 @@ import java.util.*; +import static com.yangdb.fuse.model.results.AssignmentsQueryResult.Builder.instance; + /** * Created by roman.margolis on 11/03/2018. */ @@ -71,6 +74,9 @@ public GraphHierarchyTraversalCursor(Cursor cursor, Iter //region Cursor Implementation @Override public AssignmentsQueryResult getNextResults(int numResults) { + final Query pattern = getContext().getQueryResource().getQuery(); + this.fullGraph.setPattern(pattern); + AssignmentsQueryResult newResult = (AssignmentsQueryResult) this.cursor.getNextResults(numResults); while(newResult.getAssignments().size() > 0) { consolidateFullGraph(newResult); diff --git a/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/GraphTraversalCursor.java b/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/GraphTraversalCursor.java index 013bc1136..14b121b02 100644 --- a/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/GraphTraversalCursor.java +++ b/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/GraphTraversalCursor.java @@ -24,6 +24,7 @@ import com.yangdb.fuse.dispatcher.cursor.CursorFactory; import com.yangdb.fuse.executor.cursor.TraversalCursorContext; import com.yangdb.fuse.model.asgQuery.AsgQuery; +import com.yangdb.fuse.model.query.Query; import com.yangdb.fuse.model.query.properties.CalculatedEProp; import com.yangdb.fuse.model.query.properties.projection.CalculatedFieldProjection; import com.yangdb.fuse.model.results.*; @@ -69,6 +70,9 @@ public GraphTraversalCursor(Cursor cursor) { //region Cursor Implementation @Override public AssignmentsQueryResult getNextResults(int numResults) { + final Query pattern = getContext().getQueryResource().getQuery(); + this.fullGraph.setPattern(pattern); + AssignmentsQueryResult newResult = (AssignmentsQueryResult) this.cursor.getNextResults(numResults); consolidateFullGraph(newResult); diff --git a/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/NewGraphHierarchyTraversalCursor.java b/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/NewGraphHierarchyTraversalCursor.java index 5c7013e2d..d4a716c03 100644 --- a/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/NewGraphHierarchyTraversalCursor.java +++ b/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/NewGraphHierarchyTraversalCursor.java @@ -29,6 +29,7 @@ import com.yangdb.fuse.model.execution.plan.entity.EntityOp; import com.yangdb.fuse.model.execution.plan.relation.RelationOp; import com.yangdb.fuse.model.ontology.Ontology; +import com.yangdb.fuse.model.query.Query; import com.yangdb.fuse.model.query.Rel; import com.yangdb.fuse.model.query.entity.EEntityBase; import com.yangdb.fuse.model.results.*; @@ -151,7 +152,10 @@ public QueryResultBase getNextResults(int numResults) { relTuple._3())); } - return AssignmentsQueryResult.Builder.instance().withAssignment(builder.build()).build(); + final Query pattern = getContext().getQueryResource().getQuery(); + return AssignmentsQueryResult.Builder.instance() + .withPattern(pattern) + .withAssignment(builder.build()).build(); } //endregion diff --git a/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/PathsTraversalCursor.java b/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/PathsTraversalCursor.java index 4eb5b7d33..9f56a9002 100644 --- a/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/PathsTraversalCursor.java +++ b/fuse-dv/fuse-dv-core/src/main/java/com/yangdb/fuse/executor/cursor/discrete/PathsTraversalCursor.java @@ -128,6 +128,7 @@ protected AssignmentsQueryResult toQuery(int numResults) { return builder.build(); } + protected Assignment toAssignment(Path path) { Assignment.Builder builder = Assignment.Builder.instance(); diff --git a/fuse-model/src/main/java/com/yangdb/fuse/model/ontology/Ontology.java b/fuse-model/src/main/java/com/yangdb/fuse/model/ontology/Ontology.java index 0d55147a1..c610070b5 100644 --- a/fuse-model/src/main/java/com/yangdb/fuse/model/ontology/Ontology.java +++ b/fuse-model/src/main/java/com/yangdb/fuse/model/ontology/Ontology.java @@ -71,6 +71,7 @@ public Ontology() { primitiveTypes.add(new PrimitiveType("int", Long.class)); primitiveTypes.add(new PrimitiveType("string", String.class)); + primitiveTypes.add(new PrimitiveType("text", String.class)); primitiveTypes.add(new PrimitiveType("float", Double.class)); primitiveTypes.add(new PrimitiveType("date", Date.class)); primitiveTypes.add(new PrimitiveType("datetime", Date.class)); diff --git a/fuse-model/src/main/java/com/yangdb/fuse/model/ontology/Property.java b/fuse-model/src/main/java/com/yangdb/fuse/model/ontology/Property.java index 59443b1b8..16ee4dc3c 100644 --- a/fuse-model/src/main/java/com/yangdb/fuse/model/ontology/Property.java +++ b/fuse-model/src/main/java/com/yangdb/fuse/model/ontology/Property.java @@ -9,9 +9,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -33,9 +33,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -44,12 +44,20 @@ * */ +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonValue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; /** * Created by benishue on 22-Feb-17. */ @JsonInclude(JsonInclude.Include.NON_EMPTY) +@JsonIgnoreProperties(ignoreUnknown = true) public class Property { //region Constructors public Property() { @@ -60,6 +68,13 @@ public Property(String name, String pType, String type) { this.name = name; this.type = type; } + + public Property(String name, String pType, String type, SearchType... searchType) { + this.pType = pType; + this.name = name; + this.type = type; + this.searchType = Arrays.asList(searchType); + } //endregion //region Properties @@ -83,15 +98,23 @@ public String getType() { return type; } + public void setSearchType(List searchType) { + this.searchType = searchType; + } + public void setType(String type) { this.type = type; } + + public List getSearchType() { + return searchType; + } + //endregion //region Override Methods @Override - public String toString() - { + public String toString() { return String.format("Property [pType = %s, name = %s, type = %s]", this.pType, this.name, this.type); } @@ -119,10 +142,12 @@ public int hashCode() { private String pType; private String name; private String type; + private List searchType = Collections.emptyList(); //endregion //region Builder public static final class Builder { + private List searchTypes = new ArrayList<>(); private String pType; private String name; private String type; @@ -144,12 +169,17 @@ public Builder withName(String name) { return this; } + public Builder withSearchType(SearchType type) { + this.searchTypes.add(type); + return this; + } + public Builder withType(String type) { this.type = type; return this; } - public Property build(String pType, String name, String type ) { + public Property build(String pType, String name, String type) { Property property = new Property(); property.setName(name); property.setType(type); @@ -162,11 +192,32 @@ public Property build() { property.setName(name); property.setType(type); property.pType = this.pType; + property.searchType = Collections.unmodifiableList(this.searchTypes); return property; } } //endregion + public enum SearchType { + NGRAM("ngram"), + PREFIX("prefix"), + SUFFIX("suffix"), + FULL("full"), + EXACT("exact"), + RANGE("range"), + NONE("none"); + + private String name; + + SearchType(String name) { + this.name = name; + } + + @JsonValue + public String getName() { + return name; + } + } } diff --git a/fuse-model/src/test/java/com/yangdb/fuse/model/OntologyTest.java b/fuse-model/src/test/java/com/yangdb/fuse/model/OntologyTest.java index f1fa9d5bc..d17286026 100644 --- a/fuse-model/src/test/java/com/yangdb/fuse/model/OntologyTest.java +++ b/fuse-model/src/test/java/com/yangdb/fuse/model/OntologyTest.java @@ -1,11 +1,12 @@ package com.yangdb.fuse.model; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.yangdb.fuse.model.ontology.*; +import com.yangdb.fuse.model.ontology.Ontology; import org.apache.commons.io.IOUtils; -import org.json.JSONException; -import org.junit.*; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; import org.skyscreamer.jsonassert.JSONAssert; import java.io.IOException; @@ -19,173 +20,40 @@ public class OntologyTest { private static Ontology ontologyShortObj = new Ontology(); private static Ontology ontologyWithCompositeObj = new Ontology(); - public static void main(String[] args) throws JsonProcessingException { - Ontology ontology = OntologyTestUtils.createDragonsOntologyLong(); - String json = new ObjectMapper().writeValueAsString(ontology); - System.out.println(json); - } @Test - public void a() { - int numIterations = 50000; - - for(int i = 0; i < numIterations ; i++) { - int a = Integer.parseInt(Integer.toString(i)); - } - - int a = 0; - int b = 0; - - long start = System.currentTimeMillis(); - for(int i = 0; i < numIterations ; i++) { - b += 1; - } - long elapsed = System.currentTimeMillis() - start; - System.out.println("empty loop elapsed: " + elapsed); - - start = System.currentTimeMillis(); - for(int i = 0; i < numIterations ; i++) { - a = Integer.parseInt(Integer.toString(i)); - } - elapsed = System.currentTimeMillis() - start; - - System.out.println("parsing loop elapsed: " + elapsed); -// System.out.println(a); -// System.out.println(b); + public void testShortOntologyDeSerialization() throws Exception { + String ontologyExpectedJson = readJsonToString("Dragons_Ontology_Short.json"); + Ontology resultObj = new ObjectMapper().readValue(ontologyExpectedJson, Ontology.class); + Assert.assertNotNull(resultObj); + String ontologyActualJSON = mapper.writeValueAsString(resultObj); + JSONAssert.assertEquals(ontologyExpectedJson, ontologyActualJSON, false); } @Test - @Ignore - public void testShortOntologySerialization() throws IOException, JSONException { - String ontologyActualJSON = mapper.writeValueAsString(ontologyShortObj); - String ontologyExpectedJSONString = "{\n" + - "\t\"ont\": \"Dragons\",\n" + - "\t\"enumeratedTypes\": [{\n" + - "\t\t\"eType\": \"TYPE_Gender\",\n" + - "\t\t\"values\": [{\n" + - "\t\t\t\"val\": 1,\n" + - "\t\t\t\"name\": \"Female\"\n" + - "\t\t},\n" + - "\t\t{\n" + - "\t\t\t\"val\": 2,\n" + - "\t\t\t\"name\": \"Male\"\n" + - "\t\t},\n" + - "\t\t{\n" + - "\t\t\t\"val\": 3,\n" + - "\t\t\t\"name\": \"Other\"\n" + - "\t\t}]\n" + - "\t}],\n" + - "\t\"properties\": [{\n" + - "\t\t\"pType\": 1,\n" + - "\t\t\"name\": \"firstName\",\n" + - "\t\t\"type\": \"string\"\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"pType\": 2,\n" + - "\t\t\"name\": \"lastName\",\n" + - "\t\t\"type\": \"string\"\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"pType\": 3,\n" + - "\t\t\"name\": \"gender\",\n" + - "\t\t\"type\": \"TYPE_Gender\"\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"pType\": 4,\n" + - "\t\t\"name\": \"birthDate\",\n" + - "\t\t\"type\": \"date\"\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"pType\": 5,\n" + - "\t\t\"name\": \"deathDate\",\n" + - "\t\t\"type\": \"date\"\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"pType\": 6,\n" + - "\t\t\"name\": \"height\",\n" + - "\t\t\"type\": \"int\",\n" + - "\t\t\"units\": \"cm\"\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"pType\": 7,\n" + - "\t\t\"name\": \"name\",\n" + - "\t\t\"type\": \"string\"\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"pType\": 8,\n" + - "\t\t\"name\": \"startDate\",\n" + - "\t\t\"type\": \"date\"\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"pType\": 9,\n" + - "\t\t\"name\": \"endDate\",\n" + - "\t\t\"type\": \"date\"\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"pType\": 2147483646,\n" + - "\t\t\"name\": \"type\",\n" + - "\t\t\"type\": \"string\"\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"pType\": 2147483647,\n" + - "\t\t\"name\": \"id\",\n" + - "\t\t\"type\": \"string\"\n" + - "\t}],\n" + - "\t\"entityTypes\": [{\n" + - "\t\t\"eType\": 1,\n" + - "\t\t\"name\": \"Person\",\n" + - "\t\t\"properties\": [1,\n" + - "\t\t2,\n" + - "\t\t3,\n" + - "\t\t4,\n" + - "\t\t5,\n" + - "\t\t6]\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"eType\": 2,\n" + - "\t\t\"name\": \"Dragon\",\n" + - "\t\t\"properties\": [7]\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"eType\": 4,\n" + - "\t\t\"name\": \"Guild\",\n" + - "\t\t\"properties\": [7]\n" + - "\t}],\n" + - "\t\"relationshipTypes\": [{\n" + - "\t\t\"rType\": 1,\n" + - "\t\t\"name\": \"own\",\n" + - "\t\t\"directional\": true,\n" + - "\t\t\"ePairs\": [{\n" + - "\t\t\t\"eTypeA\": 1,\n" + - "\t\t\t\"eTypeB\": 2\n" + - "\t\t}],\n" + - "\t\t\"properties\": [8,\n" + - "\t\t9]\n" + - "\t},\n" + - "\t{\n" + - "\t\t\"rType\": 2,\n" + - "\t\t\"name\": \"memberOf\",\n" + - "\t\t\"directional\": true,\n" + - "\t\t\"ePairs\": [{\n" + - "\t\t\t\"eTypeA\": 1,\n" + - "\t\t\t\"eTypeB\": 4\n" + - "\t\t}],\n" + - "\t\t\"properties\": [8,\n" + - "\t\t9]\n" + - "\t}]\n" + - "}"; -// System.out.println("ontologyExpectedJSONString:" + ontologyExpectedJSONString); -// System.out.println("ontologyActualJSON:" + ontologyActualJSON); - JSONAssert.assertEquals(ontologyExpectedJSONString, ontologyActualJSON, false); + public void testOntologyDeSerialization() throws Exception { + String ontologyExpectedJson = readJsonToString("Dragons_Ontology.json"); + Ontology resultObj = new ObjectMapper().readValue(ontologyExpectedJson, Ontology.class); + Assert.assertNotNull(resultObj); + Assert.assertEquals(resultObj.getEntityTypes().size(),5); + Assert.assertEquals(resultObj.getRelationshipTypes().size(),7); + Assert.assertEquals(resultObj.getProperties().size(),13); + Assert.assertEquals(resultObj.getPrimitiveTypes().size(),8); + Assert.assertEquals(resultObj.getEnumeratedTypes().size(),2); + Assert.assertEquals(resultObj.getProperties().stream().flatMap(p -> p.getSearchType().stream()).count(),0); } @Test - public void testShortOntologyDeSerialization() throws Exception { - String ontologyExpectedJson = readJsonToString("Dragons_Ontology_Short.json"); + public void testOntologyWithSearchTypeDeSerialization() throws Exception { + String ontologyExpectedJson = readJsonToString("Dragons_Ontology_search_type.json"); Ontology resultObj = new ObjectMapper().readValue(ontologyExpectedJson, Ontology.class); Assert.assertNotNull(resultObj); - String ontologyActualJSON = mapper.writeValueAsString(resultObj); - JSONAssert.assertEquals(ontologyExpectedJson, ontologyActualJSON, false); + Assert.assertEquals(resultObj.getEntityTypes().size(),5); + Assert.assertEquals(resultObj.getRelationshipTypes().size(),7); + Assert.assertEquals(resultObj.getProperties().size(),13); + Assert.assertEquals(resultObj.getPrimitiveTypes().size(),8); + Assert.assertEquals(resultObj.getEnumeratedTypes().size(),2); + Assert.assertEquals(resultObj.getProperties().stream().flatMap(p -> p.getSearchType().stream()).count(),9); } private String readJsonToString(String jsonFileName) throws Exception { diff --git a/fuse-model/src/test/resources/OntologyJsons/Dragons_Ontology_search_type.json b/fuse-model/src/test/resources/OntologyJsons/Dragons_Ontology_search_type.json new file mode 100644 index 000000000..77cf6d805 --- /dev/null +++ b/fuse-model/src/test/resources/OntologyJsons/Dragons_Ontology_search_type.json @@ -0,0 +1,293 @@ +{ + "ont": "Dragons", + "entityTypes": [ + { + "eType": "Person", + "name": "Person", + "metadata": [], + "properties": [ + "firstName", + "lastName", + "gender", + "birthDate", + "deathDate", + "height" + ] + }, + { + "eType": "Horse", + "name": "Horse", + "metadata": [], + "properties": [ + "name", + "gender" + ] + }, + { + "eType": "Dragon", + "name": "Dragon", + "metadata": [], + "properties": [ + "name", + "gender" + ] + }, + { + "eType": "Kingdom", + "name": "kingdom", + "metadata": [], + "properties": [ + "name" + ] + }, + { + "eType": "Guild", + "name": "Guild", + "metadata": [], + "properties": [ + "name" + ] + } + ], + "relationshipTypes": [ + { + "rType": "registered", + "name": "registered", + "directional": true, + "ePairs": [ + { + "eTypeA": "Guild", + "eTypeB": "Kingdom" + }, + { + "eTypeA": "Dragon", + "eTypeB": "Guild" + }, + { + "eTypeA": "Horse", + "eTypeB": "Guild" + } + ], + "metadata": [], + "properties": [ + "startDate", + "endDate" + ] + }, + { + "rType": "subject", + "name": "subject", + "directional": true, + "ePairs": [ + { + "eTypeA": "Person", + "eTypeB": "Kingdom" + } + ], + "metadata": [], + "properties": [ + "startDate", + "endDate" + ] + }, + { + "rType": "origin", + "name": "origin", + "directional": true, + "ePairs": [ + { + "eTypeA": "Dragon", + "eTypeB": "Kingdom" + } + ], + "metadata": [], + "properties": [ + ] + }, + { + "rType": "freeze", + "name": "freeze", + "directional": true, + "ePairs": [ + { + "eTypeA": "Dragon", + "eTypeB": "Dragon" + } + ], + "metadata": [], + "properties": [ + "startDate", + "endDate", + "temperature" + ] + }, + { + "rType": "fire", + "name": "fire", + "directional": true, + "ePairs": [ + { + "eTypeA": "Dragon", + "eTypeB": "Dragon" + } + ], + "metadata": [], + "properties": [ + "startDate", + "endDate", + "timestamp", + "temperature" + ] + }, + { + "rType": "memberOf", + "name": "memberOf", + "directional": true, + "ePairs": [ + { + "eTypeA": "Person", + "eTypeB": "Guild" + } + ], + "metadata": [], + "properties": [ + "startDate", + "endDate" + ] + }, + { + "rType": "own", + "name": "own", + "directional": true, + "ePairs": [ + { + "eTypeA": "Person", + "eTypeB": "Dragon" + }, + { + "eTypeA": "Person", + "eTypeB": "Horse" + } + ], + "metadata": [], + "properties": [ + "startDate", + "endDate" + ] + } + ], + "properties": [ + { + "pType": "firstName", + "name": "firstName", + "type": "string", + "searchType":["exact","full"] + }, + { + "pType": "lastName", + "name": "lastName", + "type": "string", + "searchType":["exact","full"] + }, + { + "pType": "gender", + "name": "gender", + "type": "TYPE_Gender", + "searchType":["exact"] + }, + { + "pType": "birthDate", + "name": "birthDate", + "type": "date", + "searchType":["range"] + }, + { + "pType": "deathDate", + "name": "deathDate", + "type": "date", + "searchType":["range"] + }, + { + "pType": "height", + "name": "height", + "type": "int", + "units": "cm" + }, + { + "pType": "name", + "name": "name", + "type": "string", + "searchType":["exact","full"] + }, + { + "pType": "startDate", + "name": "startDate", + "type": "date" + }, + { + "pType": "endDate", + "name": "endDate", + "type": "date" + }, + { + "pType": "timestamp", + "name": "timestamp", + "type": "long" + }, + { + "pType": "temperature", + "name": "temperature", + "type": "long" + }, + { + "pType": "id", + "name": "id", + "type": "string" + }, + { + "pType": "type", + "name": "type", + "type": "string" + } + ], + "enumeratedTypes": [ + { + "eType": "TYPE_Gender", + "values": [ + { + "val": 0, + "name": "MALE" + }, + { + "val": 1, + "name": "FEMALE" + }, + { + "val": 2, + "name": "OTHER" + } + ] + }, + { + "eType": "TYPE_Color", + "values": [ + { + "val": 0, + "name": "RED" + }, + { + "val": 1, + "name": "BLUE" + }, + { + "val": 2, + "name": "GREEN" + }, + { + "val": 3, + "name": "YELLOW" + } + ] + } + ] +} \ No newline at end of file diff --git a/fuse-service/src/main/java/com/yangdb/fuse/services/appRegistrars/QueryControllerRegistrar.java b/fuse-service/src/main/java/com/yangdb/fuse/services/appRegistrars/QueryControllerRegistrar.java index 37b960eb8..62c05a572 100644 --- a/fuse-service/src/main/java/com/yangdb/fuse/services/appRegistrars/QueryControllerRegistrar.java +++ b/fuse-service/src/main/java/com/yangdb/fuse/services/appRegistrars/QueryControllerRegistrar.java @@ -317,7 +317,10 @@ public static Result runCypher(Jooby app, final Request req, QueryController con String ontology = req.param("ontology").value(); req.set(ExecutionScope.class, new ExecutionScope(TIMEOUT)); - ContentResponse response = controller.run(query,ontology); + ContentResponse response = controller.run(query,ontology, + req.param("pageSize").isSet() ? req.param("pageSize").intValue() : PAGE_SIZE, + req.param("cursorType").isSet() ? req.param("cursorType").value() : LogicalGraphCursorRequest.CursorType + ); return Results.with(response, response.status()); } diff --git a/fuse-service/src/main/java/com/yangdb/fuse/services/controllers/QueryController.java b/fuse-service/src/main/java/com/yangdb/fuse/services/controllers/QueryController.java index 2388a678c..a62411517 100644 --- a/fuse-service/src/main/java/com/yangdb/fuse/services/controllers/QueryController.java +++ b/fuse-service/src/main/java/com/yangdb/fuse/services/controllers/QueryController.java @@ -83,6 +83,19 @@ public interface QueryController extends Controller { */ ContentResponse run(String cypher, String ontology); + + /** + * run a stateless cypher query and get immediate graph results (first page only) + * type may be volatile or persistent + * @param `query + * @param ontology + * @param pageSize + * @param cursorType + * @return + */ + ContentResponse run(String cypher, String ontology, int pageSize, String cursorType); + + /** * create a prepared statement, run against db and return results * type may be volatile or persistent diff --git a/fuse-service/src/main/java/com/yangdb/fuse/services/controllers/StandardQueryController.java b/fuse-service/src/main/java/com/yangdb/fuse/services/controllers/StandardQueryController.java index 4a5a4c577..b402d3026 100644 --- a/fuse-service/src/main/java/com/yangdb/fuse/services/controllers/StandardQueryController.java +++ b/fuse-service/src/main/java/com/yangdb/fuse/services/controllers/StandardQueryController.java @@ -109,6 +109,14 @@ public ContentResponse run(String cypher, String ontology) { } + @Override + public ContentResponse run(String cypher, String ontology, int pageSize, String cursorType) { + return Builder.builder(CREATED, SERVER_ERROR ) + .data(driver().run(cypher,ontology,pageSize,cursorType)) + .successPredicate(objectContentResponse -> true) + .compose(); + } + @Override public ContentResponse createAndFetch(CreateQueryRequest request) { return createAndFetch(this.create(request),request); diff --git a/fuse-service/src/main/java/com/yangdb/fuse/services/controllers/logging/LoggingQueryController.java b/fuse-service/src/main/java/com/yangdb/fuse/services/controllers/logging/LoggingQueryController.java index 1e6781c51..eb98c4e51 100644 --- a/fuse-service/src/main/java/com/yangdb/fuse/services/controllers/logging/LoggingQueryController.java +++ b/fuse-service/src/main/java/com/yangdb/fuse/services/controllers/logging/LoggingQueryController.java @@ -167,6 +167,25 @@ public ContentResponse run(String cypher, String ontology) { }, this.resultHandler()); } + @Override + public ContentResponse run(String cypher, String ontology, int pageSize, String cursorType) { + return new LoggingSyncMethodDecorator>( + this.logger, + this.metricRegistry, + run, + this.primerMdcWriter(), + Collections.singletonList(trace), + Arrays.asList(info, trace)) + .decorate(() -> { + if (cypher != null) { + new LogMessage.Impl(this.logger, debug, "query: {}", Sequence.incr(), LogType.of(log), createAndFetch) + .with(cypher).log(); + } + return this.controller.run(cypher,ontology , pageSize, cursorType); + }, this.resultHandler()); + + } + @Override public ContentResponse createAndFetch(CreateQueryRequest request) { return new LoggingSyncMethodDecorator>( diff --git a/fuse-service/src/main/resources/public/assets/swagger/swagger.json b/fuse-service/src/main/resources/public/assets/swagger/swagger.json index 3d03af09e..a2211fda0 100644 --- a/fuse-service/src/main/resources/public/assets/swagger/swagger.json +++ b/fuse-service/src/main/resources/public/assets/swagger/swagger.json @@ -222,7 +222,7 @@ } } }, - "/query/cypher/run?pageSize={pageSize};cursorType={cursorType}": { + "/query/cypher/run": { "get": { "tags": [ "query" @@ -382,7 +382,7 @@ } } }, - "/query/v1/run?pageSize={pageSize};cursorType={cursorType}": { + "/query/v1/run": { "post": { "tags": [ "query" @@ -753,7 +753,7 @@ } } }, - "/query/{queryId}/cursor/{cursorId}/nextPageData?pageSize={pageSize};deletePage={deletePage}": { + "/query/{queryId}/cursor/{cursorId}/nextPageData": { "get": { "tags": [ "data"