diff --git a/geaflow/geaflow-dsl/geaflow-dsl-common/src/main/java/org/apache/geaflow/dsl/common/function/LabeledPredicateFunctions.java b/geaflow/geaflow-dsl/geaflow-dsl-common/src/main/java/org/apache/geaflow/dsl/common/function/LabeledPredicateFunctions.java new file mode 100644 index 000000000..7603c51b1 --- /dev/null +++ b/geaflow/geaflow-dsl/geaflow-dsl-common/src/main/java/org/apache/geaflow/dsl/common/function/LabeledPredicateFunctions.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.geaflow.dsl.common.function; + +import org.apache.geaflow.dsl.common.data.RowEdge; +import org.apache.geaflow.dsl.common.data.RowVertex; + +/** + * Utility class providing static methods for the ISO-GQL labeled predicate. + * + *
Implements ISO-GQL Section 19.9: <labeled predicate>, which tests whether a + * graph element (vertex or edge) has a given label. + * + *
ISO-GQL General Rules (three-valued logic): + *
Implements ISO-GQL Section 19.9: <labeled predicate> + * + *
Syntax:
+ *+ * IS_LABELED(element, label) + *+ * + *
Semantics:
+ * Returns TRUE if the vertex or edge has the given label, FALSE if not, or NULL if either + * operand is NULL. + * + *Example:
+ *+ * MATCH (a) -[e]-> (b) + * WHERE IS_LABELED(a, 'person') + * RETURN a, e, b + *+ */ +@Description( + name = "is_labeled", + description = "ISO-GQL Labeled Predicate: Returns TRUE if the vertex or edge has the given " + + "label, FALSE if not, NULL if either operand is NULL. Follows ISO-GQL three-valued logic." +) +public class IsLabeled extends UDF { + + /** + * Evaluates the IS LABELED predicate. + * + * @param elementValue vertex or edge to check + * @param labelValue label name to test for + * @return Boolean: true if the element has the given label, false if not, null if either + * operand is null + */ + public Boolean eval(Object elementValue, Object labelValue) { + return LabeledPredicateFunctions.isLabeled(elementValue, labelValue); + } + + /** + * Type-specific overload for vertices. + */ + public Boolean eval(RowVertex vertex, String label) { + return LabeledPredicateFunctions.isLabeled(vertex, label); + } + + /** + * Type-specific overload for edges. + */ + public Boolean eval(RowEdge edge, String label) { + return LabeledPredicateFunctions.isLabeled(edge, label); + } +} diff --git a/geaflow/geaflow-dsl/geaflow-dsl-plan/src/main/java/org/apache/geaflow/dsl/udf/table/other/IsNotLabeled.java b/geaflow/geaflow-dsl/geaflow-dsl-plan/src/main/java/org/apache/geaflow/dsl/udf/table/other/IsNotLabeled.java new file mode 100644 index 000000000..3804cb874 --- /dev/null +++ b/geaflow/geaflow-dsl/geaflow-dsl-plan/src/main/java/org/apache/geaflow/dsl/udf/table/other/IsNotLabeled.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.geaflow.dsl.udf.table.other; + +import org.apache.geaflow.dsl.common.data.RowEdge; +import org.apache.geaflow.dsl.common.data.RowVertex; +import org.apache.geaflow.dsl.common.function.Description; +import org.apache.geaflow.dsl.common.function.LabeledPredicateFunctions; +import org.apache.geaflow.dsl.common.function.UDF; + +/** + * UDF implementation for the ISO-GQL IS NOT LABELED predicate. + * + *
Implements ISO-GQL Section 19.9: <labeled predicate> + * + *
Syntax:
+ *+ * IS_NOT_LABELED(element, label) + *+ * + *
Semantics:
+ * Returns TRUE if the vertex or edge does NOT have the given label, FALSE if it does, or NULL + * if either operand is NULL. + * + *Example:
+ *+ * MATCH (a) -[e]-> (b) + * WHERE IS_NOT_LABELED(a, 'software') + * RETURN a, e, b + *+ */ +@Description( + name = "is_not_labeled", + description = "ISO-GQL Labeled Predicate: Returns TRUE if the vertex or edge does NOT have " + + "the given label, FALSE if it does, NULL if either operand is NULL. Follows ISO-GQL " + + "three-valued logic." +) +public class IsNotLabeled extends UDF { + + /** + * Evaluates the IS NOT LABELED predicate. + * + * @param elementValue vertex or edge to check + * @param labelValue label name to test for + * @return Boolean: true if the element does NOT have the given label, false if it does, null + * if either operand is null + */ + public Boolean eval(Object elementValue, Object labelValue) { + return LabeledPredicateFunctions.isNotLabeled(elementValue, labelValue); + } + + /** + * Type-specific overload for vertices. + */ + public Boolean eval(RowVertex vertex, String label) { + return LabeledPredicateFunctions.isNotLabeled(vertex, label); + } + + /** + * Type-specific overload for edges. + */ + public Boolean eval(RowEdge edge, String label) { + return LabeledPredicateFunctions.isNotLabeled(edge, label); + } +} diff --git a/geaflow/geaflow-dsl/geaflow-dsl-runtime/src/test/java/org/apache/geaflow/dsl/runtime/query/GQLLabeledPredicateTest.java b/geaflow/geaflow-dsl/geaflow-dsl-runtime/src/test/java/org/apache/geaflow/dsl/runtime/query/GQLLabeledPredicateTest.java new file mode 100644 index 000000000..4b33b6838 --- /dev/null +++ b/geaflow/geaflow-dsl/geaflow-dsl-runtime/src/test/java/org/apache/geaflow/dsl/runtime/query/GQLLabeledPredicateTest.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.geaflow.dsl.runtime.query; + +import org.testng.annotations.Test; + +public class GQLLabeledPredicateTest { + + @Test + public void testLabeledPredicate_001() throws Exception { + QueryTester + .build() + .withGraphDefine("/query/modern_graph.sql") + .withQueryPath("/query/gql_labeled_predicate_001.sql") + .execute() + .checkSinkResult(); + } +} diff --git a/geaflow/geaflow-dsl/geaflow-dsl-runtime/src/test/resources/expect/gql_labeled_predicate_001.txt b/geaflow/geaflow-dsl/geaflow-dsl-runtime/src/test/resources/expect/gql_labeled_predicate_001.txt new file mode 100644 index 000000000..6abf2432d --- /dev/null +++ b/geaflow/geaflow-dsl/geaflow-dsl-runtime/src/test/resources/expect/gql_labeled_predicate_001.txt @@ -0,0 +1,6 @@ +1,2,true,false,true,false +1,3,true,true,true,true +1,4,true,false,true,false +4,3,true,true,true,true +4,5,true,true,true,true +6,3,true,true,true,true diff --git a/geaflow/geaflow-dsl/geaflow-dsl-runtime/src/test/resources/query/gql_labeled_predicate_001.sql b/geaflow/geaflow-dsl/geaflow-dsl-runtime/src/test/resources/query/gql_labeled_predicate_001.sql new file mode 100644 index 000000000..4cf48d68d --- /dev/null +++ b/geaflow/geaflow-dsl/geaflow-dsl-runtime/src/test/resources/query/gql_labeled_predicate_001.sql @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +-- Test Case 1: IS_LABELED / IS_NOT_LABELED predicate on vertices and edges. +-- For every matched (a)-[e]->(b) triple, evaluate the labeled predicate against +-- the known labels of the modern graph (person / software / knows / created). + +CREATE TABLE tbl_result ( + a_id bigint, + b_id bigint, + a_is_person boolean, + b_is_software boolean, + a_is_not_software boolean, + e_is_created boolean +) WITH ( + type='file', + geaflow.dsl.file.path='${target}' +); + +USE GRAPH modern; + +INSERT INTO tbl_result +SELECT + a.id, + b.id, + IS_LABELED(a, 'person') as a_is_person, + IS_LABELED(b, 'software') as b_is_software, + IS_NOT_LABELED(a, 'software') as a_is_not_software, + IS_LABELED(e, 'created') as e_is_created +FROM ( + MATCH (a) -[e]-> (b) + RETURN a, e, b +) +ORDER BY a.id, b.id +;