mirror of
				https://github.com/OpenSPG/openspg.git
				synced 2025-11-04 03:55:40 +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 list_project
 | 
			
		||||
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 list_schema
 | 
			
		||||
from knext.command.sub_command.schema import reg_concept_rule
 | 
			
		||||
@ -79,5 +80,15 @@ def reasoner() -> None:
 | 
			
		||||
 | 
			
		||||
reasoner.command("execute")(execute_reasoner_job)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@_main.group()
 | 
			
		||||
def thinker() -> None:
 | 
			
		||||
    """Thinker client."""
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
thinker.command("execute")(execute_thinker_job)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
combo_seperator = "\0+\0"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def is_blank(text):
 | 
			
		||||
    if not text:
 | 
			
		||||
        return True
 | 
			
		||||
@ -95,7 +98,7 @@ class SPGConceptRuleMarkLang:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        reasoning_po_match = re.match(
 | 
			
		||||
            r"^\[([^\]]+)\]->\(`?([a-zA-Z0-9\.]+)`?/`([^`]+)`\):$",
 | 
			
		||||
            r"^\[([^\]]+)\]->\(`?([a-zA-Z0-9\.]+)`?/`([^`]+)`(\+`([^`]+)`)?\):$",
 | 
			
		||||
            expression,
 | 
			
		||||
        )
 | 
			
		||||
        if reasoning_po_match:
 | 
			
		||||
