diff --git a/reasoner/catalog/openspg-catalog/pom.xml b/reasoner/catalog/openspg-catalog/pom.xml
new file mode 100644
index 00000000..ded8793d
--- /dev/null
+++ b/reasoner/catalog/openspg-catalog/pom.xml
@@ -0,0 +1,74 @@
+
+
+
+ 4.0.0
+
+ com.antgroup.openspg.reasoner
+ reasoner-parent
+ 0.0.1-SNAPSHOT
+ ../../pom.xml
+
+
+ reasoner-openspg-catalog
+
+
+ 8
+ 8
+
+
+
+
+ com.antgroup.openspg.reasoner
+ reasoner-common
+
+
+ com.antgroup.openspg.reasoner
+ reasoner-lube-api
+
+
+ com.antgroup.openspg.reasoner
+ reasoner-kgdsl-parser
+
+
+ junit
+ junit
+
+
+ org.apache.commons
+ commons-collections4
+
+
+ org.projectlombok
+ lombok
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+ org.apache.hadoop
+ hadoop-common
+
+
+ com.antgroup.openspg.server
+ api-http-client
+
+
+ com.antgroup.openspg.server
+ core-schema-model
+
+
+
+
diff --git a/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/ConceptRule.java b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/ConceptRule.java
new file mode 100644
index 00000000..79de1cff
--- /dev/null
+++ b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/ConceptRule.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2023 Ant Group CO., Ltd.
+ *
+ * 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.
+ */
+
+package com.antgroup.openspg.reasoner.catalog.impl.struct;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+@Data
+public class ConceptRule {
+ @JSONField(name = "relation")
+ private String relation;
+
+ @JSONField(name = "objectMetaType")
+ private String objectMetaType;
+
+ @JSONField(name = "objectConcept")
+ private String objectConcept;
+
+ @JSONField(name = "dsl")
+ private String dsl;
+
+ /**
+ * Getter method for property relation.
+ *
+ * @return property value of relation
+ */
+ public String getRelation() {
+ return relation;
+ }
+
+ /**
+ * Setter method for property relation.
+ *
+ * @param relation value to be assigned to property relation
+ */
+ public void setRelation(String relation) {
+ this.relation = relation;
+ }
+
+ /**
+ * Getter method for property objectMetaType.
+ *
+ * @return property value of objectMetaType
+ */
+ public String getObjectMetaType() {
+ return objectMetaType;
+ }
+
+ /**
+ * Setter method for property objectMetaType.
+ *
+ * @param objectMetaType value to be assigned to property objectMetaType
+ */
+ public void setObjectMetaType(String objectMetaType) {
+ this.objectMetaType = objectMetaType;
+ }
+
+ /**
+ * Getter method for property objectConcept.
+ *
+ * @return property value of objectConcept
+ */
+ public String getObjectConcept() {
+ return objectConcept;
+ }
+
+ /**
+ * Setter method for property objectConcept.
+ *
+ * @param objectConcept value to be assigned to property objectConcept
+ */
+ public void setObjectConcept(String objectConcept) {
+ this.objectConcept = objectConcept;
+ }
+
+ /**
+ * Getter method for property dsl.
+ *
+ * @return property value of dsl
+ */
+ public String getDsl() {
+ return dsl;
+ }
+
+ /**
+ * Setter method for property dsl.
+ *
+ * @param dsl value to be assigned to property dsl
+ */
+ public void setDsl(String dsl) {
+ this.dsl = dsl;
+ }
+}
diff --git a/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/PropertyMeta.java b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/PropertyMeta.java
new file mode 100644
index 00000000..27304e30
--- /dev/null
+++ b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/PropertyMeta.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2023 Ant Group CO., Ltd.
+ *
+ * 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.
+ */
+
+package com.antgroup.openspg.reasoner.catalog.impl.struct;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+@Data
+public class PropertyMeta {
+ @JSONField(name = "id")
+ private Long id;
+
+ @JSONField(name = "name")
+ private String name;
+
+ @JSONField(name = "attrRangeDetail")
+ private PropertyRangeDetail propRange;
+
+ @JSONField(name = "propertyCategoryEnum")
+ private String category;
+
+ @JSONField(name = "spreadable")
+ private boolean spreadable;
+
+ @JSONField(name = "transformerDetail")
+ private TransformerDetail transformerDetail;
+
+ @JSONField(name = "logicRule")
+ private Rule logicRule;
+
+ /**
+ * Getter method for property logicalRule.
+ *
+ * @return property value of logicalRule
+ */
+ public Rule getLogicRule() {
+ return logicRule;
+ }
+
+ /**
+ * Setter method for property logicalRule.
+ *
+ * @param logicRule value to be assigned to property logicalRule
+ */
+ public void setLogicRule(Rule logicRule) {
+ this.logicRule = logicRule;
+ }
+
+ /**
+ * Getter method for property name.
+ *
+ * @return property value of name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Setter method for property name.
+ *
+ * @param name value to be assigned to property name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Getter method for property propRange.
+ *
+ * @return property value of propRange
+ */
+ public PropertyRangeDetail getPropRange() {
+ return propRange;
+ }
+
+ /**
+ * Setter method for property propRange.
+ *
+ * @param propRange value to be assigned to property propRange
+ */
+ public void setPropRange(PropertyRangeDetail propRange) {
+ this.propRange = propRange;
+ }
+
+ /**
+ * Getter method for property category.
+ *
+ * @return property value of category
+ */
+ public String getCategory() {
+ return category;
+ }
+
+ /**
+ * Setter method for property category.
+ *
+ * @param category value to be assigned to property category
+ */
+ public void setCategory(String category) {
+ this.category = category;
+ }
+
+ public boolean isSpreadable() {
+ return spreadable;
+ }
+
+ /**
+ * Setter method for property spreadable.
+ *
+ * @param spreadable value to be assigned to property spreadable
+ */
+ public void setSpreadable(boolean spreadable) {
+ this.spreadable = spreadable;
+ }
+
+ /**
+ * Getter method for property transformerDetail.
+ *
+ * @return property value of transformerDetail
+ */
+ public TransformerDetail getTransformerDetail() {
+ return transformerDetail;
+ }
+
+ /**
+ * Setter method for property transformerDetail.
+ *
+ * @param transformerDetail value to be assigned to property transformerDetail
+ */
+ public void setTransformerDetail(TransformerDetail transformerDetail) {
+ this.transformerDetail = transformerDetail;
+ }
+}
diff --git a/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/PropertyRangeDetail.java b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/PropertyRangeDetail.java
new file mode 100644
index 00000000..fc2137f9
--- /dev/null
+++ b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/PropertyRangeDetail.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 Ant Group CO., Ltd.
+ *
+ * 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.
+ */
+
+package com.antgroup.openspg.reasoner.catalog.impl.struct;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+@Data
+public class PropertyRangeDetail {
+ @JSONField(name = "id")
+ private long id;
+
+ @JSONField(name = "rangeEntityName")
+ private String rangeEntityName;
+
+ @JSONField(name = "attrRangeTypeEnumCode")
+ private String attrRangeTypeEnum;
+
+ /**
+ * Getter method for property rangeEntityName.
+ *
+ * @return property value of rangeEntityName
+ */
+ public String getRangeEntityName() {
+ return rangeEntityName;
+ }
+
+ /**
+ * Getter method for property attrRangeTypeEnum.
+ *
+ * @return property value of attrRangeTypeEnum
+ */
+ public String getAttrRangeTypeEnum() {
+ return attrRangeTypeEnum;
+ }
+
+ /**
+ * Setter method for property attrRangeTypeEnum.
+ *
+ * @param attrRangeTypeEnum value to be assigned to property attrRangeTypeEnum
+ */
+ public void setAttrRangeTypeEnum(String attrRangeTypeEnum) {
+ this.attrRangeTypeEnum = attrRangeTypeEnum;
+ }
+}
diff --git a/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/RelationTypeDetail.java b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/RelationTypeDetail.java
new file mode 100644
index 00000000..83beae10
--- /dev/null
+++ b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/RelationTypeDetail.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2023 Ant Group CO., Ltd.
+ *
+ * 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.
+ */
+
+package com.antgroup.openspg.reasoner.catalog.impl.struct;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import java.util.List;
+import lombok.Data;
+
+@Data
+public class RelationTypeDetail {
+ @JSONField(name = "id")
+ private Long id;
+
+ @JSONField(name = "name")
+ private String name;
+
+ @JSONField(name = "startEntityTypeDetail")
+ private VertexMeta startEntityType;
+
+ @JSONField(name = "endEntityTypeDetail")
+ private VertexMeta endEntityType;
+
+ @JSONField(name = "attributeTypeDetailList")
+ private List attributeTypeDetailList;
+
+ @JSONField(name = "relationDirectionEnumCode")
+ private String relationDirectionEnum;
+
+ @JSONField(name = "logicRule")
+ private Rule logicRule;
+
+ /**
+ * Getter method for property logicalRule.
+ *
+ * @return property value of logicalRule
+ */
+ public Rule getLogicRule() {
+ return logicRule;
+ }
+
+ /**
+ * Setter method for property logicalRule.
+ *
+ * @param logicRule value to be assigned to property logicalRule
+ */
+ public void setLogicRule(Rule logicRule) {
+ this.logicRule = logicRule;
+ }
+
+ /**
+ * Getter method for property name.
+ *
+ * @return property value of name
+ */
+ public Long getId() {
+ return id;
+ }
+
+ /**
+ * Getter method for property name.
+ *
+ * @return property value of name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Setter method for property name.
+ *
+ * @param name value to be assigned to property name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Getter method for property startEntityType.
+ *
+ * @return property value of startEntityType
+ */
+ public VertexMeta getStartEntityType() {
+ return startEntityType;
+ }
+
+ /**
+ * Setter method for property startEntityType.
+ *
+ * @param startEntityType value to be assigned to property startEntityType
+ */
+ public void setStartEntityType(VertexMeta startEntityType) {
+ this.startEntityType = startEntityType;
+ }
+
+ /**
+ * Getter method for property endEntityType.
+ *
+ * @return property value of endEntityType
+ */
+ public VertexMeta getEndEntityType() {
+ return endEntityType;
+ }
+
+ /**
+ * Setter method for property endEntityType.
+ *
+ * @param endEntityType value to be assigned to property endEntityType
+ */
+ public void setEndEntityType(VertexMeta endEntityType) {
+ this.endEntityType = endEntityType;
+ }
+
+ /**
+ * Getter method for property attributeTypeDetailList.
+ *
+ * @return property value of attributeTypeDetailList
+ */
+ public List getAttributeTypeDetailList() {
+ return attributeTypeDetailList;
+ }
+
+ /**
+ * Setter method for property attributeTypeDetailList.
+ *
+ * @param attributeTypeDetailList value to be assigned to property attributeTypeDetailList
+ */
+ public void setAttributeTypeDetailList(List attributeTypeDetailList) {
+ this.attributeTypeDetailList = attributeTypeDetailList;
+ }
+
+ /**
+ * Getter method for property relationDirectionEnum.
+ *
+ * @return property value of relationDirectionEnum
+ */
+ public String getRelationDirectionEnum() {
+ return relationDirectionEnum;
+ }
+
+ /**
+ * Setter method for property relationDirectionEnum.
+ *
+ * @param relationDirectionEnum value to be assigned to property relationDirectionEnum
+ */
+ public void setRelationDirectionEnum(String relationDirectionEnum) {
+ this.relationDirectionEnum = relationDirectionEnum;
+ }
+}
diff --git a/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/Rule.java b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/Rule.java
new file mode 100644
index 00000000..c72b8d59
--- /dev/null
+++ b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/Rule.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2023 Ant Group CO., Ltd.
+ *
+ * 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.
+ */
+
+package com.antgroup.openspg.reasoner.catalog.impl.struct;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+@Data
+public class Rule {
+ @JSONField(name = "ruleId")
+ private String ruleId;
+
+ @JSONField(name = "ruleContent")
+ private String ruleContent;
+
+ /**
+ * Getter method for property ruleId.
+ *
+ * @return property value of ruleId
+ */
+ public String getRuleId() {
+ return ruleId;
+ }
+
+ /**
+ * Setter method for property ruleId.
+ *
+ * @param ruleId value to be assigned to property ruleId
+ */
+ public void setRuleId(String ruleId) {
+ this.ruleId = ruleId;
+ }
+
+ /**
+ * Getter method for property ruleContent.
+ *
+ * @return property value of ruleContent
+ */
+ public String getRuleContent() {
+ return ruleContent;
+ }
+
+ /**
+ * Setter method for property ruleContent.
+ *
+ * @param ruleContent value to be assigned to property ruleContent
+ */
+ public void setRuleContent(String ruleContent) {
+ this.ruleContent = ruleContent;
+ }
+}
diff --git a/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/TransformerDetail.java b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/TransformerDetail.java
new file mode 100644
index 00000000..302e80bc
--- /dev/null
+++ b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/TransformerDetail.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 Ant Group CO., Ltd.
+ *
+ * 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.
+ */
+
+package com.antgroup.openspg.reasoner.catalog.impl.struct;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+@Data
+public class TransformerDetail {
+
+ @JSONField(name = "transformerCategoryEnum")
+ private String transformerCategoryEnum;
+
+ /**
+ * Getter method for property transformerCategoryEnum.
+ *
+ * @return property value of transformerCategoryEnum
+ */
+ public String getTransformerCategoryEnum() {
+ return transformerCategoryEnum;
+ }
+
+ /**
+ * Setter method for property transformerCategoryEnum.
+ *
+ * @param transformerCategoryEnum value to be assigned to property transformerCategoryEnum
+ */
+ public void setTransformerCategoryEnum(String transformerCategoryEnum) {
+ this.transformerCategoryEnum = transformerCategoryEnum;
+ }
+}
diff --git a/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/VertexMeta.java b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/VertexMeta.java
new file mode 100644
index 00000000..29b2d5cb
--- /dev/null
+++ b/reasoner/catalog/openspg-catalog/src/main/java/com/antgroup/openspg/reasoner/catalog/impl/struct/VertexMeta.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2023 Ant Group CO., Ltd.
+ *
+ * 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.
+ */
+
+package com.antgroup.openspg.reasoner.catalog.impl.struct;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import java.util.List;
+import lombok.Data;
+
+@Data
+public class VertexMeta {
+ @JSONField(name = "id")
+ private Long id;
+
+ @JSONField(name = "name")
+ private String name;
+
+ @JSONField(name = "attributeTypeDetailList")
+ private List attributeTypeDetailList;
+
+ @JSONField(name = "relationTypeDetailList")
+ private List relationTypeDetailList;
+
+ @JSONField(name = "inheritAttributeTypeDetailList")
+ private List inheritAttributeTypeDetailList;
+
+ @JSONField(name = "entityCategory")
+ private String entityCategory;
+
+ /**
+ * Getter method for property entityCategory.
+ *
+ * @return property value of entityCategory
+ */
+ public String getEntityCategory() {
+ return entityCategory;
+ }
+
+ /**
+ * Setter method for property entityCategory.
+ *
+ * @param entityCategory value to be assigned to property entityCategory
+ */
+ public void setEntityCategory(String entityCategory) {
+ this.entityCategory = entityCategory;
+ }
+
+ /**
+ * Getter method for property name.
+ *
+ * @return property value of name
+ */
+ public Long getId() {
+ return id;
+ }
+
+ /**
+ * Getter method for property name.
+ *
+ * @return property value of name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Setter method for property name.
+ *
+ * @param name value to be assigned to property name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Getter method for property attributeTypeDetailList.
+ *
+ * @return property value of attributeTypeDetailList
+ */
+ public List getAttributeTypeDetailList() {
+ return attributeTypeDetailList;
+ }
+
+ /**
+ * Setter method for property attributeTypeDetailList.
+ *
+ * @param attributeTypeDetailList value to be assigned to property attributeTypeDetailList
+ */
+ public void setAttributeTypeDetailList(List attributeTypeDetailList) {
+ this.attributeTypeDetailList = attributeTypeDetailList;
+ }
+
+ /**
+ * Getter method for property relationTypeDetailList.
+ *
+ * @return property value of relationTypeDetailList
+ */
+ public List getRelationTypeDetailList() {
+ return relationTypeDetailList;
+ }
+
+ /**
+ * Getter method for property relationTypeDetailList.
+ *
+ * @return property value of relationTypeDetailList
+ */
+ public List getInheritAttributeTypeDetailList() {
+ return inheritAttributeTypeDetailList;
+ }
+
+ /**
+ * Setter method for property relationTypeDetailList.
+ *
+ * @param relationTypeDetailList value to be assigned to property relationTypeDetailList
+ */
+ public void setRelationTypeDetailList(List relationTypeDetailList) {
+ this.relationTypeDetailList = relationTypeDetailList;
+ }
+}
diff --git a/reasoner/catalog/openspg-catalog/src/main/scala/com/antgroup/openspg/reasoner/catalog/impl/KgSchemaConnectionInfo.scala b/reasoner/catalog/openspg-catalog/src/main/scala/com/antgroup/openspg/reasoner/catalog/impl/KgSchemaConnectionInfo.scala
new file mode 100644
index 00000000..a326ab6f
--- /dev/null
+++ b/reasoner/catalog/openspg-catalog/src/main/scala/com/antgroup/openspg/reasoner/catalog/impl/KgSchemaConnectionInfo.scala
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2023 Ant Group CO., Ltd.
+ *
+ * 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.
+ */
+
+package com.antgroup.openspg.reasoner.catalog.impl
+
+case class KgSchemaConnectionInfo(uri: String, token: String)
diff --git a/reasoner/catalog/openspg-catalog/src/main/scala/com/antgroup/openspg/reasoner/catalog/impl/OpenSPGCatalog.scala b/reasoner/catalog/openspg-catalog/src/main/scala/com/antgroup/openspg/reasoner/catalog/impl/OpenSPGCatalog.scala
new file mode 100644
index 00000000..b107ffd6
--- /dev/null
+++ b/reasoner/catalog/openspg-catalog/src/main/scala/com/antgroup/openspg/reasoner/catalog/impl/OpenSPGCatalog.scala
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2023 Ant Group CO., Ltd.
+ *
+ * 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.
+ */
+
+package com.antgroup.openspg.reasoner.catalog.impl
+
+import scala.collection.JavaConverters._
+import scala.collection.mutable
+import scala.collection.mutable.ListBuffer
+
+import com.antgroup.openspg.core.schema.model.`type`.{BaseAdvancedType, BaseSPGType, BasicType, ProjectSchema}
+import com.antgroup.openspg.core.schema.model.predicate.{Property, Relation}
+import com.antgroup.openspg.core.schema.model.semantic.DynamicTaxonomySemantic
+import com.antgroup.openspg.reasoner.common.constants.Constants
+import com.antgroup.openspg.reasoner.common.exception.SchemaException
+import com.antgroup.openspg.reasoner.common.graph.edge.SPO
+import com.antgroup.openspg.reasoner.common.types.KTString
+import com.antgroup.openspg.reasoner.lube.catalog.{AbstractConnection, Catalog, GeneralSemanticRule, PropertyGraphSchema, SemanticPropertyGraph, SemanticRule}
+import com.antgroup.openspg.reasoner.lube.catalog.struct.{Edge, Field, Node}
+import com.antgroup.openspg.server.api.facade.ApiResponse
+import com.antgroup.openspg.server.api.facade.client.{ConceptFacade, SchemaFacade}
+import com.antgroup.openspg.server.api.facade.dto.schema.request.{ConceptRequest, ProjectSchemaRequest}
+import com.antgroup.openspg.server.api.http.client.{HttpConceptFacade, HttpSchemaFacade}
+import com.antgroup.openspg.server.api.http.client.util.{ConnectionInfo, HttpClientBootstrap}
+import org.apache.commons.collections4.CollectionUtils
+import org.apache.commons.lang3.StringUtils
+
+
+class OpenSPGCatalog(val projectId: Long,
+ val connInfo: KgSchemaConnectionInfo,
+ val projectSchema: ProjectSchema = null) extends Catalog {
+
+ if (projectSchema == null) {
+ HttpClientBootstrap.init(new ConnectionInfo(connInfo.uri))
+ }
+
+ private val spgSchemaFacade: SchemaFacade = new HttpSchemaFacade()
+ private val spgConceptFacade: ConceptFacade = new HttpConceptFacade()
+
+ private val defineRules = new mutable.HashMap[String, SemanticRule]()
+
+ /**
+ * Get schema from knowledge graph
+ */
+ override def getKnowledgeGraph(): SemanticPropertyGraph = {
+ val realProjectSchema: ProjectSchema =
+ if (projectSchema == null) {
+ val request = new ProjectSchemaRequest()
+ request.setProjectId(projectId)
+ resultOf(spgSchemaFacade.queryProjectSchema(request))
+ } else {
+ projectSchema
+ }
+
+ val nodes: mutable.Map[String, Node] = new mutable.HashMap[String, Node]()
+ val edges: mutable.Map[SPO, Edge] = new mutable.HashMap[SPO, Edge]
+ realProjectSchema.getSpgTypes.asScala.foreach(spgType => {
+ val node = toNode(realProjectSchema, spgType)
+ if (node != null) {
+ nodes.put(spgType.getName, node)
+
+ val vertexEdges = toEdges(realProjectSchema, spgType)
+ for (e <- vertexEdges) {
+ if (edges.contains(e._1)) {
+ val edgeInfo = edges(e._1)
+ val mergeSet = edgeInfo.properties ++ e._2.properties
+ edges += (e._1 -> Edge(
+ edgeInfo.startNode,
+ edgeInfo.typeName,
+ edgeInfo.endNode,
+ mergeSet,
+ edgeInfo.resolved))
+ } else {
+ edges += e
+ }
+ }
+ }
+ })
+
+ new SemanticPropertyGraph(
+ Catalog.defaultGraphName,
+ new PropertyGraphSchema(nodes, edges),
+ defineRules,
+ null)
+ }
+
+ private def toNode(projectSchema: ProjectSchema, spgType: BaseSPGType): Node = {
+ val attrList = new ListBuffer[Field]()
+ attrList.+=(defaultTypeField)
+ spgType match {
+ case _: BasicType =>
+ null
+ case advancedType: BaseAdvancedType =>
+ attrList.++=(advancedType.getProperties.asScala.map(spgProperty => {
+ toField(projectSchema, spgType, spgProperty)
+ }))
+ attrList.++=(getDefaultNodeProperties())
+ Node(
+ advancedType.getName,
+ PropertySchemaOps.toNodeType(spgType.getSpgTypeEnum),
+ attrList.toSet,
+ true)
+ }
+ }
+
+ private def toField(projectSchema: ProjectSchema,
+ spgType: BaseSPGType,
+ spgProperty: Property): Field = {
+ val propertyType = PropertySchemaOps
+ .stringToKgType2(projectSchema.getByRef(spgProperty.getObjectTypeRef))
+ val rule = spgProperty.getLogicalRule
+ val predicateName = spgProperty.getName
+ if (rule != null && StringUtils.isNotBlank(rule.getContent)) {
+ defineRules.put(s"${spgType.getName}.${predicateName}", GeneralSemanticRule(rule.getContent))
+ new Field(predicateName, propertyType, false)
+ } else {
+ new Field(predicateName, propertyType, true)
+ }
+ }
+
+ private def defaultTypeField: Field = {
+ new Field(Constants.CONTEXT_LABEL, KTString, true)
+ }
+
+ private def toEdges(projectSchema: ProjectSchema, spgType: BaseSPGType): Map[SPO, Edge] = {
+ if (CollectionUtils.isEmpty(spgType.getRelations)) {
+ Map.empty
+ } else {
+ spgType.getRelations.asScala
+ .flatMap(relation => toEdge(projectSchema, spgType, relation))
+ .map(e => (new SPO(e.startNode, e.typeName, e.endNode), e))
+ .toMap
+ }
+ }
+
+ private def toEdge(projectSchema: ProjectSchema,
+ spgType: BaseSPGType,
+ rel: Relation): List[Edge] = {
+ val attrList = rel.getSubProperties.asScala.toList
+ val fields = new ListBuffer[Field]()
+ val s = spgType.getName
+ val p = rel.getName
+ val o = rel.getObjectTypeRef.getName
+ val spo = new SPO(s, p, o).toString
+
+ fields.++=(attrList.map(att => {
+ val relationType = PropertySchemaOps
+ .stringToKgType2(projectSchema.getByRef(att.getObjectTypeRef))
+ new Field(att.getName, relationType, true)
+ }))
+ fields.+=(defaultTypeField)
+ fields.++=(getDefaultEdgeProperties())
+
+ val rule = rel.getLogicalRule
+ if (rule != null && StringUtils.isNotBlank(rule.getContent)) {
+ defineRules.put(spo, GeneralSemanticRule(rule.getContent))
+ List.apply(Edge(s, p, o, fields.toSet, false))
+ } else if (p.equals("belongTo")) {
+ val request = new ConceptRequest()
+ request.setConceptTypeName(o)
+
+ val concept = resultOf(spgConceptFacade.queryConcept(request))
+ if (CollectionUtils.isNotEmpty(concept.getConcepts)) {
+ concept.getConcepts.asScala
+ .map(r => {
+ r.getSemantics.asScala.foreach {
+ case belong: DynamicTaxonomySemantic =>
+ if (belong.getLogicalRule != null) {
+ defineRules.put(spo + "/" + r.getName,
+ GeneralSemanticRule(belong.getLogicalRule.getContent))
+ }
+ case _ =>
+ }
+ Edge(s, p, o + "/" + r.getName, fields.toSet, false)
+ })
+ .toList
+ } else {
+ List.apply(Edge(s, p, o, fields.toSet, true))
+ }
+ } else {
+ List.apply(Edge(s, p, o, fields.toSet, true))
+ }
+ }
+
+ /**
+ * Get connections of knowledge graph
+ *
+ * @return
+ */
+ override def getConnections(): Map[AbstractConnection, Set[String]] = {
+ val connections = new mutable.HashMap[AbstractConnection, Set[String]]()
+ graphRepository
+ .get("KG")
+ .map(graph => {
+ val graphSchema = graph.graphSchema
+
+ val types = new mutable.HashSet[String]()
+ types.++=(graphSchema.nodes.keySet)
+ types.++=(graphSchema.edges.map(x => x._1.toString).toSet)
+
+ connections.put(new AbstractConnection {}, types.toSet)
+ })
+ connections.toMap
+ }
+
+ private def resultOf[T](apiResponse: ApiResponse[T]): T = {
+ if (apiResponse.isSuccess) {
+ apiResponse.getData
+ } else {
+ throw SchemaException("Get Schema failed")
+ }
+ }
+
+ /**
+ * get default node properties
+ *
+ * @return
+ */
+ override def getDefaultNodeProperties()
+ : Set[Field] = {
+ Set.apply(
+ new Field(Constants.NODE_ID_KEY, KTString, true),
+ new Field(Constants.VERTEX_INTERNAL_ID_KEY, KTString, true),
+ new Field(Constants.CONTEXT_LABEL, KTString, true))
+ }
+
+ /**
+ * get default edge properties
+ */
+ override def getDefaultEdgeProperties()
+ : Set[Field] = {
+ Set.apply(
+ new Field(Constants.CONTEXT_LABEL, KTString, true),
+ new Field(Constants.EDGE_FROM_ID_KEY, KTString, true),
+ new Field(Constants.EDGE_TO_ID_KEY, KTString, true),
+ new Field(Constants.EDGE_FROM_INTERNAL_ID_KEY, KTString, true),
+ new Field(Constants.EDGE_TO_INTERNAL_ID_KEY, KTString, true),
+ new Field(Constants.EDGE_FROM_ID_TYPE_KEY, KTString, true),
+ new Field(Constants.EDGE_TO_ID_TYPE_KEY, KTString, true)
+ )
+ }
+
+}
diff --git a/reasoner/catalog/openspg-catalog/src/main/scala/com/antgroup/openspg/reasoner/catalog/impl/PropertySchemaOps.scala b/reasoner/catalog/openspg-catalog/src/main/scala/com/antgroup/openspg/reasoner/catalog/impl/PropertySchemaOps.scala
new file mode 100644
index 00000000..b51616cc
--- /dev/null
+++ b/reasoner/catalog/openspg-catalog/src/main/scala/com/antgroup/openspg/reasoner/catalog/impl/PropertySchemaOps.scala
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2023 Ant Group CO., Ltd.
+ *
+ * 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.
+ */
+
+package com.antgroup.openspg.reasoner.catalog.impl
+
+import scala.language.implicitConversions
+
+import com.antgroup.openspg.core.schema.model.`type`.{BaseSPGType, BasicType, ConceptType, EntityType, EventType, SPGTypeEnum, StandardType}
+import com.antgroup.openspg.reasoner.catalog.impl.struct.PropertyMeta
+import com.antgroup.openspg.reasoner.common.exception.KGValueException
+import com.antgroup.openspg.reasoner.common.types._
+import com.antgroup.openspg.reasoner.lube.catalog.struct.NodeType
+
+object PropertySchemaOps {
+
+ implicit def stringToKgType(propertySchema: PropertyMeta): KgType = {
+ propertySchema.getCategory match {
+ case "BASIC" =>
+ toKgType(propertySchema.getPropRange.getAttrRangeTypeEnum)
+ case "CONCEPT" =>
+ KTConcept(propertySchema.getPropRange.getRangeEntityName)
+ case "STANDARD" =>
+ KTStd(propertySchema.getPropRange.getRangeEntityName, propertySchema.isSpreadable)
+ case "PROPERTY" =>
+ KTStd(propertySchema.getPropRange.getRangeEntityName, propertySchema.isSpreadable)
+ case "ENTITY" =>
+ KTAdvanced(propertySchema.getPropRange.getRangeEntityName)
+ case _ => throw KGValueException(s"unsupported type: ${propertySchema.getCategory}")
+ }
+ }
+
+ def stringToKgType2(spgType: BaseSPGType): KgType = {
+ spgType match {
+ case entityType: EntityType =>
+ KTAdvanced(entityType.getName)
+ case conceptType: ConceptType =>
+ KTConcept(conceptType.getName)
+ case eventType: EventType =>
+ // todo
+ KTAdvanced(eventType.getName)
+ case standardType: StandardType =>
+ KTStd(spgType.getName, standardType.getSpreadable)
+ case basicType: BasicType =>
+ toKgType(basicType.getBasicType.name())
+ case _ =>
+ throw KGValueException(s"unsupported type: ${spgType}")
+ }
+ }
+
+ private def toKgType(basicType: String): KgType = {
+ basicType.toUpperCase() match {
+ case "INTEGER" => KTLong
+ case "LONG" => KTLong
+ case "TEXT" => KTString
+ case "FLOAT" => KTDouble
+ case "DOUBLE" => KTDouble
+ case "BOOLEAN" => KTString
+ case "DATE" => KTString
+ case "TIME" => KTString
+ case "URL" => KTString
+ case "DATETIME" => KTString
+ case "TIMESTAMP" => KTString
+ case _ => throw KGValueException(s"unsupported type: $basicType")
+ }
+ }
+
+ def toNodeType(spgType: SPGTypeEnum): NodeType.Value = {
+ spgType match {
+ case SPGTypeEnum.ENTITY_TYPE =>
+ NodeType.ADVANCED
+ case SPGTypeEnum.CONCEPT_TYPE =>
+ NodeType.CONCEPT
+ case SPGTypeEnum.STANDARD_TYPE =>
+ NodeType.STANDARD
+ case SPGTypeEnum.EVENT_TYPE =>
+ NodeType.EVENT
+ case _ => throw KGValueException(s"unsupported type: $spgType")
+ }
+ }
+
+}
diff --git a/reasoner/catalog/openspg-catalog/src/test/java/com/antgroup/openspg/reasoner/catalog/impl/OpenSPGCatalogTest.java b/reasoner/catalog/openspg-catalog/src/test/java/com/antgroup/openspg/reasoner/catalog/impl/OpenSPGCatalogTest.java
new file mode 100644
index 00000000..7acbddd5
--- /dev/null
+++ b/reasoner/catalog/openspg-catalog/src/test/java/com/antgroup/openspg/reasoner/catalog/impl/OpenSPGCatalogTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2023 Ant Group CO., Ltd.
+ *
+ * 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.
+ */
+
+package com.antgroup.openspg.reasoner.catalog.impl;
+
+import com.antgroup.openspg.reasoner.lube.catalog.SemanticPropertyGraph;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+@Ignore
+public class OpenSPGCatalogTest {
+
+ public static final KgSchemaConnectionInfo connInfo =
+ new KgSchemaConnectionInfo("http://127.0.0.1:8887", "a8bB6398B6Da9170");
+
+ @Test
+ public void testGet() {
+ long projectId = 2L;
+
+ OpenSPGCatalog catalog = new OpenSPGCatalog(projectId, connInfo, null);
+ catalog.init();
+ SemanticPropertyGraph graph = catalog.getKnowledgeGraph();
+
+ Assert.assertNotNull(graph);
+ }
+}
diff --git a/reasoner/lube-api/src/main/scala/com/antgroup/openspg/reasoner/lube/catalog/Catalog.scala b/reasoner/lube-api/src/main/scala/com/antgroup/openspg/reasoner/lube/catalog/Catalog.scala
index 77c8c4da..76c72ef9 100644
--- a/reasoner/lube-api/src/main/scala/com/antgroup/openspg/reasoner/lube/catalog/Catalog.scala
+++ b/reasoner/lube-api/src/main/scala/com/antgroup/openspg/reasoner/lube/catalog/Catalog.scala
@@ -32,7 +32,7 @@ import com.antgroup.openspg.reasoner.lube.common.graph.IRGraph
* and the property graph at runtime
*/
abstract class Catalog() extends Serializable {
- private val graphRepository = new mutable.HashMap[String, SemanticPropertyGraph]()
+ protected val graphRepository = new mutable.HashMap[String, SemanticPropertyGraph]()
private val connections = new mutable.HashMap[String, AbstractConnection]()
/**
diff --git a/reasoner/pom.xml b/reasoner/pom.xml
index c1cd9177..ed791a52 100644
--- a/reasoner/pom.xml
+++ b/reasoner/pom.xml
@@ -29,6 +29,7 @@
udf
lube-api
kgdsl-parser
+ catalog/openspg-catalog