mirror of
https://github.com/OpenSPG/openspg.git
synced 2025-08-15 20:32:21 +00:00
feat(reasoner): support thinker in knext (#344)
Co-authored-by: matthewhyx <matthew.hyx@antgroup.com>
This commit is contained in:
parent
f0e552e9ec
commit
b48dd2cbe5
@ -18,6 +18,7 @@ from knext.command.sub_command.config import list_config
|
|||||||
from knext.command.sub_command.project import create_project
|
from knext.command.sub_command.project import create_project
|
||||||
from knext.command.sub_command.project import list_project
|
from knext.command.sub_command.project import list_project
|
||||||
from knext.command.sub_command.reasoner import execute_reasoner_job
|
from knext.command.sub_command.reasoner import execute_reasoner_job
|
||||||
|
from knext.command.sub_command.thinker import execute_thinker_job
|
||||||
from knext.command.sub_command.schema import commit_schema
|
from knext.command.sub_command.schema import commit_schema
|
||||||
from knext.command.sub_command.schema import list_schema
|
from knext.command.sub_command.schema import list_schema
|
||||||
from knext.command.sub_command.schema import reg_concept_rule
|
from knext.command.sub_command.schema import reg_concept_rule
|
||||||
@ -79,5 +80,15 @@ def reasoner() -> None:
|
|||||||
|
|
||||||
reasoner.command("execute")(execute_reasoner_job)
|
reasoner.command("execute")(execute_reasoner_job)
|
||||||
|
|
||||||
|
|
||||||
|
@_main.group()
|
||||||
|
def thinker() -> None:
|
||||||
|
"""Thinker client."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
thinker.command("execute")(execute_thinker_job)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
_main()
|
_main()
|
||||||
|
28
python/knext/knext/command/sub_command/thinker.py
Normal file
28
python/knext/knext/command/sub_command/thinker.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2023 OpenSPG Authors
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from knext.thinker.client import ThinkerClient
|
||||||
|
|
||||||
|
|
||||||
|
@click.option("--subject", help="The subject of reasoning goal, eg: id,type or type")
|
||||||
|
@click.option("--predicate", help="The predicate of reasoning goal, eg: type")
|
||||||
|
@click.option("--object", help="The object of reasoning goal, eg: id,type or type")
|
||||||
|
@click.option("--mode", help="Reasoning mode, eg: spo or node")
|
||||||
|
@click.option("--params", help="Reasoning context")
|
||||||
|
def execute_thinker_job(subject="", predicate="", object="", mode="spo", params=""):
|
||||||
|
"""
|
||||||
|
Submit asynchronous reasoner jobs to server by providing DSL file or string.
|
||||||
|
"""
|
||||||
|
client = ThinkerClient()
|
||||||
|
client.execute(subject, predicate, object, mode, params)
|
@ -16,6 +16,9 @@ from knext.schema.client import SchemaClient
|
|||||||
from knext.schema.model.base import SpgTypeEnum
|
from knext.schema.model.base import SpgTypeEnum
|
||||||
|
|
||||||
|
|
||||||
|
combo_seperator = "\0+\0"
|
||||||
|
|
||||||
|
|
||||||
def is_blank(text):
|
def is_blank(text):
|
||||||
if not text:
|
if not text:
|
||||||
return True
|
return True
|
||||||
@ -95,7 +98,7 @@ class SPGConceptRuleMarkLang:
|
|||||||
return
|
return
|
||||||
|
|
||||||
reasoning_po_match = re.match(
|
reasoning_po_match = re.match(
|
||||||
r"^\[([^\]]+)\]->\(`?([a-zA-Z0-9\.]+)`?/`([^`]+)`\):$",
|
r"^\[([^\]]+)\]->\(`?([a-zA-Z0-9\.]+)`?/`([^`]+)`(\+`([^`]+)`)?\):$",
|
||||||
expression,
|
expression,
|
||||||
)
|
)
|
||||||
if reasoning_po_match:
|
if reasoning_po_match:
|
||||||
@ -103,16 +106,19 @@ class SPGConceptRuleMarkLang:
|
|||||||
"please define namespace first"
|
"please define namespace first"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
combo_add = reasoning_po_match.group(5)
|
||||||
self.predicate = reasoning_po_match.group(1)
|
self.predicate = reasoning_po_match.group(1)
|
||||||
self.dst_concept = (
|
self.dst_concept = (
|
||||||
reasoning_po_match.group(2),
|
reasoning_po_match.group(2),
|
||||||
reasoning_po_match.group(3),
|
reasoning_po_match.group(3)
|
||||||
|
if combo_add is None
|
||||||
|
else reasoning_po_match.group(3) + combo_seperator + combo_add,
|
||||||
)
|
)
|
||||||
self.is_reasoning = True
|
self.is_reasoning = True
|
||||||
return
|
return
|
||||||
|
|
||||||
reasoning_spo_match = re.match(
|
reasoning_spo_match = re.match(
|
||||||
r"^\(`?([a-zA-Z0-9\.]+)`?/`([^`]+)`\)-\[([^\]]+)\]->\(`([a-zA-Z0-9\.]+)`/`([^`]+)`\):$",
|
r"^\(`?([a-zA-Z0-9\.]+)`?/`([^`]+)`\)-\[([^\]]+)\]->\(`([a-zA-Z0-9\.]+)`/`([^`]+)`(\+`([^`]+)`)?\):$",
|
||||||
expression,
|
expression,
|
||||||
)
|
)
|
||||||
if reasoning_spo_match:
|
if reasoning_spo_match:
|
||||||
@ -125,9 +131,12 @@ class SPGConceptRuleMarkLang:
|
|||||||
reasoning_spo_match.group(2),
|
reasoning_spo_match.group(2),
|
||||||
)
|
)
|
||||||
self.predicate = reasoning_spo_match.group(3)
|
self.predicate = reasoning_spo_match.group(3)
|
||||||
|
combo_add = reasoning_po_match.group(7)
|
||||||
self.dst_concept = (
|
self.dst_concept = (
|
||||||
reasoning_spo_match.group(4),
|
reasoning_spo_match.group(4),
|
||||||
reasoning_spo_match.group(5),
|
reasoning_spo_match.group(5)
|
||||||
|
if combo_add is None
|
||||||
|
else reasoning_spo_match.group(5) + combo_seperator + combo_add,
|
||||||
)
|
)
|
||||||
self.is_reasoning = True
|
self.is_reasoning = True
|
||||||
return
|
return
|
||||||
@ -215,6 +224,9 @@ class SPGConceptRuleMarkLang:
|
|||||||
break
|
break
|
||||||
|
|
||||||
if self.is_reasoning:
|
if self.is_reasoning:
|
||||||
|
if combo_seperator in object_name:
|
||||||
|
names = object_name.split(combo_seperator)
|
||||||
|
object_name = f"{names[0]}`+{object_type}/`{names[1]}"
|
||||||
if (
|
if (
|
||||||
subject_type is None
|
subject_type is None
|
||||||
and self.predicate is None
|
and self.predicate is None
|
||||||
@ -230,7 +242,7 @@ class SPGConceptRuleMarkLang:
|
|||||||
head = f"DefinePriority ({object_type})" + " {\n"
|
head = f"DefinePriority ({object_type})" + " {\n"
|
||||||
else:
|
else:
|
||||||
head = (
|
head = (
|
||||||
f"Define (:{object_type}/`{object_name}`)-[:{predicate_name}]->"
|
f"Define (:{subject_type}/`{subject_name}`)-[:{predicate_name}]->"
|
||||||
f"(:{object_type}/`{object_name}`)" + " {\n"
|
f"(:{object_type}/`{object_name}`)" + " {\n"
|
||||||
)
|
)
|
||||||
elif subject_name is None:
|
elif subject_name is None:
|
||||||
|
10
python/knext/knext/thinker/__init__.py
Normal file
10
python/knext/knext/thinker/__init__.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Copyright 2023 OpenSPG Authors
|
||||||
|
#
|
||||||
|
# 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.
|
59
python/knext/knext/thinker/client.py
Normal file
59
python/knext/knext/thinker/client.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2023 OpenSPG Authors
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
import os
|
||||||
|
|
||||||
|
from knext.common.base.client import Client
|
||||||
|
|
||||||
|
|
||||||
|
class ThinkerClient(Client):
|
||||||
|
"""SPG Thinker Client."""
|
||||||
|
|
||||||
|
def __init__(self, host_addr: str = None, project_id: int = None):
|
||||||
|
super().__init__(host_addr, project_id)
|
||||||
|
|
||||||
|
def execute(self, subject="", predicate="", object="", mode="spo", params=""):
|
||||||
|
"""
|
||||||
|
Execute a synchronous builder job in local runner.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
from knext.reasoner import lib
|
||||||
|
from knext.common import env
|
||||||
|
|
||||||
|
jar_path = os.path.join(lib.__path__[0], lib.LOCAL_REASONER_JAR)
|
||||||
|
|
||||||
|
java_cmd = [
|
||||||
|
"java",
|
||||||
|
"-cp",
|
||||||
|
jar_path,
|
||||||
|
"com.antgroup.openspg.reasoner.runner.local.thinker.LocalThinkerMain",
|
||||||
|
"--projectId",
|
||||||
|
self._project_id,
|
||||||
|
"--subject",
|
||||||
|
subject or "",
|
||||||
|
"--predicate",
|
||||||
|
predicate or "",
|
||||||
|
"--object",
|
||||||
|
object or "",
|
||||||
|
"--mode",
|
||||||
|
mode,
|
||||||
|
"--params" or "",
|
||||||
|
params,
|
||||||
|
"--schemaUrl",
|
||||||
|
os.environ.get("KNEXT_HOST_ADDR") or env.LOCAL_SCHEMA_URL,
|
||||||
|
"--graphStateClass",
|
||||||
|
os.environ.get("KNEXT_GRAPH_STATE_CLASS") or lib.LOCAL_GRAPH_STATE_CLASS,
|
||||||
|
"--graphStoreUrl",
|
||||||
|
os.environ.get("KNEXT_GRAPH_STORE_URL") or lib.LOCAL_GRAPH_STORE_URL,
|
||||||
|
]
|
||||||
|
|
||||||
|
subprocess.call(java_cmd)
|
@ -68,6 +68,10 @@
|
|||||||
<groupId>com.antgroup.openspg.reasoner</groupId>
|
<groupId>com.antgroup.openspg.reasoner</groupId>
|
||||||
<artifactId>reasoner-warehouse-common</artifactId>
|
<artifactId>reasoner-warehouse-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.antgroup.openspg.reasoner</groupId>
|
||||||
|
<artifactId>reasoner-thinker</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.antgroup.openspg.reasoner</groupId>
|
<groupId>com.antgroup.openspg.reasoner</groupId>
|
||||||
<artifactId>reasoner-cloudext-warehouse</artifactId>
|
<artifactId>reasoner-cloudext-warehouse</artifactId>
|
||||||
|
@ -13,13 +13,6 @@
|
|||||||
|
|
||||||
package com.antgroup.openspg.reasoner.runner.local;
|
package com.antgroup.openspg.reasoner.runner.local;
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level;
|
|
||||||
import ch.qos.logback.classic.Logger;
|
|
||||||
import ch.qos.logback.classic.LoggerContext;
|
|
||||||
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
|
||||||
import ch.qos.logback.core.ConsoleAppender;
|
|
||||||
import ch.qos.logback.core.FileAppender;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.TypeReference;
|
import com.alibaba.fastjson.TypeReference;
|
||||||
import com.antgroup.openspg.reasoner.catalog.impl.KgSchemaConnectionInfo;
|
import com.antgroup.openspg.reasoner.catalog.impl.KgSchemaConnectionInfo;
|
||||||
@ -42,7 +35,6 @@ import org.apache.commons.cli.HelpFormatter;
|
|||||||
import org.apache.commons.cli.Options;
|
import org.apache.commons.cli.Options;
|
||||||
import org.apache.commons.cli.ParseException;
|
import org.apache.commons.cli.ParseException;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class LocalReasonerMain {
|
public class LocalReasonerMain {
|
||||||
@ -149,36 +141,36 @@ public class LocalReasonerMain {
|
|||||||
try {
|
try {
|
||||||
cmd = parser.parse(options, args);
|
cmd = parser.parse(options, args);
|
||||||
|
|
||||||
String logFileName = cmd.getOptionValue(LOG_FILE_OPTION);
|
String logFileName = cmd.getOptionValue(ParamsKey.LOG_FILE_OPTION);
|
||||||
setUpLogFile(logFileName);
|
LogUtil.setUpLogFile(logFileName);
|
||||||
|
|
||||||
projectId = Long.parseLong(cmd.getOptionValue(PROJECT_ID_OPTION));
|
projectId = Long.parseLong(cmd.getOptionValue(ParamsKey.PROJECT_ID_OPTION));
|
||||||
|
|
||||||
dsl = cmd.getOptionValue(QUERY_OPTION);
|
dsl = cmd.getOptionValue(ParamsKey.QUERY_OPTION);
|
||||||
if (StringUtils.isEmpty(dsl)) {
|
if (StringUtils.isEmpty(dsl)) {
|
||||||
throw new ParseException("please provide query dsl!");
|
throw new ParseException("please provide query dsl!");
|
||||||
}
|
}
|
||||||
outputFile = cmd.getOptionValue(OUTPUT_OPTION);
|
outputFile = cmd.getOptionValue(ParamsKey.OUTPUT_OPTION);
|
||||||
if (StringUtils.isEmpty(outputFile)) {
|
if (StringUtils.isEmpty(outputFile)) {
|
||||||
outputFile = null;
|
outputFile = null;
|
||||||
}
|
}
|
||||||
schemaUri = cmd.getOptionValue(SCHEMA_URL_OPTION);
|
schemaUri = cmd.getOptionValue(ParamsKey.SCHEMA_URL_OPTION);
|
||||||
if (StringUtils.isEmpty(schemaUri)) {
|
if (StringUtils.isEmpty(schemaUri)) {
|
||||||
throw new ParseException("please provide openspg schema uri!");
|
throw new ParseException("please provide openspg schema uri!");
|
||||||
}
|
}
|
||||||
graphLoaderClass = cmd.getOptionValue(GRAPH_LOADER_CLASS_OPTION);
|
graphLoaderClass = cmd.getOptionValue(ParamsKey.GRAPH_LOADER_CLASS_OPTION);
|
||||||
graphStateClass = cmd.getOptionValue(GRAPH_STATE_CLASS_OPTION);
|
graphStateClass = cmd.getOptionValue(ParamsKey.GRAPH_STATE_CLASS_OPTION);
|
||||||
graphStateUrl = cmd.getOptionValue(GRAPH_STORE_URL_OPTION);
|
graphStateUrl = cmd.getOptionValue(ParamsKey.GRAPH_STORE_URL_OPTION);
|
||||||
if (StringUtils.isEmpty(graphStateUrl)) {
|
if (StringUtils.isEmpty(graphStateUrl)) {
|
||||||
graphStateUrl = null;
|
graphStateUrl = null;
|
||||||
}
|
}
|
||||||
String startIdListJson = cmd.getOptionValue(START_ID_OPTION);
|
String startIdListJson = cmd.getOptionValue(ParamsKey.START_ID_OPTION);
|
||||||
if (StringUtils.isBlank(startIdListJson)) {
|
if (StringUtils.isBlank(startIdListJson)) {
|
||||||
startIdList = Collections.emptyList();
|
startIdList = Collections.emptyList();
|
||||||
} else {
|
} else {
|
||||||
startIdList = JSON.parseObject(startIdListJson, new TypeReference<List<List<String>>>() {});
|
startIdList = JSON.parseObject(startIdListJson, new TypeReference<List<List<String>>>() {});
|
||||||
}
|
}
|
||||||
String paramsJson = cmd.getOptionValue(PARAMs_OPTION);
|
String paramsJson = cmd.getOptionValue(ParamsKey.PARAMs_OPTION);
|
||||||
if (StringUtils.isNotEmpty(paramsJson)) {
|
if (StringUtils.isNotEmpty(paramsJson)) {
|
||||||
params = new HashMap<>(JSON.parseObject(paramsJson));
|
params = new HashMap<>(JSON.parseObject(paramsJson));
|
||||||
}
|
}
|
||||||
@ -203,81 +195,33 @@ public class LocalReasonerMain {
|
|||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final String PROJECT_ID_OPTION = "projectId";
|
|
||||||
protected static final String QUERY_OPTION = "query";
|
|
||||||
protected static final String OUTPUT_OPTION = "output";
|
|
||||||
protected static final String SCHEMA_URL_OPTION = "schemaUrl";
|
|
||||||
protected static final String GRAPH_STATE_CLASS_OPTION = "graphStateClass";
|
|
||||||
protected static final String GRAPH_LOADER_CLASS_OPTION = "graphLoaderClass";
|
|
||||||
protected static final String GRAPH_STORE_URL_OPTION = "graphStoreUrl";
|
|
||||||
protected static final String START_ID_OPTION = "startIdList";
|
|
||||||
protected static final String PARAMs_OPTION = "params";
|
|
||||||
protected static final String LOG_FILE_OPTION = "logFile";
|
|
||||||
|
|
||||||
protected static Options getOptions() {
|
protected static Options getOptions() {
|
||||||
Options options = new Options();
|
Options options = new Options();
|
||||||
|
|
||||||
options.addRequiredOption(PROJECT_ID_OPTION, PROJECT_ID_OPTION, true, "project id");
|
|
||||||
options.addRequiredOption(QUERY_OPTION, QUERY_OPTION, true, "query dsl string");
|
|
||||||
options.addOption(OUTPUT_OPTION, OUTPUT_OPTION, true, "output file name");
|
|
||||||
options.addRequiredOption(SCHEMA_URL_OPTION, SCHEMA_URL_OPTION, true, "schema url");
|
|
||||||
options.addOption(
|
|
||||||
GRAPH_STATE_CLASS_OPTION, GRAPH_STATE_CLASS_OPTION, true, "graph state class name");
|
|
||||||
options.addOption(
|
|
||||||
GRAPH_LOADER_CLASS_OPTION, GRAPH_LOADER_CLASS_OPTION, true, "graph loader class name");
|
|
||||||
options.addRequiredOption(
|
options.addRequiredOption(
|
||||||
GRAPH_STORE_URL_OPTION, GRAPH_STORE_URL_OPTION, true, "graph store url");
|
ParamsKey.PROJECT_ID_OPTION, ParamsKey.PROJECT_ID_OPTION, true, "project id");
|
||||||
options.addOption(START_ID_OPTION, START_ID_OPTION, true, "start id list");
|
options.addRequiredOption(
|
||||||
options.addOption(PARAMs_OPTION, PARAMs_OPTION, true, "params");
|
ParamsKey.QUERY_OPTION, ParamsKey.QUERY_OPTION, true, "query dsl string");
|
||||||
options.addOption(LOG_FILE_OPTION, LOG_FILE_OPTION, true, "log file name");
|
options.addOption(ParamsKey.OUTPUT_OPTION, ParamsKey.OUTPUT_OPTION, true, "output file name");
|
||||||
|
options.addRequiredOption(
|
||||||
|
ParamsKey.SCHEMA_URL_OPTION, ParamsKey.SCHEMA_URL_OPTION, true, "schema url");
|
||||||
|
options.addOption(
|
||||||
|
ParamsKey.GRAPH_STATE_CLASS_OPTION,
|
||||||
|
ParamsKey.GRAPH_STATE_CLASS_OPTION,
|
||||||
|
true,
|
||||||
|
"graph state class name");
|
||||||
|
options.addOption(
|
||||||
|
ParamsKey.GRAPH_LOADER_CLASS_OPTION,
|
||||||
|
ParamsKey.GRAPH_LOADER_CLASS_OPTION,
|
||||||
|
true,
|
||||||
|
"graph loader class name");
|
||||||
|
options.addRequiredOption(
|
||||||
|
ParamsKey.GRAPH_STORE_URL_OPTION,
|
||||||
|
ParamsKey.GRAPH_STORE_URL_OPTION,
|
||||||
|
true,
|
||||||
|
"graph store url");
|
||||||
|
options.addOption(ParamsKey.START_ID_OPTION, ParamsKey.START_ID_OPTION, true, "start id list");
|
||||||
|
options.addOption(ParamsKey.PARAMs_OPTION, ParamsKey.PARAMs_OPTION, true, "params");
|
||||||
|
options.addOption(ParamsKey.LOG_FILE_OPTION, ParamsKey.LOG_FILE_OPTION, true, "log file name");
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void setUpLogFile(String logFileName) {
|
|
||||||
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
|
|
||||||
loggerContext.reset();
|
|
||||||
|
|
||||||
PatternLayoutEncoder patternLayoutEncoder = new PatternLayoutEncoder();
|
|
||||||
patternLayoutEncoder.setPattern("%d [%X{traceId}] [%X{rpcId}] [%t] %-5p %c{2} - %m%n");
|
|
||||||
patternLayoutEncoder.setContext(loggerContext);
|
|
||||||
patternLayoutEncoder.start();
|
|
||||||
|
|
||||||
FileAppender<ILoggingEvent> fileAppender = null;
|
|
||||||
if (StringUtils.isNotBlank(logFileName)) {
|
|
||||||
fileAppender = new FileAppender<>();
|
|
||||||
fileAppender.setFile(logFileName);
|
|
||||||
fileAppender.setEncoder(patternLayoutEncoder);
|
|
||||||
fileAppender.setContext(loggerContext);
|
|
||||||
fileAppender.setAppend(false);
|
|
||||||
fileAppender.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
ConsoleAppender<ILoggingEvent> consoleAppender = new ConsoleAppender<>();
|
|
||||||
consoleAppender.setEncoder(patternLayoutEncoder);
|
|
||||||
consoleAppender.setContext(loggerContext);
|
|
||||||
consoleAppender.start();
|
|
||||||
|
|
||||||
Logger brpcLogger = loggerContext.getLogger("com.baidu.brpc");
|
|
||||||
brpcLogger.setLevel(Level.ERROR);
|
|
||||||
brpcLogger.setAdditive(false);
|
|
||||||
if (fileAppender != null) {
|
|
||||||
brpcLogger.addAppender(fileAppender);
|
|
||||||
}
|
|
||||||
brpcLogger.addAppender(consoleAppender);
|
|
||||||
|
|
||||||
Logger dtflysLogger = loggerContext.getLogger("com.dtflys.forest");
|
|
||||||
dtflysLogger.setLevel(Level.ERROR);
|
|
||||||
dtflysLogger.setAdditive(false);
|
|
||||||
if (fileAppender != null) {
|
|
||||||
dtflysLogger.addAppender(fileAppender);
|
|
||||||
}
|
|
||||||
dtflysLogger.addAppender(consoleAppender);
|
|
||||||
|
|
||||||
Logger rootLogger = loggerContext.getLogger("root");
|
|
||||||
if (fileAppender != null) {
|
|
||||||
rootLogger.addAppender(fileAppender);
|
|
||||||
}
|
|
||||||
rootLogger.addAppender(consoleAppender);
|
|
||||||
rootLogger.setLevel(Level.INFO);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 OpenSPG Authors
|
||||||
|
*
|
||||||
|
* 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.runner.local;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level;
|
||||||
|
import ch.qos.logback.classic.Logger;
|
||||||
|
import ch.qos.logback.classic.LoggerContext;
|
||||||
|
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.core.ConsoleAppender;
|
||||||
|
import ch.qos.logback.core.FileAppender;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class LogUtil {
|
||||||
|
public static void setUpLogFile(String logFileName) {
|
||||||
|
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||||
|
loggerContext.reset();
|
||||||
|
|
||||||
|
PatternLayoutEncoder patternLayoutEncoder = new PatternLayoutEncoder();
|
||||||
|
patternLayoutEncoder.setPattern("%d [%X{traceId}] [%X{rpcId}] [%t] %-5p %c{2} - %m%n");
|
||||||
|
patternLayoutEncoder.setContext(loggerContext);
|
||||||
|
patternLayoutEncoder.start();
|
||||||
|
|
||||||
|
FileAppender<ILoggingEvent> fileAppender = null;
|
||||||
|
if (StringUtils.isNotBlank(logFileName)) {
|
||||||
|
fileAppender = new FileAppender<>();
|
||||||
|
fileAppender.setFile(logFileName);
|
||||||
|
fileAppender.setEncoder(patternLayoutEncoder);
|
||||||
|
fileAppender.setContext(loggerContext);
|
||||||
|
fileAppender.setAppend(false);
|
||||||
|
fileAppender.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleAppender<ILoggingEvent> consoleAppender = new ConsoleAppender<>();
|
||||||
|
consoleAppender.setEncoder(patternLayoutEncoder);
|
||||||
|
consoleAppender.setContext(loggerContext);
|
||||||
|
consoleAppender.start();
|
||||||
|
|
||||||
|
Logger brpcLogger = loggerContext.getLogger("com.baidu.brpc");
|
||||||
|
brpcLogger.setLevel(Level.ERROR);
|
||||||
|
brpcLogger.setAdditive(false);
|
||||||
|
if (fileAppender != null) {
|
||||||
|
brpcLogger.addAppender(fileAppender);
|
||||||
|
}
|
||||||
|
brpcLogger.addAppender(consoleAppender);
|
||||||
|
|
||||||
|
Logger dtflysLogger = loggerContext.getLogger("com.dtflys.forest");
|
||||||
|
dtflysLogger.setLevel(Level.ERROR);
|
||||||
|
dtflysLogger.setAdditive(false);
|
||||||
|
if (fileAppender != null) {
|
||||||
|
dtflysLogger.addAppender(fileAppender);
|
||||||
|
}
|
||||||
|
dtflysLogger.addAppender(consoleAppender);
|
||||||
|
|
||||||
|
Logger rootLogger = loggerContext.getLogger("root");
|
||||||
|
if (fileAppender != null) {
|
||||||
|
rootLogger.addAppender(fileAppender);
|
||||||
|
}
|
||||||
|
rootLogger.addAppender(consoleAppender);
|
||||||
|
rootLogger.setLevel(Level.INFO);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 OpenSPG Authors
|
||||||
|
*
|
||||||
|
* 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.runner.local;
|
||||||
|
|
||||||
|
public class ParamsKey {
|
||||||
|
public static final String PROJECT_ID_OPTION = "projectId";
|
||||||
|
public static final String QUERY_OPTION = "query";
|
||||||
|
public static final String OUTPUT_OPTION = "output";
|
||||||
|
public static final String SCHEMA_URL_OPTION = "schemaUrl";
|
||||||
|
public static final String GRAPH_STATE_CLASS_OPTION = "graphStateClass";
|
||||||
|
public static final String GRAPH_LOADER_CLASS_OPTION = "graphLoaderClass";
|
||||||
|
public static final String GRAPH_STORE_URL_OPTION = "graphStoreUrl";
|
||||||
|
public static final String START_ID_OPTION = "startIdList";
|
||||||
|
public static final String PARAMs_OPTION = "params";
|
||||||
|
public static final String LOG_FILE_OPTION = "logFile";
|
||||||
|
public static final String SUBJECT = "subject";
|
||||||
|
public static final String PREDICATE = "predicate";
|
||||||
|
public static final String OBJECT = "object";
|
||||||
|
public static final String MODE = "mode";
|
||||||
|
}
|
@ -0,0 +1,229 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 OpenSPG Authors
|
||||||
|
*
|
||||||
|
* 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.runner.local.thinker;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.antgroup.openspg.reasoner.catalog.impl.KgSchemaConnectionInfo;
|
||||||
|
import com.antgroup.openspg.reasoner.common.graph.vertex.IVertexId;
|
||||||
|
import com.antgroup.openspg.reasoner.graphstate.GraphState;
|
||||||
|
import com.antgroup.openspg.reasoner.graphstate.impl.MemGraphState;
|
||||||
|
import com.antgroup.openspg.reasoner.runner.local.LogUtil;
|
||||||
|
import com.antgroup.openspg.reasoner.runner.local.ParamsKey;
|
||||||
|
import com.antgroup.openspg.reasoner.runner.local.load.graph.AbstractLocalGraphLoader;
|
||||||
|
import com.antgroup.openspg.reasoner.thinker.Thinker;
|
||||||
|
import com.antgroup.openspg.reasoner.thinker.catalog.LogicCatalog;
|
||||||
|
import com.antgroup.openspg.reasoner.thinker.catalog.OpenSPGLogicCatalog;
|
||||||
|
import com.antgroup.openspg.reasoner.thinker.engine.DefaultThinker;
|
||||||
|
import com.antgroup.openspg.reasoner.thinker.logic.Result;
|
||||||
|
import com.antgroup.openspg.reasoner.thinker.logic.graph.*;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.cli.*;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class LocalThinkerMain {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
doMain(args);
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void doMain(String[] args) {
|
||||||
|
ThinkerParams task = parseArgs(args);
|
||||||
|
if (null == task) {
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
GraphState<IVertexId> graphState = loadGraph(task);
|
||||||
|
LogicCatalog logicCatalog = new OpenSPGLogicCatalog(task.getProjectId(), task.getConnInfo());
|
||||||
|
logicCatalog.init();
|
||||||
|
Thinker thinker = new DefaultThinker(graphState, logicCatalog);
|
||||||
|
List<Result> result;
|
||||||
|
if (task.getMode().toLowerCase().equals("spo")) {
|
||||||
|
result =
|
||||||
|
thinker.find(
|
||||||
|
task.getTriple().getSubject(),
|
||||||
|
task.getTriple().getPredicate(),
|
||||||
|
task.getTriple().getObject(),
|
||||||
|
task.getParams());
|
||||||
|
} else {
|
||||||
|
result = thinker.find((Node) task.getTriple().getSubject(), task.getParams());
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(result)) {
|
||||||
|
log.error("local runner return null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("result:\n {}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ThinkerParams parseArgs(String[] args) {
|
||||||
|
Options options = getThinkerOptions();
|
||||||
|
|
||||||
|
CommandLineParser parser = new DefaultParser();
|
||||||
|
HelpFormatter formatter = new HelpFormatter();
|
||||||
|
CommandLine cmd;
|
||||||
|
|
||||||
|
long projectId;
|
||||||
|
String schemaUri;
|
||||||
|
String graphStateClass;
|
||||||
|
String graphLoaderClass;
|
||||||
|
String graphStateUrl;
|
||||||
|
Element s = Element.ANY;
|
||||||
|
Element p = Element.ANY;
|
||||||
|
Element o = Element.ANY;
|
||||||
|
String mode = "spo";
|
||||||
|
Map<String, Object> params = new HashMap<>(3);
|
||||||
|
try {
|
||||||
|
cmd = parser.parse(options, args);
|
||||||
|
|
||||||
|
String logFileName = cmd.getOptionValue(ParamsKey.LOG_FILE_OPTION);
|
||||||
|
LogUtil.setUpLogFile(logFileName);
|
||||||
|
|
||||||
|
projectId = Long.parseLong(cmd.getOptionValue(ParamsKey.PROJECT_ID_OPTION));
|
||||||
|
|
||||||
|
schemaUri = cmd.getOptionValue(ParamsKey.SCHEMA_URL_OPTION);
|
||||||
|
if (StringUtils.isEmpty(schemaUri)) {
|
||||||
|
throw new ParseException("please provide openspg schema uri!");
|
||||||
|
}
|
||||||
|
graphLoaderClass = cmd.getOptionValue(ParamsKey.GRAPH_LOADER_CLASS_OPTION);
|
||||||
|
graphStateClass = cmd.getOptionValue(ParamsKey.GRAPH_STATE_CLASS_OPTION);
|
||||||
|
graphStateUrl = cmd.getOptionValue(ParamsKey.GRAPH_STORE_URL_OPTION);
|
||||||
|
if (StringUtils.isEmpty(graphStateUrl)) {
|
||||||
|
graphStateUrl = null;
|
||||||
|
}
|
||||||
|
String paramsJson = cmd.getOptionValue(ParamsKey.PARAMs_OPTION);
|
||||||
|
if (StringUtils.isNotEmpty(paramsJson)) {
|
||||||
|
params = new HashMap<>(JSON.parseObject(paramsJson));
|
||||||
|
}
|
||||||
|
String subject = cmd.getOptionValue(ParamsKey.SUBJECT);
|
||||||
|
if (StringUtils.isNotBlank(subject)) {
|
||||||
|
s = strToElement(subject, false);
|
||||||
|
}
|
||||||
|
String predicate = cmd.getOptionValue(ParamsKey.PREDICATE);
|
||||||
|
if (StringUtils.isNotBlank(predicate)) {
|
||||||
|
p = strToElement(predicate, true);
|
||||||
|
}
|
||||||
|
String object = cmd.getOptionValue(ParamsKey.OBJECT);
|
||||||
|
if (StringUtils.isNotBlank(object)) {
|
||||||
|
o = strToElement(object, false);
|
||||||
|
}
|
||||||
|
if (s == Element.ANY && p == Element.ANY && o == Element.ANY) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"subject, predicate, object cannot all be empty at the same time.");
|
||||||
|
}
|
||||||
|
String m = cmd.getOptionValue(ParamsKey.MODE);
|
||||||
|
if (StringUtils.isNotBlank(m)) {
|
||||||
|
mode = m;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
formatter.printHelp("ThinkerLocalMain", options);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThinkerParams task = new ThinkerParams();
|
||||||
|
task.setTriple(new Triple(s, p, o));
|
||||||
|
task.setConnInfo(new KgSchemaConnectionInfo(schemaUri, ""));
|
||||||
|
task.setGraphLoadClass(graphLoaderClass);
|
||||||
|
task.setGraphStateClassName(graphStateClass);
|
||||||
|
task.setGraphStateInitString(graphStateUrl);
|
||||||
|
task.setProjectId(projectId);
|
||||||
|
task.setParams(params);
|
||||||
|
task.setMode(mode);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Element strToElement(String content, Boolean isPredicate) {
|
||||||
|
String[] parts = StringUtils.split(content, ",");
|
||||||
|
if (parts.length == 2) {
|
||||||
|
return new Entity(parts[0], parts[1]);
|
||||||
|
} else if (parts.length == 1) {
|
||||||
|
if (isPredicate) {
|
||||||
|
return new Predicate(parts[0]);
|
||||||
|
} else {
|
||||||
|
return new Node(parts[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("format error, require id,type or type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Options getThinkerOptions() {
|
||||||
|
Options options = new Options();
|
||||||
|
options.addRequiredOption(
|
||||||
|
ParamsKey.PROJECT_ID_OPTION, ParamsKey.PROJECT_ID_OPTION, true, "project id");
|
||||||
|
options.addRequiredOption(
|
||||||
|
ParamsKey.SCHEMA_URL_OPTION, ParamsKey.SCHEMA_URL_OPTION, true, "schema url");
|
||||||
|
options.addOption(
|
||||||
|
ParamsKey.SUBJECT, ParamsKey.SUBJECT, true, "query subject, eg: id,type or type");
|
||||||
|
options.addOption(ParamsKey.PREDICATE, ParamsKey.PREDICATE, true, "query predicate, eg: type");
|
||||||
|
options.addOption(
|
||||||
|
ParamsKey.OBJECT, ParamsKey.OBJECT, true, "query object, eg: id,type or type");
|
||||||
|
options.addOption(ParamsKey.OUTPUT_OPTION, ParamsKey.OUTPUT_OPTION, true, "output file name");
|
||||||
|
options.addOption(
|
||||||
|
ParamsKey.GRAPH_STATE_CLASS_OPTION,
|
||||||
|
ParamsKey.GRAPH_STATE_CLASS_OPTION,
|
||||||
|
true,
|
||||||
|
"graph state class name");
|
||||||
|
options.addOption(
|
||||||
|
ParamsKey.GRAPH_LOADER_CLASS_OPTION,
|
||||||
|
ParamsKey.GRAPH_LOADER_CLASS_OPTION,
|
||||||
|
true,
|
||||||
|
"graph loader class name");
|
||||||
|
options.addOption(
|
||||||
|
ParamsKey.GRAPH_STORE_URL_OPTION,
|
||||||
|
ParamsKey.GRAPH_STORE_URL_OPTION,
|
||||||
|
true,
|
||||||
|
"graph store url");
|
||||||
|
options.addOption(ParamsKey.PARAMs_OPTION, ParamsKey.PARAMs_OPTION, true, "params");
|
||||||
|
options.addOption(ParamsKey.LOG_FILE_OPTION, ParamsKey.LOG_FILE_OPTION, true, "log file name");
|
||||||
|
options.addOption(ParamsKey.MODE, ParamsKey.MODE, true, "infer mode, eg: spo or node");
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static GraphState<IVertexId> loadGraph(ThinkerParams params) {
|
||||||
|
GraphState<IVertexId> graphState;
|
||||||
|
String graphStateClass = params.getGraphStateClassName();
|
||||||
|
if (StringUtils.isNotEmpty(graphStateClass)) {
|
||||||
|
try {
|
||||||
|
graphState =
|
||||||
|
(GraphState<IVertexId>)
|
||||||
|
Class.forName(graphStateClass)
|
||||||
|
.getConstructor(String.class)
|
||||||
|
.newInstance(params.getGraphStateInitString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("can not create graph state from " + graphStateClass, e);
|
||||||
|
}
|
||||||
|
return graphState;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemGraphState memGraphState = new MemGraphState();
|
||||||
|
String graphLoadClass = params.getGraphLoadClass();
|
||||||
|
if (StringUtils.isBlank(graphLoadClass)) {
|
||||||
|
return memGraphState;
|
||||||
|
}
|
||||||
|
AbstractLocalGraphLoader graphLoader;
|
||||||
|
try {
|
||||||
|
graphLoader =
|
||||||
|
(AbstractLocalGraphLoader) Class.forName(graphLoadClass).getConstructor().newInstance();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("can not create graph loader from name " + graphLoadClass, e);
|
||||||
|
}
|
||||||
|
graphLoader.setGraphState(memGraphState);
|
||||||
|
graphLoader.load();
|
||||||
|
return memGraphState;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 OpenSPG Authors
|
||||||
|
*
|
||||||
|
* 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.runner.local.thinker;
|
||||||
|
|
||||||
|
import com.antgroup.openspg.reasoner.catalog.impl.KgSchemaConnectionInfo;
|
||||||
|
import com.antgroup.openspg.reasoner.thinker.logic.graph.Triple;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ThinkerParams implements Serializable {
|
||||||
|
private KgSchemaConnectionInfo connInfo = null;
|
||||||
|
private Long projectId;
|
||||||
|
private Triple triple;
|
||||||
|
private Map<String, Object> params;
|
||||||
|
|
||||||
|
/** Choose between graphLoadClass and graphState, or specify a class name */
|
||||||
|
private String graphLoadClass = null;
|
||||||
|
|
||||||
|
/** User specified the name of graphstate */
|
||||||
|
private String graphStateClassName = null;
|
||||||
|
|
||||||
|
private String graphStateInitString = null;
|
||||||
|
|
||||||
|
private String mode = "spo";
|
||||||
|
}
|
@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2023 OpenSPG Authors
|
|
||||||
*
|
|
||||||
* 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.thinker.catalog;
|
|
||||||
|
|
||||||
import com.antgroup.openspg.reasoner.lube.catalog.AbstractConnection;
|
|
||||||
import com.antgroup.openspg.reasoner.lube.catalog.Catalog;
|
|
||||||
import com.antgroup.openspg.reasoner.lube.catalog.SemanticPropertyGraph;
|
|
||||||
import com.antgroup.openspg.reasoner.lube.catalog.struct.Field;
|
|
||||||
import com.antgroup.openspg.reasoner.thinker.logic.LogicNetwork;
|
|
||||||
import com.antgroup.openspg.reasoner.thinker.logic.rule.Rule;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import scala.collection.immutable.Map;
|
|
||||||
import scala.collection.immutable.Set;
|
|
||||||
|
|
||||||
public class DefaultLogicCatalog extends LogicCatalog {
|
|
||||||
private Catalog kgCatalog;
|
|
||||||
private List<Rule> rules;
|
|
||||||
|
|
||||||
private DefaultLogicCatalog() {
|
|
||||||
rules = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DefaultLogicCatalog(List<Rule> rules, Catalog kgCatalog) {
|
|
||||||
this.rules = rules;
|
|
||||||
this.kgCatalog = kgCatalog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LogicNetwork loadLogicNetwork() {
|
|
||||||
LogicNetwork logicNetwork = new LogicNetwork();
|
|
||||||
for (Rule r : rules) {
|
|
||||||
logicNetwork.addRule(r);
|
|
||||||
}
|
|
||||||
return logicNetwork;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SemanticPropertyGraph getKnowledgeGraph() {
|
|
||||||
return kgCatalog.getKnowledgeGraph();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<AbstractConnection, Set<String>> getConnections() {
|
|
||||||
return kgCatalog.getConnections();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Field> getDefaultNodeProperties() {
|
|
||||||
return kgCatalog.getDefaultNodeProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Field> getDefaultEdgeProperties() {
|
|
||||||
return kgCatalog.getDefaultEdgeProperties();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 OpenSPG Authors
|
||||||
|
*
|
||||||
|
* 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.thinker.catalog;
|
||||||
|
|
||||||
|
import com.antgroup.openspg.core.schema.model.semantic.TripleSemantic;
|
||||||
|
import com.antgroup.openspg.core.schema.model.type.BaseSPGType;
|
||||||
|
import com.antgroup.openspg.core.schema.model.type.ProjectSchema;
|
||||||
|
import com.antgroup.openspg.core.schema.model.type.SPGTypeEnum;
|
||||||
|
import com.antgroup.openspg.reasoner.catalog.impl.KgSchemaConnectionInfo;
|
||||||
|
import com.antgroup.openspg.reasoner.catalog.impl.OpenSPGCatalog;
|
||||||
|
import com.antgroup.openspg.reasoner.common.exception.SystemError;
|
||||||
|
import com.antgroup.openspg.reasoner.lube.catalog.AbstractConnection;
|
||||||
|
import com.antgroup.openspg.reasoner.lube.catalog.Catalog;
|
||||||
|
import com.antgroup.openspg.reasoner.lube.catalog.SemanticPropertyGraph;
|
||||||
|
import com.antgroup.openspg.reasoner.lube.catalog.struct.Field;
|
||||||
|
import com.antgroup.openspg.reasoner.thinker.SimplifyThinkerParser;
|
||||||
|
import com.antgroup.openspg.reasoner.thinker.logic.LogicNetwork;
|
||||||
|
import com.antgroup.openspg.reasoner.thinker.logic.rule.Rule;
|
||||||
|
import com.antgroup.openspg.server.api.facade.ApiResponse;
|
||||||
|
import com.antgroup.openspg.server.api.facade.client.ConceptFacade;
|
||||||
|
import com.antgroup.openspg.server.api.facade.client.SchemaFacade;
|
||||||
|
import com.antgroup.openspg.server.api.facade.dto.schema.request.ProjectSchemaRequest;
|
||||||
|
import com.antgroup.openspg.server.api.facade.dto.schema.request.SPGTypeRequest;
|
||||||
|
import com.antgroup.openspg.server.api.http.client.HttpConceptFacade;
|
||||||
|
import com.antgroup.openspg.server.api.http.client.HttpSchemaFacade;
|
||||||
|
import com.antgroup.openspg.server.api.http.client.util.ConnectionInfo;
|
||||||
|
import com.antgroup.openspg.server.api.http.client.util.HttpClientBootstrap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
public class OpenSPGLogicCatalog extends LogicCatalog {
|
||||||
|
private Catalog openSPGCatalog;
|
||||||
|
private Long projectId;
|
||||||
|
private SchemaFacade schemaFacade;
|
||||||
|
private ConceptFacade conceptFacade;
|
||||||
|
|
||||||
|
public OpenSPGLogicCatalog(Long projectId, KgSchemaConnectionInfo connInfo) {
|
||||||
|
this.openSPGCatalog = new OpenSPGCatalog(projectId, connInfo, null);
|
||||||
|
HttpClientBootstrap.init(new ConnectionInfo(connInfo.uri()));
|
||||||
|
this.projectId = projectId;
|
||||||
|
this.schemaFacade = new HttpSchemaFacade();
|
||||||
|
this.conceptFacade = new HttpConceptFacade();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LogicNetwork loadLogicNetwork() {
|
||||||
|
ProjectSchemaRequest request = new ProjectSchemaRequest();
|
||||||
|
request.setProjectId(projectId);
|
||||||
|
ApiResponse<ProjectSchema> projectSchema = schemaFacade.queryProjectSchema(request);
|
||||||
|
if (!projectSchema.isSuccess()) {
|
||||||
|
throw new SystemError("Cannot get schema for projectId=" + projectId, null);
|
||||||
|
}
|
||||||
|
Set<String> conceptTypes =
|
||||||
|
projectSchema.getData().getSpgTypes().stream()
|
||||||
|
.filter(e -> e.getSpgTypeEnum() == SPGTypeEnum.CONCEPT_TYPE)
|
||||||
|
.map(BaseSPGType::getName)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
SPGTypeRequest spgTypeRequest = new SPGTypeRequest(StringUtils.join(conceptTypes, ","));
|
||||||
|
ApiResponse<List<TripleSemantic>> response =
|
||||||
|
conceptFacade.getReasoningConceptsDetail(spgTypeRequest);
|
||||||
|
if (!response.isSuccess()) {
|
||||||
|
throw new SystemError("Cannot get schema for projectId=" + projectId, null);
|
||||||
|
}
|
||||||
|
LogicNetwork logicNetwork = new LogicNetwork();
|
||||||
|
for (TripleSemantic ts : response.getData()) {
|
||||||
|
SimplifyThinkerParser parser = new SimplifyThinkerParser();
|
||||||
|
Rule rule = parser.parseSimplifyDsl(ts.getLogicalRule().getContent(), null).head();
|
||||||
|
logicNetwork.addRule(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
return logicNetwork;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SemanticPropertyGraph getKnowledgeGraph() {
|
||||||
|
return this.openSPGCatalog.getKnowledgeGraph();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public scala.collection.immutable.Map<AbstractConnection, scala.collection.immutable.Set<String>>
|
||||||
|
getConnections() {
|
||||||
|
return this.openSPGCatalog.getConnections();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public scala.collection.immutable.Set<Field> getDefaultNodeProperties() {
|
||||||
|
return this.openSPGCatalog.getDefaultNodeProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public scala.collection.immutable.Set<Field> getDefaultEdgeProperties() {
|
||||||
|
return this.openSPGCatalog.getDefaultEdgeProperties();
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ import com.antgroup.openspg.server.api.http.server.HttpBizCallback;
|
|||||||
import com.antgroup.openspg.server.api.http.server.HttpBizTemplate;
|
import com.antgroup.openspg.server.api.http.server.HttpBizTemplate;
|
||||||
import com.antgroup.openspg.server.biz.common.util.AssertUtils;
|
import com.antgroup.openspg.server.biz.common.util.AssertUtils;
|
||||||
import com.antgroup.openspg.server.biz.schema.ConceptManager;
|
import com.antgroup.openspg.server.biz.schema.ConceptManager;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@ -73,7 +74,8 @@ public class ConceptController extends BaseController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TripleSemantic> action() {
|
public List<TripleSemantic> action() {
|
||||||
return conceptManager.getReasoningConceptsDetail(request.getNameList());
|
List<String> nameList = Lists.newArrayList(request.getName().split(","));
|
||||||
|
return conceptManager.getReasoningConceptsDetail(nameList);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user