@ -103,16 +106,19 @@ class SPGConceptRuleMarkLang:
 | 
			
		||||
                "please define namespace first"
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            combo_add = reasoning_po_match.group(5)
 | 
			
		||||
            self.predicate = reasoning_po_match.group(1)
 | 
			
		||||
            self.dst_concept = (
 | 
			
		||||
                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
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        reasoning_spo_match = re.match(
 | 
			
		||||
            r"^\(`?([a-zA-Z0-9\.]+)`?/`([^`]+)`\)-\[([^\]]+)\]->\(`([a-zA-Z0-9\.]+)`/`([^`]+)`\):$",
 | 
			
		||||
            r"^\(`?([a-zA-Z0-9\.]+)`?/`([^`]+)`\)-\[([^\]]+)\]->\(`([a-zA-Z0-9\.]+)`/`([^`]+)`(\+`([^`]+)`)?\):$",
 | 
			
		||||
            expression,
 | 
			
		||||
        )
 | 
			
		||||
        if reasoning_spo_match:
 | 
			
		||||
@ -125,9 +131,12 @@ class SPGConceptRuleMarkLang:
 | 
			
		||||
                reasoning_spo_match.group(2),
 | 
			
		||||
            )
 | 
			
		||||
            self.predicate = reasoning_spo_match.group(3)
 | 
			
		||||
            combo_add = reasoning_po_match.group(7)
 | 
			
		||||
            self.dst_concept = (
 | 
			
		||||
                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
 | 
			
		||||
            return
 | 
			
		||||
@ -215,6 +224,9 @@ class SPGConceptRuleMarkLang:
 | 
			
		||||
                            break
 | 
			
		||||
 | 
			
		||||
            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 (
 | 
			
		||||
                    subject_type is None
 | 
			
		||||
                    and self.predicate is None
 | 
			
		||||
@ -230,7 +242,7 @@ class SPGConceptRuleMarkLang:
 | 
			
		||||
                    head = f"DefinePriority ({object_type})" + " {\n"
 | 
			
		||||
                else:
 | 
			
		||||
                    head = (
 | 
			
		||||
                        f"Define (:{object_type}/`{object_name}`)-[:{predicate_name}]->"
 | 
			
		||||
                        f"Define (:{subject_type}/`{subject_name}`)-[:{predicate_name}]->"
 | 
			
		||||
                        f"(:{object_type}/`{object_name}`)" + " {\n"
 | 
			
		||||
                    )
 | 
			
		||||
            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>
 | 
			
		||||
      <artifactId>reasoner-warehouse-common</artifactId>
 | 
			
		||||
    </dependency>
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>com.antgroup.openspg.reasoner</groupId>
 | 
			
		||||
      <artifactId>reasoner-thinker</artifactId>
 | 
			
		||||
    </dependency>
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>com.antgroup.openspg.reasoner</groupId>
 | 
			
		||||
      <artifactId>reasoner-cloudext-warehouse</artifactId>
 | 
			
		||||
 | 
			
		||||
@ -13,13 +13,6 @@
 | 
			
		||||
 | 
			
		||||
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.TypeReference;
 | 
			
		||||
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.ParseException;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class LocalReasonerMain {
 | 
			
		||||
@ -149,36 +141,36 @@ public class LocalReasonerMain {
 | 
			
		||||
    try {
 | 
			
		||||
      cmd = parser.parse(options, args);
 | 
			
		||||
 | 
			
		||||
      String logFileName = cmd.getOptionValue(LOG_FILE_OPTION);
 | 
			
		||||
      setUpLogFile(logFileName);
 | 
			
		||||
      String logFileName = cmd.getOptionValue(ParamsKey.LOG_FILE_OPTION);
 | 
			
		||||
      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)) {
 | 
			
		||||
        throw new ParseException("please provide query dsl!");
 | 
			
		||||
      }
 | 
			
		||||
      outputFile = cmd.getOptionValue(OUTPUT_OPTION);
 | 
			
		||||
      outputFile = cmd.getOptionValue(ParamsKey.OUTPUT_OPTION);
 | 
			
		||||
      if (StringUtils.isEmpty(outputFile)) {
 | 
			
		||||
        outputFile = null;
 | 
			
		||||
      }
 | 
			
		||||
      schemaUri = cmd.getOptionValue(SCHEMA_URL_OPTION);
 | 
			
		||||
      schemaUri = cmd.getOptionValue(ParamsKey.SCHEMA_URL_OPTION);
 | 
			
		||||
      if (StringUtils.isEmpty(schemaUri)) {
 | 
			
		||||
        throw new ParseException("please provide openspg schema uri!");
 | 
			
		||||
      }
 | 
			
		||||
      graphLoaderClass = cmd.getOptionValue(GRAPH_LOADER_CLASS_OPTION);
 | 
			
		||||
      graphStateClass = cmd.getOptionValue(GRAPH_STATE_CLASS_OPTION);
 | 
			
		||||
      graphStateUrl = cmd.getOptionValue(GRAPH_STORE_URL_OPTION);
 | 
			
		||||
      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 startIdListJson = cmd.getOptionValue(START_ID_OPTION);
 | 
			
		||||
      String startIdListJson = cmd.getOptionValue(ParamsKey.START_ID_OPTION);
 | 
			
		||||
      if (StringUtils.isBlank(startIdListJson)) {
 | 
			
		||||
        startIdList = Collections.emptyList();
 | 
			
		||||
      } else {
 | 
			
		||||
        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)) {
 | 
			
		||||
        params = new HashMap<>(JSON.parseObject(paramsJson));
 | 
			
		||||
      }
 | 
			
		||||
@ -203,81 +195,33 @@ public class LocalReasonerMain {
 | 
			
		||||
    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() {
 | 
			
		||||
    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(
 | 
			
		||||
        GRAPH_STORE_URL_OPTION, GRAPH_STORE_URL_OPTION, true, "graph store url");
 | 
			
		||||
    options.addOption(START_ID_OPTION, START_ID_OPTION, true, "start id list");
 | 
			
		||||
    options.addOption(PARAMs_OPTION, PARAMs_OPTION, true, "params");
 | 
			
		||||
    options.addOption(LOG_FILE_OPTION, LOG_FILE_OPTION, true, "log file name");
 | 
			
		||||
        ParamsKey.PROJECT_ID_OPTION, ParamsKey.PROJECT_ID_OPTION, true, "project id");
 | 
			
		||||
    options.addRequiredOption(
 | 
			
		||||
        ParamsKey.QUERY_OPTION, ParamsKey.QUERY_OPTION, true, "query dsl string");
 | 
			
		||||
    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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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.biz.common.util.AssertUtils;
 | 
			
		||||
import com.antgroup.openspg.server.biz.schema.ConceptManager;
 | 
			
		||||
import com.google.common.collect.Lists;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
@ -73,7 +74,8 @@ public class ConceptController extends BaseController {
 | 
			
		||||
 | 
			
		||||
          @Override
 | 
			
		||||
          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