Implementing projection

This commit is contained in:
luca.frosini 2023-11-24 14:03:06 +01:00
parent 5fe0e5771b
commit 6a1e0e5838
8 changed files with 275 additions and 131 deletions

View File

@ -22,6 +22,7 @@ import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaE
import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaNotFoundException;
import org.gcube.informationsystem.resourceregistry.queries.operators.ConditionalOperator;
import org.gcube.informationsystem.resourceregistry.queries.operators.LogicalOperator;
import org.gcube.informationsystem.resourceregistry.queries.operators.MatemathicsOperator;
import org.gcube.informationsystem.resourceregistry.queries.operators.ProjectionOperator;
import org.gcube.informationsystem.resourceregistry.types.TypesCache;
import org.gcube.informationsystem.utils.TypeUtility;
@ -187,10 +188,10 @@ public abstract class JsonQueryERElement {
protected StringBuffer generateAlias() {
StringBuffer sb = new StringBuffer();
sb.append(type.toLowerCase());
// The entry point will have 00 as suffix
sb.append(breadcrumb.size());
sb.append(position);
for(JsonQueryERElement elem : breadcrumb) {
sb.append(elem.getPosition());
}
sb.append(this.position);
return sb;
}
@ -243,13 +244,11 @@ public abstract class JsonQueryERElement {
JsonNode node = objectNode.get(fieldName);
StringBuffer evBuffer = evaluateNode(node, fieldName, fieldNamePrefix);
if(!first) {
stringBuffer.append(queryLogicalOperator.getLogicalOperator());
}
if(evBuffer!=null && evBuffer.length()>0) {
if(first) {
first = false;
}else {
stringBuffer.append(queryLogicalOperator.getLogicalOperator());
}
stringBuffer.append(evBuffer);
}
@ -293,13 +292,23 @@ public abstract class JsonQueryERElement {
b.append(getAlias(true));
b.append(".");
b.append(fieldNameToEmit);
b.append(" AS ");
b.append(" AS `");
b.append(nameOfFieldToEmit);
b.append("`");
addFieldToEmit(b.toString());
}
return null;
}
if(MatemathicsOperator.getOperators().contains(fieldName)) {
--size;
setProjection(true);
MatemathicsOperator mo = MatemathicsOperator.getMatemathicsOperator(fieldName);
String fieldToEmit = mo.generateFieldToEmit(jsonNode, getAlias(true));
addFieldToEmit(fieldToEmit);
return null;
}
StringBuffer stringBuffer = new StringBuffer();
@ -347,6 +356,11 @@ public abstract class JsonQueryERElement {
stringBuffer.append(addCondition(ConditionalOperator.EQ, key, value));
}
if(jsonNode.isNull()) {
StringBuffer key = getKey(fieldName, null);
stringBuffer.append(addCondition(ConditionalOperator.IS, key, null));
}
return stringBuffer;
}

View File

@ -5,6 +5,15 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.BadRequestException;
import org.gcube.com.fasterxml.jackson.databind.JsonNode;
import org.gcube.com.fasterxml.jackson.databind.node.ArrayNode;
import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode;
import org.gcube.com.fasterxml.jackson.databind.node.TextNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Luca Frosini (ISTI - CNR)
*
@ -32,46 +41,137 @@ public enum MatemathicsOperator {
BITWISE_XOR("_bitxor", " ^ ", ""),
ARRAY_CONCATENATION("_arrayconcat", " || ", "");
protected final String operator;
protected final String matemathicsOperator;
protected static Logger logger = LoggerFactory.getLogger(MatemathicsOperator.class);
public static final String VALUES_KEY = "values";
public static final String SEPARATOR_KEY = "separator";
public static final String AS_KEY = "as";
protected final String operatorKey;
protected final String dbQueryOperator;
protected final String description;
private MatemathicsOperator(String operator, String matemathicsOperator, String description) {
this.operator = operator;
this.matemathicsOperator = matemathicsOperator;
private MatemathicsOperator(String operatorKey, String dbQueryOperator, String description) {
this.operatorKey = operatorKey;
this.dbQueryOperator = dbQueryOperator;
this.description = description;
}
public String getOperator() {
return operator;
public String getOperatorKey() {
return operatorKey;
}
public String getMatemathicsOperator() {
return matemathicsOperator;
public String getDbQueryOperator() {
return dbQueryOperator;
}
public String getDescription() {
return description;
}
private static Set<String> operators;
private static Map<String,MatemathicsOperator> operatorByKey;
static {
MatemathicsOperator.operators = new HashSet<>();
MatemathicsOperator.operatorByKey = new HashMap<>();
for(MatemathicsOperator queryLogicalOperator : MatemathicsOperator.values()) {
MatemathicsOperator.operators.add(queryLogicalOperator.getOperator());
MatemathicsOperator.operatorByKey.put(queryLogicalOperator.getOperator(), queryLogicalOperator);
for(MatemathicsOperator matemathicsOperator : MatemathicsOperator.values()) {
MatemathicsOperator.operatorByKey.put(matemathicsOperator.getOperatorKey(), matemathicsOperator);
}
}
public static Set<String> getOperators() {
return MatemathicsOperator.operators;
return new HashSet<>(MatemathicsOperator.operatorByKey.keySet());
}
public static MatemathicsOperator getQueryLogicalOperator(String key) {
public static MatemathicsOperator getMatemathicsOperator(String key) {
return operatorByKey.get(key);
}
protected String getError(String key, Class<?> clazz, boolean mandatory) {
StringBuffer error = new StringBuffer();
error.append("Root emitting MatemathicsOperator (i.e. ");
error.append(this.operatorKey);
error.append(")");
error.append(" contains ");
if(mandatory) {
error.append("mandatory ");
}
error.append(key);
error.append(" which must be a");
error.append(clazz.getSimpleName());
error.append(". This is a client error. Please fix your query");
logger.error(error.toString());
throw new BadRequestException(error.toString());
}
public String generateFieldToEmit(JsonNode jsonNode, String fieldPrefix) {
JsonNode jn = jsonNode.get(VALUES_KEY);
if(jn.isNull() || !jn.isArray()) {
getError(VALUES_KEY, ArrayNode.class, true);
}
String fieldSeparator = null;
if(this == MatemathicsOperator.SUM && jsonNode.has(SEPARATOR_KEY)) {
JsonNode sep = jsonNode.get(SEPARATOR_KEY);
if(!sep.isTextual()) {
getError(SEPARATOR_KEY, TextNode.class, false);
}
fieldSeparator = sep.asText();
}
StringBuffer sb = new StringBuffer();
sb.append("(");
sb.append(generateFieldToEmit((ArrayNode) jn, fieldSeparator, fieldPrefix));
JsonNode jnAs = jsonNode.get(AS_KEY);
if(jnAs.isNull() || !jnAs.isTextual()) {
getError(AS_KEY, TextNode.class, true);
}
sb.append(") AS `");
sb.append(jnAs.asText());
sb.append("`");
return sb.toString();
}
protected StringBuffer addFieldPrefix(StringBuffer sb, String fieldPrefix) {
if(fieldPrefix !=null && fieldPrefix.trim().length()>0) {
sb.append(fieldPrefix.trim());
sb.append(".");
}
return sb;
}
protected StringBuffer generateFieldToEmit(ArrayNode arrayNode, String fieldsSeparator, String fieldPrefix) {
StringBuffer buffer = new StringBuffer();
int size = arrayNode.size();
for(int i=0; i<size; i++) {
JsonNode jn = arrayNode.get(i);
if(jn.isObject()) {
ObjectNode on = (ObjectNode) jn;
String key = on.fieldNames().next();
MatemathicsOperator mo = MatemathicsOperator.getMatemathicsOperator(key);
ArrayNode an = (ArrayNode) on.get(key);
buffer.append("(");
buffer.append(mo.generateFieldToEmit(an, null, fieldPrefix));
buffer.append(")");
}
if(jn.isTextual()) {
buffer = addFieldPrefix(buffer, fieldPrefix);
buffer.append(jn.asText());
}
if(i<(size-1)) {
buffer.append(" ");
buffer.append(dbQueryOperator);
buffer.append(" ");
if(fieldsSeparator!=null) {
buffer.append("'");
buffer.append(fieldsSeparator);
buffer.append("' ");
buffer.append(dbQueryOperator);
buffer.append(" ");
}
}
}
return buffer;
}
}

View File

@ -199,7 +199,7 @@ public class JsonQueryTest extends ContextTest {
@Test
public void testCreateMatchQuery() throws Exception {
File queriesDirectory = getProjectionQueriesDirectory();
File jsonQueryFile = new File(queriesDirectory, "EService-query.json");
File jsonQueryFile = new File(queriesDirectory, "HostingNode-query.json");
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(jsonQueryFile);
logger.info("Going to test the following JSON query {}", jsonNode.toString());

View File

@ -0,0 +1,38 @@
package org.gcube.informationsystem.resourceregistry.queries.operators;
import org.gcube.com.fasterxml.jackson.databind.JsonNode;
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MathematicsOperatorTest {
protected static Logger logger = LoggerFactory.getLogger(MathematicsOperatorTest.class);
public static final String JSON = "{ \n"
+ " \"values\" : [\n"
+ " {\n"
+ " \"_minus\" : [\n"
+ " \"size\", \n"
+ " \"used\" \n"
+ " ]\n"
+ " },\n"
+ " \"unit\" \n"
+ " ],\n"
+ " \"separator\" : \" \",\n"
+ " \"as\" : \"HD Space Left\"\n"
+ "}";
@Test
public void testGenerateFieldToEmit() throws Exception {
ObjectMapper om = new ObjectMapper();
JsonNode jn = om.readTree(JSON);
String s = MatemathicsOperator.SUM.generateFieldToEmit(jn, "haspersistentmemory20");
logger.debug(s);
}
}

View File

@ -21,9 +21,9 @@ MATCH
.outV('EService') { where: ($matched.eservice00 == $currentMatch)}
RETURN
networkingfacet40.hostName AS Host,
softwarefacet20.group AS Group,
softwarefacet20.name AS Name,
softwarefacet20.version AS Version,
statefacet20.value AS Status,
eservice00.id AS ID
networkingfacet40.hostName AS `Host`,
softwarefacet20.group AS `Group`,
softwarefacet20.name AS `Name`,
softwarefacet20.version AS `Version`,
statefacet20.value AS `Status`,
eservice00.id AS `ID`

View File

@ -1,37 +0,0 @@
SELECT id AS ID,
outE("IsIdentifiedBy").inV("SoftwareFacet").name[0] AS `Name`,
outE("IsIdentifiedBy").inV("SoftwareFacet").group[0] AS `Group`,
outE("IsIdentifiedBy").inV("SoftwareFacet").version[0] AS `Version`,
outE("ConsistsOf").inV("StateFacet").value AS `Status`,
inE("Activates").outV("HostingNode").outE("IsIdentifiedBy").inV("NetworkingFacet").hostName[0] AS `Host`
FROM (
TRAVERSE outV("EService") FROM (
TRAVERSE inE("ConsistsOf") FROM (
SELECT FROM (
TRAVERSE inV("StateFacet") FROM (
TRAVERSE outE("ConsistsOf") FROM (
TRAVERSE outV("EService") FROM (
TRAVERSE inE("IsIdentifiedBy") FROM (
SELECT FROM (
TRAVERSE inV("SoftwareFacet") FROM (
TRAVERSE outE("IsIdentifiedBy") FROM (
TRAVERSE inV("EService") FROM (
TRAVERSE outE("Activates") FROM (
TRAVERSE outV("HostingNode") FROM (
TRAVERSE inE("IsIdentifiedBy") FROM (
SELECT FROM NetworkingFacet
)
)
)
)
)
)
)
)
)
)
)
)
)
)
) WHERE @class INSTANCEOF "EService"

View File

@ -1,66 +1,65 @@
{
"_projection" : {
"type": "HostingNode",
"_emit" : {
"id" : "Id",
},
"metadata" : {
"_emit" : {
"lastUpdateTime" : "Last Update Time"
}
},
"consistsOf": [
{
"type": "IsIdentifiedBy",
"target": {
"type": "NetworkingFacet",
"_emit" : {
"hostName" : "HostName"
}
}
},
{
"type": "ConsistsOf",
"target": {
"type": "StateFacet",
"_emit" : {
"value" : "Status"
}
}
},
{
"type": "HasPersistentMemory",
"target": {
"type": "MemoryFacet",
"_concat" : {
"values" : [
{
"_sub" : [
"size",
"used"
]
},
"unit"
],
"separator" : " ",
"as" : "HD Space Left"
}
}
},
{
"type": "HasVolatileMemory",
"target": {
"type": "MemoryFacet",
"_concat" : {
"values" : [
"size",
"unit"
],
"separator" : " ",
"as" : "Mem. Available."
}
"type": "HostingNode",
"_emit" : {
"id" : "ID"
},
"metadata" : {
"_emit" : {
"lastUpdateTime" : "Last Update Time"
}
},
"consistsOf": [
{
"type": "IsIdentifiedBy",
"target": {
"type": "NetworkingFacet",
"_emit" : {
"hostName" : "HostName"
}
}
]
}
},
{
"type": "ConsistsOf",
"target": {
"type": "StateFacet",
"_emit" : {
"value" : "Status"
}
}
},
{
"type": "HasPersistentMemory",
"target": {
"type": "MemoryFacet",
"_sum" : {
"values" : [
{
"_minus" : [
"size",
"used"
]
},
"unit"
],
"separator" : " ",
"as" : "HD Space Left"
}
}
},
{
"type": "HasVolatileMemory",
"target": {
"type": "MemoryFacet",
"jvmMaxMemory" : null,
"_sum" : {
"values" : [
"size",
"unit"
],
"separator" : " ",
"as" : "Mem. Available."
}
}
}
]
}

View File

@ -0,0 +1,30 @@
MATCH
{class: HostingNode, as: hostingnode0, where: ($currentMatch['@class'] INSTANCEOF 'HostingNode')}
.outE('IsIdentifiedBy') { as: isidentifiedby00, where: ($currentMatch['@class'] INSTANCEOF 'IsIdentifiedBy')}
.inV('NetworkingFacet') { as: networkingfacet000, where: ($currentMatch['@class'] INSTANCEOF 'NetworkingFacet')}
.inE('IsIdentifiedBy') { where: ($matched.isidentifiedby00 == $currentMatch)}
.outV('HostingNode') { where: ($matched.hostingnode0 == $currentMatch)}
.outE('ConsistsOf') { as: consistsof01, where: ($currentMatch['@class'] INSTANCEOF 'ConsistsOf')}
.inV('StateFacet') { as: statefacet010, where: ($currentMatch['@class'] INSTANCEOF 'StateFacet')}
.inE('ConsistsOf') { where: ($matched.consistsof01 == $currentMatch)}
.outV('HostingNode') { where: ($matched.hostingnode0 == $currentMatch)}
.outE('HasPersistentMemory') { as: haspersistentmemory02, where: ($currentMatch['@class'] INSTANCEOF 'HasPersistentMemory')}
.inV('MemoryFacet') { as: memoryfacet020, where: ($currentMatch['@class'] INSTANCEOF 'MemoryFacet')}
.inE('HasPersistentMemory') { where: ($matched.haspersistentmemory02 == $currentMatch)}
.outV('HostingNode') { where: ($matched.hostingnode0 == $currentMatch)}
.outE('HasVolatileMemory') { as: hasvolatilememory03, where: ($currentMatch['@class'] INSTANCEOF 'HasVolatileMemory')}
.inV('MemoryFacet') { as: memoryfacet030, where: (($currentMatch['@class'] INSTANCEOF 'MemoryFacet') AND (jvmMaxMemory IS null))}
.inE('HasVolatileMemory') { where: ($matched.hasvolatilememory03 == $currentMatch)}
.outV('HostingNode') { where: ($matched.hostingnode0 == $currentMatch)}
RETURN
networkingfacet000.hostName AS `HostName`,
statefacet010.value AS `Status`,
((memoryfacet020.size - memoryfacet020.used) + ' ' + memoryfacet020.unit) AS `HD Space Left`,
(memoryfacet030.size + ' ' + memoryfacet030.unit) AS `Mem. Available.`,
hostingnode0.id AS `ID`,
hostingnode0.lastUpdateTime AS `Last Update Time`