diff --git a/.dumi/pages/.download.en-US.tsx b/.dumi/pages/download.en-US.tsx similarity index 100% rename from .dumi/pages/.download.en-US.tsx rename to .dumi/pages/download.en-US.tsx diff --git a/.dumi/pages/.index.en-US.tsx b/.dumi/pages/index.en-US.tsx similarity index 100% rename from .dumi/pages/.index.en-US.tsx rename to .dumi/pages/index.en-US.tsx diff --git a/.dumi/pages/.openkg.en-US.tsx b/.dumi/pages/openkg.en-US.tsx similarity index 100% rename from .dumi/pages/.openkg.en-US.tsx rename to .dumi/pages/openkg.en-US.tsx diff --git a/.dumirc.ts b/.dumirc.ts index d254afc..dcb429e 100644 --- a/.dumirc.ts +++ b/.dumirc.ts @@ -39,10 +39,10 @@ export default defineConfig({ content: '语义增强可编程知识图谱SPG', }, ], - // locales: [ - // { id: 'zh-CN', name: '中文' }, - // { id: 'en-US', name: 'English' }, - // ], + locales: [ + { id: 'zh-CN', name: '中文' }, + { id: 'en-US', name: 'English' }, + ], logo: 'https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*D5uYQpLS8dsAAAAAAAAAAAAADtmcAQ/original', ...(process.env.NODE_ENV === 'production' ? ProductionConfig : {}), }); diff --git a/docs/_example/enterprise-supply-chain/builder.md b/docs/_example/enterprise-supply-chain/builder.md deleted file mode 100644 index 6a425cc..0000000 --- a/docs/_example/enterprise-supply-chain/builder.md +++ /dev/null @@ -1,245 +0,0 @@ ---- -title: 知识构建 -order: 3 ---- - -本例中数据均为结构化数据,本例中主要需要两个部分能力: - -- 结构化Mapping:原始数据和schema定义表字段并不完全一致,需要定义数据字段映射过程 -- 实体链指:在关系构建中,实体链指是非常重要的建设手段,本例演示一个简单case,实现公司的链指能力 - -## 1 源数据到SPG数据的Mapping能力 - -以导入company数据为例: - -```yaml -id,name,products -CSF0000000254,北大*药*份限公司,"医疗器械批发,医药批发,制药,其他化学药品" -``` - -导入company的代码如下,详细内容如注释: - -````python -# -*- coding: utf-8 -*- - -from knext.core.builder.pipeline.builder_job import BuilderJob -from knext.core.builder.pipeline.model.component import SourceCsvComponent, SinkToKgComponent, EntityMappingComponent, \ -RelationMappingComponent - -# 导入基本信息任务,必须继承BuilderJob -class Company(BuilderJob): - # 并行化参数 - parallelism = 6 - - ``` - 返回构建任务pipeline,每个导入任务都需要有一个source节点,一个sink节点 - 这里mappiing节点为一个结构化数据映射节点 - ``` - def build(self): - source = SourceCsvComponent( - # 指定数据源地址 - local_path="./builder/task/data/Company.csv", - columns=["id", "name", "products"], - start_row=2 - ) - - # spg_type_name代表是向哪个数据类型导入 - # add_field表示从数据源的哪个字段导入到schema中定义的哪个字段 - mapping = EntityMappingComponent( - spg_type_name="DEFAULT.Company" - ).add_field("id", "id") \ - .add_field("name", "name") \ - .add_field("products", "product") - - # sink节点,使用系统的图谱节点 - sink = SinkToKgComponent() - - return source >> mapping >> sink - - -# 导入公司间的资金关系 -class CompanyFundTrans(BuilderJob): - - ``` - 和基本信息导入类似,此处RelationMappingComponent代表关系隐射节点 - ``` - def build(self): - source = SourceCsvComponent( - local_path="./builder/task/data/Company_fundTrans_Company.csv", - columns=["src", "dst", 'transDate', 'transAmt'], - start_row=2 - ) - - # 关系映射节点需要指定是哪条具体关系 - # add_field表示从数据源的哪个字段导入到schema中定义的哪个字段 - mapping = RelationMappingComponent( - subject_name='DEFAULT.Company', - predicate_name='fundTrans', - object_name='DEFAULT.Company' - ).add_field("src", "srcId") \ - .add_field("dst", "dstId") \ - .add_field("transDate", 'transDate') \ - .add_field('transAmt', 'transAmt') - - sink = SinkToKgComponent() - - return source >> mapping >> sink - -```` - -在knext中执行如下命令提交任务: - -```shell -knext builder submit Company,CompanyFundTrans -``` - -一般情况下这种映射关系基本能够满足结构化数据导入,但在一些场景下可能需要对数据进行部分数据才能满足要求,此时就需要实现自定义算子来处理问题。 - -## 2 自定义算子实现链指能力 - -例如如下数据: - -```python -id,name,age,legalRep -0,路**,63,"新疆*花*股*限公司,三角*胎股*限公司,传化*联*份限公司" -``` - -legalRep字段为公司名字,但在系统中已经将公司id设置成为主键,直接通过公司名是无法关联到具体公司,假定存在一个搜索服务,可将公司名转换为id,此时需要自定开发一个链指算子,实现该过程的转换。 - -算子放在如下目录: - -```python -|_event - |_builder - |_operator - |_company_operator.py -``` - -具体实现代码如下: - -```python -# -*- coding: utf-8 -*- - -from typing import List - -import requests - -from knext.core.builder.operator import Vertex, EvalResult -from knext.core.builder.operator.model.op import EntityLinkOp -from knext.core.wrapper.search_client import SearchClient - - -def llm_infer(word, recall): - """ - Here is the implement of LLM inferring - """ - - prompt_text = f'你作为一个语言专家,请在目标词里选出跟输入词意思最相近的一个词,如果没有意思相近的则输出null。\n要求:输出结果直接显示选中的目标词,不需要给出选择的任何理由。\n输入词:{word}。\n目标词:[{recall}]。' - param = { - "prompt": prompt_text, - "history": None - } - llm_response = requests.post('http://127.0.0.1:8888', json=param) - if llm_response.status_code == 200: - content = llm_response.content - if content.startswith("输出结果:"): - return content[content.index(":") + 1:].strip().rstrip("。") - else: - return "null" - -# 必须继承EntityLinkOp 才为链指算子 -class CompanyLinkerOperator(EntityLinkOp): - # 绑定到SupplyChain.Company类型,所有链指到该实体的关系均会进行链指操作 - bind_to = "SupplyChain.Company" - - def __init__(self): - super().__init__() - self.search_client = SearchClient("SupplyChain.Company") - # 默认关闭大模型精排能力 - self.enable_llm = False - - def eval(self, record: Vertex) -> EvalResult[List[Vertex]]: - company_name = record.properties["company"] - query = {"match": {"name": company_name}} - recalls = self.search_client.search(query, 0, 30) - if recalls is not None: - if recalls[0].score < 0.6: - # Low similarity, discard recall results - return EvalResult([]) - - if company_name == recalls[0].properties["name"]: - # If the result of Top1 is the same as the attribute value, then returned directly - return EvalResult([Vertex(biz_id=recalls[0].doc_id, vertex_type="SupplyChain.Company")]) - - # Perform fine-ranking on coarse recall results by calling LLM - if not self.enable_llm: - return EvalResult([Vertex(biz_id=recalls[0].doc_id, vertex_type="SupplyChain.Company")]) - - recall_dict = {} - for item in recalls: - recall_dict[item.properties["name"]] = item.doc_id - recall_str = ",".join(recall_dict.keys()) - - # ----- Please enable the code below when LLM service is ready ------ - llm_result = llm_infer(company_name, recall_str) - if len(llm_result) > 0 and llm_result != "null": - return EvalResult([Vertex(biz_id=recall_dict[llm_result], vertex_type="SupplyChain.Company")]) - - return EvalResult([]) - -``` - -执行如下命令提交: - -```shell -knext operator publish CompanyLinkerOperator -``` - -提交完成后,person构建只需按照正常mapping流程即可,如下person代码: - -```python -# -*- coding: utf-8 -*- - -# Copyright 2023 Ant Group CO., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except -# in compliance with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed under the License -# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. - -from knext.core.builder.job.builder import BuilderJob -from knext.core.builder.job.model.component import SourceCsvComponent, SinkToKgComponent, RelationMappingComponent, - EntityMappingComponent -from knext.examples.supplychain.schema.supplychain_schema_helper import SupplyChain - - -class Person(BuilderJob): - - def build(self): - source = SourceCsvComponent( - local_path="./builder/job/data/Person.csv", - columns=["id", 'name', 'age', 'legalRep'], - start_row=2 - ) - - mapping = EntityMappingComponent( - spg_type_name=SupplyChain.Person - ).add_field("id", SupplyChain.Person.id) - .add_field("name", SupplyChain.Person.name) - .add_field("age", SupplyChain.Person.age) - .add_field("legalRep", SupplyChain.Person.legalRepresentative) - - sink = SinkToKgComponent() - - return source >> mapping >> sink -``` - -最后提交person任务即可: - -```shell -knext builder submit Person -``` diff --git a/docs/_example/enterprise-supply-chain/data.md b/docs/_example/enterprise-supply-chain/data.md deleted file mode 100644 index d1b3f2d..0000000 --- a/docs/_example/enterprise-supply-chain/data.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -title: 数据介绍 -order: 2 ---- - -## 1 数据目录 - -``` -|_supplychain - |_builder - |_job - |__data - |_Company.csv // 存放公司数据 - |_Company_fundTrans_Company.csv //公司转账关系 - |_Person.csv //人相关数据 - |_Industry.csv //行业类目概念数据 - |_Product.csv //产品类目概念数据 - |_Index.csv //指标类目概念数据 - |_Trend.csv //趋势类目概念数据 - |_ProductChainEvent.csv //产业链事件 - |_TaxOfCompanyEvent.csv //公司事件分类数据 - |_TaxOfProdEvent.csv //产业链产品事件分类数据 -``` - -分别抽样部分数据进行介绍。 - -## 2 公司数据(Company.csv) - -``` -id,name,products -CSF0000002238,三角*胎股*限公司,"轮胎,全钢子午线轮胎" -``` - -- id:公司在系统中的唯一id -- name:公司名 -- products:公司生产的产品,使用逗号分隔 - -## 3 公司资金转账(Company_fundTrans_Company.csv) - -``` -src,dst,transDate,transAmt -CSF0000002227,CSF0000001579,20230506,73 -``` - -- src:转出方 -- dst:转入方 -- transDate:转账日期 -- transAmt:转账总金额 - -## 4 法人代表(Person.csv) - -``` -id,name,age,legalRep -0,路**,63,"新疆*花*股*限公司,三角*胎股*限公司,传化*联*份限公司" -``` - -- id:自然人在系统中唯一标识 -- name:姓名 -- age:年龄 -- legalRep:法人代表公司名字 - -## 5 产业类目概念(Industry.csv) - -``` -fullname -能源 -能源-能源 -能源-能源-能源设备与服务 -能源-能源-能源设备与服务-能源设备与服务 -能源-能源-石油、天然气与消费用燃料 -``` - -产业只有名字,其中段横线代表其上位概念,例如“能源-能源-能源设备与服务”的上位概念是“能源-能源”;“能源-能源-能源设备与服务-能源设备与服务”的上位概念为“能源-能源-能源设备与服务”。 - -## 6 产品类目概念(Product.csv) - -``` -fullname,belongToIndustry,hasSupplyChain -商品化工-橡胶-合成橡胶-顺丁橡胶,原材料-原材料-化学制品-商品化工,"化工商品贸易-化工产品贸易-橡塑制品贸易,轮胎与橡胶-轮胎,轮胎与橡胶-轮胎-特种轮胎,轮胎与橡胶-轮胎-工程轮胎,轮胎与橡胶-轮胎-斜交轮胎,轮胎与橡胶-轮胎-全钢子午线轮胎,轮胎与橡胶-轮胎-半钢子午线轮胎" -``` - -- fullname:产品名,同样通过段横线分隔上下位 -- belongToIndustry:所归属的行业,例如本例中,顺丁橡胶属于商品化工 -- hasSupplyChain:是其下游产业,例如顺丁橡胶下游产业有轮胎、橡塑制品贸易等 - -## 7 产业链事件(ProductChainEvent.csv) - -``` -id,name,subject,index,trend -1,顺丁橡胶成本上涨,商品化工-橡胶-合成橡胶-顺丁橡胶,价格,上升 -``` - -- id:事件的id -- name:事件的名字 -- subject:事件的主体,本例为顺丁橡胶 -- index:指标,本例为价格 -- trend:趋势,本例为上升 - -## 8 指标(Index.csv)和趋势(Trend.csv) - -趋势、指标作为原子概念类目,可组合成产业链事件和公司事件。 - -- 趋势,值域为:上涨、下跌 -- 指标,值域为:价格、成本、利润 - -## 9 事件分类(TaxOfCompanyEvent.csv、TaxOfProdEvent.csv) - -事件分类包括产业链事件分类和公司事件分类,数据为: - -- 产业链事件分类,值域:价格上涨 -- 公司事件分类,值域:成本上升 diff --git a/docs/_example/enterprise-supply-chain/index.md b/docs/_example/enterprise-supply-chain/index.md deleted file mode 100644 index 936fdaa..0000000 --- a/docs/_example/enterprise-supply-chain/index.md +++ /dev/null @@ -1,164 +0,0 @@ ---- -title: 企业供应链 -nav: - second: - title: 企业供应链 - order: 2 ---- - -## 1 背景 - -信贷机构对企业的财务状况、经营状况、市场地位、管理能力等进行综合分析,给予企业一个评级等级,反映其信用状况的好坏,以便支撑信贷业务。在实践中基本依赖被评估企业自身提供的信息,例如企业年报、各类资质文件、资产证明等,这一类信息只能围绕企业自身提供微观层面的信息,不能体现企业在整个产业链上下游市场情况,也无法得到证明之外的信息。 - -本例基于SPG构建产业链企业图谱,挖掘出企业之间基于产业链的深度信息,支持企业信用评级。 - -## 2 总览 - -建模参考文件[企业供应链图谱schema](https://github.com/OpenSPG/openspg/blob/master/python/knext/examples/supplychain/schema/supplychain.schema),如下图实例 - -![产业链企业图谱深度语义关联](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*J_NpRoNbO-YAAAAAAAAAAAAADtmcAQ/original) - -
图1:产业链企业图谱深度语义关联
- -概念知识维护着产业链相关数据,包括上下位层级、供应关系;实体实例仅有法人代表、转账信息,公司实例通过生产的产品属性和概念中的产品节点挂载,实现了公司实例之间的深度信息挖掘,例如供应商、同行业、同法人代表等关系。基于深度上下文信息,可提供更多的信用评估因子。 - -![产业链事件归纳演绎 ](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*X2TES7hf9ycAAAAAAAAAAAAADtmcAQ/original) - -
图2:产业链事件归纳演绎
- -产业链中建立了产品和公司事件类别,该类别属于指标和趋势的一种组合,例如价格上涨,是由指标:价格,趋势:上涨两部分构成。 -事理知识设定了产品价格上涨引起公司利润下降及公司成本上涨事件,当发生某个具体事件时,例如“橡胶价格大涨事件”,被归类在产品价格上涨,由于事理知识中定义产品价格上涨会引起公司利润下降/公司成本上涨两个事件类型,会产出新事件:“三角\*\*轮胎公司成本上涨事件”、“三角\*\*轮胎公司利润下跌”。 - -## 3 Quick Start - -### Step1:进入案例目录 - -```shell - cd python/knext/examples/supplychain/ -``` - -### Step2:项目初始化 - -先对项目进行初始化动作 - -```cypher -knext project create --prj_path . -``` - -### Step3:知识建模 - -schema文件已创建好,可执行如下命令提交 - -```shell -knext schema commit -``` - -```shell -# 提交公司事件分类数据 -knext builder submit TaxOfCompanyEvent -# 提交产品事件分类数据 -knext builder submit TaxOfProdEvent -``` - -执行查询任务命令,等待任务完成 - -```shell -knext builder get --id ${jobId} -``` - -其中jobId为提交后返回的id - -```shell -# 提交导致关系逻辑规则 -knext schema reg_concept_rule --file ./schema/concept.rule -``` - -schema建模详细内容可参见 [基于SPG建模的产业链企业图谱](./model.md) - -### Step4:知识构建 - -知识构建将数据导入到系统中,数据介绍参见文档[产业链案例数据介绍](./data.md)。 - -本例主要为结构化数据,故演示结构化数据转换和实体链指,具体细节可参见文档[产业链案例知识构建](./builder.md)。 - -**第一步:提交自定义实体链指算子** - -```shell -knext operator publish CompanyLinkerOperator -``` - -**第二步:提交知识导入任务** - -```shell -knext builder submit Index,Trend -knext builder submit Industry,Product,ProductHasSupplyChain -knext builder submit Company,CompanyFundTrans,Person -``` - -最后提交事件 - -```shell -knext builder submit ProductChainEvent -``` - -### Step5:执行图谱任务 - -SPG支持ISO GQL写法,可用如下命令行执行查询任务 - -```cypher -knext reasoner query --dsl "${ql}" -``` - -具体任务详情可参见文档[产业链企业信用图谱查询任务](./query.md)。 - -信用评级因子获取: - -```cypher -knext reasoner query --dsl " -MATCH - (s:SupplyChain.Company) -RETURN - s.id, s.name, s.fundTrans1Month, s.fundTrans3Month, - s.fundTrans6Month, s.fundTrans1MonthIn, s.fundTrans3MonthIn, - s.fundTrans6MonthIn, s.cashflowDiff1Month, s.cashflowDiff3Month, - s.cashflowDiff6Month -" -``` - -```cypher -knext reasoner query --dsl " -MATCH - (s:SupplyChain.Company)-[:mainSupply]->(o:SupplyChain.Company) -RETURN - s.name, o.name -" -``` - -```cypher -knext reasoner query --dsl " -MATCH - (s:SupplyChain.Company)-[:belongToIndustry]->(o:SupplyChain.Industry) -RETURN - s.name, o.name -" -``` - -```cypher -knext reasoner query --dsl " -MATCH - (s:SupplyChain.Company)-[:sameLegalRepresentative]->(o:SupplyChain.Company) -RETURN - s.name, o.name -" -``` - -事件影响分析: - -```cypher -knext reasoner query --dsl " -MATCH - (s:SupplyChain.ProductChainEvent)-[:leadTo]->(o:SupplyChain.CompanyEvent) -RETURN - s.id,s.subject,o.subject,o.name -" -``` diff --git a/docs/_example/enterprise-supply-chain/model.md b/docs/_example/enterprise-supply-chain/model.md deleted file mode 100644 index 01676a0..0000000 --- a/docs/_example/enterprise-supply-chain/model.md +++ /dev/null @@ -1,191 +0,0 @@ ---- -title: 知识建模 -order: 1 ---- - -## 1 建模文件 - -建模描述文档参见[spg schema](../../tutorial_deprecated/spgschema/index.md)。 - -建模参考文件[企业供应链图谱schema](https://github.com/OpenSPG/openspg/blob/master/python/knext/examples/supplychain/schema/supplychain.schema)。 - -执行以下脚本,完成schema创建: - -``` -knext schema commit -``` - -## 2 SPG建模方法 vs 属性图建模方法 - -本节对比 SPG语义建模 和 普通建模的差异。 - -### 2.1 语义属性 vs 文本属性 - -假定存在如下公司信息:"北大*药*份限公司"生产的产品有四个"医疗器械批发,医药批发,制药,其他化学药品"。 - -``` -id,name,products -CSF0000000254,北大*药*份限公司,"医疗器械批发,医药批发,制药,其他化学药品" -``` - -#### 2.1.1 基于文本属性建模 - -```yaml -//文本属性建模 -Company(企业): EntityType - properties: - product(经营产品): Text -``` - -此时经营产品只为文本,不包含语义信息,是无法得到“北大*药*份限公司”的上下游产业链相关信息,极不方便维护也不方便使用。 - -#### 2.1.2 基于关系建模 - -若期望能对经营产品进行较好的维护管理,一般是将产品作为实体存在,将公司和产品通过关系关联起来。 - -```yaml -Product(产品): EntityType - properties: - name(产品名): Text - relations: - isA(上位产品): Product - -Company(企业): EntityType - relations: - product(经营产品): Product -``` - -但如此建模,则需要将数据分为3列: - -``` -id,name,product -CSF0000000254,北大*药*份限公司,医疗器械批发 -CSF0000000254,北大*药*份限公司,医药批发 -CSF0000000254,北大*药*份限公司,制药 -CSF0000000254,北大*药*份限公司,其他化学药品 -``` - -这种方式也存在两个缺点: - -1)原始数据需要做一次清洗,转换成多行。 - -2)需要新增维护关系数据,当原始数据发生变更时,需要删除原有关系,再新增数据,容易导致数据错误。 - -#### 2.1.3 基于SPG语义属性建模 - -SPG支持语义属性,可简化知识构建,如下: - -```yaml -Product(产品): ConceptType - hypernymPredicate: isA - -Company(企业): EntityType - properties: - product(经营产品): Product - constraint: MultiValue -``` - -企业中具有一个经营产品属性,且该属性的类型为Product类型,只需将如下数据导入,可自动实现属性到关系的转换。 - -``` -id,name,products -CSF0000000254,北大*药*份限公司,"医疗器械批发,医药批发,制药,其他化学药品" -``` - -### 2.2 逻辑表达的属性、关系 vs 数据表达的属性、关系 - -假定需要得到企业所在行业,根据当前已有数据,可执行如下查询语句: - -``` -MATCH - (s:Company)-[:product]->(o:Product)-[:belongToIndustry]->(i:Industry) -RETURN - s.id, i.id -``` - -该方式需要熟悉图谱schema,对人员上手要求比较高,故也有一种实践是将这类属性重新导入图谱,如下: - -```yaml -Company(企业): EntityType - properties: - product(经营产品): Product - constraint: MultiValue - relations: - belongToIndustry(所在行业): Industry -``` - -新增一个关系类型,来直接获取公司所属行业信息。 - -这种方式缺点主要有两个: - -- 需要用户手动维护新增关系数据,增加使用维护成本 -- 由于新关系和图谱数据存在来源依赖,非常容易导致图谱数据出现不一致问题 - -针对上述缺点,SPG支持逻辑表达属性和关系,如下建模方式: - -```yaml -Company(企业): EntityType - properties: - product(经营产品): Product - constraint: MultiValue - relations: - belongToIndustry(所在行业): Industry - rule: [[ - Define (s:Company)-[p:belongToIndustry]->(o:Industry) { - Structure { - (s)-[:product]->(c:Product)-[:belongToIndustry]->(o) - } - Constraint { - } - } - ]] -``` - -具体内容可参见[查询任务](./query.md)场景一、场景二的示例。 - -### 2.3 概念体系 vs 实体体系 - -现有图谱方案也有常识图谱,例如ConceptNet等,但在业务落地中,不同业务有各自体现业务语义的类目体系,基本上不存在一个常识图谱可应用到所有业务场景,故常见的实践为将业务领域体系创建为实体,和其他实体数据混用,这就导致在同一个分类体系上,既要对schema的扩展建模,又要对语义上的细分类建模,数据结构定义和语义建模的耦合,导致工程实现及维护管理的复杂性,也增加了业务梳理和表示(认知)领域知识的困难。 - -SPG区分了概念和实体,用于解耦语义和数据,如下: - -```yaml -Product(产品): ConceptType - hypernymPredicate: isA - -Company(企业): EntityType - properties: - product(经营产品): Product - constraint: MultiValue -``` - -产品被定义为概念,公司被定义为实体,相互独立演进,两者通过SPG提供的语义属性进行挂载关联,用户无需手动维护企业和产品之间关联。 - -### 2.4 事件时空多元表达 - -事件多要素结构表示也是一类超图(HyperGrpah)无损表示的问题,它表达的是时空多元要素的时空关联性,事件是各要素因某种行为而产生的临时关联,一旦行为结束,这种关联也随即消失。在以往的属性图中,事件只能使用实体进行替代,由文本属性表达事件内容,如下类似事件: - -![事件表达](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*pUlGS6-E3lEAAAAAAAAAAAAADtmcAQ/original) - -```yaml -Event(事件): - properties: - eventTime(发生时间): Long - subject(涉事主体): Text - object(客体): Text - place(地点): Text - industry(涉事行业): Text -``` - -这种表达方式,是无法体现真实事件的多元关联性,SPG提供了事件建模,可实现事件多元要素的关联,如下: - -```yaml -CompanyEvent(公司事件): EventType - properties: - subject(主体): Company - index(指标): Index - trend(趋势): Trend - belongTo(属于): TaxOfCompanyEvent -``` - -上述的事件中,属性类型均为已被定义类型,没有基本类型表达,SPG基于此申明实现事件多元要素表达,具体应用示例可见[查询任务](./query.md)中场景3的具体描述。 diff --git a/docs/_example/enterprise-supply-chain/query.md b/docs/_example/enterprise-supply-chain/query.md deleted file mode 100644 index 67e966f..0000000 --- a/docs/_example/enterprise-supply-chain/query.md +++ /dev/null @@ -1,317 +0,0 @@ ---- -title: 查询任务 -order: 4 ---- - -## 场景1:企业信用评级特征生成 - -需求:在企业信用评级中,假定需要得到如下决策因子
-1)主供应商关系
-2)企业生产产品所在行业
-3)企业资金近1月、3月、6月转账流水
-4)企业资金近1月、3月、6月流水差
-5)实控人相关公司信息
-但在原有图谱中,只有资金转账、法人代表信息,无法直接获取上述特征,本例演示如果通过SPG完成如上5个特征获取。
-特征定义在schema文件中,可点击查看[企业供应链图谱schema](https://github.com/OpenSPG/openspg/blob/master/python/knext/examples/supplychain/schema/supplychain.schema)。
- -**特征1:先定义企业和企业间的主供应链关系,规则定义如下** - -``` -Define (s:Compnay)-[p:mainSupply]->(o:Company) { - Structure { - (s)-[:product]->(upProd:Product)-[:hasSupplyChain]->(downProd:Product)<-[:product]-(o), - (o)-[f:fundTrans]->(s) - (otherCompany:Company)-[otherf:fundTrans]->(s) - } - Constraint { - // 计算公司o的转入占比 - otherTransSum("总共转入金额") = group(s).sum(otherf.transAmt) - targetTransSum("o转入的金额总数") = group(s,o).sum(f.transAmt) - transRate = targetTransSum*1.0/(otherTransSum + targetTransSum) - R1("占比必须超过50%"): transRate > 0.5 - } -} -``` - -**特征2:企业生成产品所在行业** - -``` -Define (s:Compnay)-[p:belongToIndustry]->(o:Industry) { - Structure { - (s)-[:product]->(c:Product)-[:belongToIndustry]->(o) - } - Constraint { - } -} -``` - -**特征3:企业资金近1月、3月、6月转账流水** - -``` -// 近1个月流出金额 -Define (s:Compnay)-[p:fundTrans1Month]->(o:Int) { - Structure { - (s)-[f:fundTrans]->(c:Company) - } - Constraint { - R1("近1个月的流出资金"): date_diff(from_unix_time(now(), 'yyyyMMdd'),f.transDate) < 30 - totalOut = group(s).sum(transAmt) - o = totalOut - } -} - -// 近3个月流出金额 -Define (s:Compnay)-[p:fundTrans3Month]->(o:Int) { - Structure { - (s)-[f:fundTrans]->(c:Company) - } - Constraint { - R1("近4个月的流出资金"): date_diff(from_unix_time(now(), 'yyyyMMdd'),f.transDate) < 90 - totalOut = group(s).sum(transAmt) - o = totalOut - } -} - -// 近6个月流出金额 -Define (s:Compnay)-[p:fundTrans6Month]->(o:Int) { - Structure { - (s)-[f:fundTrans]->(c:Company) - } - Constraint { - R1("近5个月的流出资金"): date_diff(from_unix_time(now(), 'yyyyMMdd'),f.transDate) < 180 - totalOut = group(s).sum(transAmt) - o = totalOut - } -} - -// 近1个月流入金额 -Define (s:Compnay)-[p:fundTrans1MonthIn]->(o:Int) { - Structure { - (s)<-[f:fundTrans]-(c:Company) - } - Constraint { - R1("近1个月的流入资金"): date_diff(from_unix_time(now(), 'yyyyMMdd'),f.transDate) < 30 - totalOut = group(s).sum(transAmt) - o = totalOut - } -} - -// 近3个月流入金额 -Define (s:Compnay)-[p:fundTrans3MonthIn]->(o:Int) { - Structure { - (s)<-[f:fundTrans]-(c:Company) - } - Constraint { - R1("近3个月的流入资金"): date_diff(from_unix_time(now(), 'yyyyMMdd'),f.transDate) < 90 - totalOut = group(s).sum(transAmt) - o = totalOut - } -} - - -// 近6个月流入金额 -Define (s:Compnay)-[p:fundTrans6MonthIn]->(o:Int) { - Structure { - (s)<-[f:fundTrans]-(c:Company) - } - Constraint { - R1("近6个月的流入资金"): date_diff(from_unix_time(now(), 'yyyyMMdd'),f.transDate) < 180 - totalOut = group(s).sum(transAmt) - o = totalOut - } -} -``` - -**特征4:企业资金近1月、3月、6月流水差** - -``` -// 近1个月资金流水差 -Define (s:Company)-[p:cashflowDiff1Month]->(o:Integer) { - Structure { - (s) - } - Constraint { - // 此处引用特征3中的规则 - fundTrans1Month = rule_value(s.fundTrans1Month == null, 0, s.fundTrans1Month) - fundTrans1MonthIn = rule_value(s.fundTrans1MonthIn == null, 0, s.fundTrans1MonthIn) - o = fundTrans1Month - fundTrans1MonthIn - } -} - -// 近3个月资金流水差 -Define (s:Company)-[p:cashflowDiff3Month]->(o:Integer) { - Structure { - (s) - } - Constraint { - // 此处引用特征3中的规则 - fundTrans3Month = rule_value(s.fundTrans3Month == null, 0, s.fundTrans3Month) - fundTrans3MonthIn = rule_value(s.fundTrans3MonthIn == null, 0, s.fundTrans3MonthIn) - o = fundTrans3Month - fundTrans3MonthIn - } -} - -// 近6个月资金流水差 -Define (s:Company)-[p:cashflowDiff6Month]->(o:Integer) { - Structure { - (s) - } - Constraint { - fundTrans6Month = rule_value(s.fundTrans6Month == null, 0, s.fundTrans6Month) - fundTrans6MonthIn = rule_value(s.fundTrans6MonthIn == null, 0, s.fundTrans6MonthIn) - o = fundTrans6Month - fundTrans6MonthIn - } -} -``` - -**特征5:同实控人公司** - -``` -// 定义同法人关系 -Define (s:Compnay)-[p:sameLegalReprensentative]->(o:Company) { - Structure { - (s)<-[:legalReprensentative]-(u:Person)-[:legalReprensentative]->(o) - } - Constraint { - } -} -``` - -通过如下GQL执行得到某个公司的具体特征: - -``` -MATCH - (s:SupplyChain.Company) -RETURN - s.id, s.fundTrans1Month, s.fundTrans3Month, - s.fundTrans6Month, s.fundTrans1MonthIn, s.fundTrans3MonthIn, - s.fundTrans6MonthIn, s.cashflowDiff1Month, s.cashflowDiff3Month, s.cashflowDiff6Month -``` - -``` -MATCH - (s:SupplyChain.Company)-[:mainSupply]->(o:SupplyChain.Company) -RETURN - s.id, o.id -``` - -``` -MATCH - (s:SupplyChain.Company)-[:belongToIndustry]->(o:SupplyChain.Industry) -RETURN - s.id, o.id -``` - -``` -MATCH - (s:SupplyChain.Company)-[:sameLegalRepresentative]->(o:SupplyChain.Company) -RETURN - s.id, o.id -``` - -## 场景2:企业供应链发生变化 - -假设供应链发生如下变化:
- -``` -"钱****份限公司"发布公告,生产产品“三轮摩托车,二轮摩托车”变更为“两轮摩托车”,则"三角**轮胎股份"和钱"****份限公司"的主供应链关系自动断裂,"三角**轮胎股份"和"钱****份限公司"不再具有主供应链关系 -``` - -变更后的数据存在CompanyUpdate.csv: - -```cypher -id,name,products -CSF0000001662,浙江**摩托**限公司,"汽车-摩托车制造-二轮摩托车" -``` - -重新提交任务: - -```cypher -knext builder submit CompanyUpdate -``` - -执行完成后再次查询,只会返回二轮摩托车,而三轮摩托车不再被关联: - -``` -MATCH - (s:SupplyChain.Company)-[:product]->(o:SupplyChain.Product) -WHERE - s.id = "CSF0000001662" -RETURN - s.id, o.id -``` - -## 场景3:产业链影响 - -事件内容如下: - -``` -id,name,subject,index,trend -1,顺丁橡胶成本上涨,商品化工-橡胶-合成橡胶-顺丁橡胶,价格,上涨 -``` - -提交事件数据: - -``` -knext builder submit ProductChainEvent -``` - -传导链路如下:
-![image.png](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*mJWRQJek1BsAAAAAAAAAAAAADtmcAQ/original)
-顺丁橡胶成本上升,被分类为产业链价格上涨事件,如下DSL: - -``` -// ProductChainEvent为一个具体的事件实例,当其属性满足价格上涨条件时,该事件分类为价格上涨事件 -Define (e:ProductChainEvent)-[p:belongTo]->(o:`TaxonofProductChainEvent`/`价格上涨`) { - Structure { - } - Constraint { - R1: e.index == '价格' - R2: e.trend == '上涨' - } -} -``` - -产业链价格上涨,在如下条件下,会导致特定公司的成本上升 - -``` -// 定义了价格上涨和企业成本上升的规则 -Define (s:`TaxonofProductChainEvent`/`价格上涨`)-[p:leadTo]->(o:`TaxonofCompanyEvent`/`成本上涨`) { - Structure { - //1、找到产业链事件的主体,本例中为顺丁橡胶 - //2、找到顺丁橡胶的下游产品,本例中为斜交轮胎 - //3、找到生成斜交轮胎的所有企业,本例中为三角**轮胎股份 - (s)-[:subject]->[prod:Product]-[:hasSupplyChain]->(down:Product)<-[:product]-(c:Company) - } - Constraint { - } - Action { - // 创建一个公司成本上升事件,主体为查询得到的三角**轮胎股份 - downEvent = createNodeInstance( - type=CompanyEvent, - value={ - subject=c.id - trend="上涨" - index="成本" - } - ) - // 由于这个事件是通过产业链价格上涨引起,故在两者之间增加一条边 - createEdgeInstance( - src=s, - dst=downEvent, - type=leadTo, - value={ - } - ) - } -} -``` - -可通过如下查询语句查出某个事件产生的影响 - -```cypher -MATCH - (s:SupplyChain.ProductChainEvent)-[:leadTo]->(o:SupplyChain.CompanyEvent) -RETURN - s.id,s.subject,o.subject,o.name -``` diff --git a/docs/_example/index.md b/docs/_example/index.md deleted file mode 100644 index b22337c..0000000 --- a/docs/_example/index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: 案例 -order: 3 -nav: - title: 案例 - order: 3 ---- - - diff --git a/docs/_example/medical/index.md b/docs/_example/medical/index.md deleted file mode 100644 index 3165c44..0000000 --- a/docs/_example/medical/index.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: 医疗领域 -nav: - second: - title: 医疗领域 - order: 3 ---- - -## 从文本构建医疗图谱 - -本示例旨在展示如何基于SPG-Schema的定义,利用大模型实现对图谱实体和关系的抽取和构建到图谱。 -![image.jpg](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*-PKySKstgy8AAAAAAAAAAAAADtmcAQ/original) - -## 1 Quick Start - -### Step1:进入案例目录 - -```shell - cd python/knext/examples/medical/ -``` - -### Step2:项目初始化 - -先对项目进行初始化动作 - -```shell -knext project create --prj_path . -``` - -### Step3:知识建模 - -schema文件已创建好[医疗SPG Schema模型](https://github.com/OpenSPG/openspg/blob/master/python/knext/examples/medical/schema/medical.schema),可执行如下命令提交 - -```shell -knext schema commit -``` - -```shell -# 提交人体部位和医院部门概念导入任务 -knext builder submit BodyPart,HospitalDepartment -``` - -### step4:知识抽取构建 - -**第一步:提交自定义的疾病实体类型的抽取算子** - -```shell -knext operator publish DiseaseExtractor -``` - -**第二步【可选】:大模型(ChatGLM2)微调** - -**1、训练样本准备** - -针对ChatGLM2模型,只需要准备相对结构化的sample数据,可以通过提供的sample转换工具`convert_util.py`,拉取spg schema信息,自动生成模型微调可接收的训练样本。 - -```shell -python builder/model/dataset/convert_util.py \ - --entity_type Medical.Disease \ - --task_type RE \ - --src_path builder/model/dataset/RE/sample.json \ - --tgt_path builder/model/dataset/RE/processed.json \ - --template_path schema/prompt.json -``` - -**2、模型微调** - -执行以下命令,使用 [p-tuning-v2](https://github.com/THUDM/ChatGLM2-6B/tree/main/ptuning#p-tuning-v2) 对模型参数进行微调 - -```shell -sh builder/model/train.sh -``` - -**第三步:部署大模型(ChatGLM2)推理服务** - -将p-tuning的结果参数文件覆盖原模型参数文件,并执行以下命令部署模型服务 - -```bash -sh builder/model/deploy.sh -``` - -**第四步:提交知识抽取任务** - -```bash -knext builder submit Disease -``` - -### step5:执行图谱任务 - -SPG支持ISO GQL写法,可用如下命令行执行查询任务 - -```cypher -knext reasoner query --dsl " -MATCH - (s:Medical.Disease)-[p]->(o) -RETURN - s -" -``` diff --git a/docs/_example/risk-mining/index.md b/docs/_example/risk-mining/index.md deleted file mode 100644 index 497f394..0000000 --- a/docs/_example/risk-mining/index.md +++ /dev/null @@ -1,199 +0,0 @@ ---- -title: 黑产挖掘 -nav: - second: - title: 黑产挖掘 - order: 1 ---- - -## 黑产挖掘图谱 - -关键词:语义属性,实体动态多分类,面向业务知识和事实数据分层下的知识应用 - -![image.png](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*KGmMRJvQEdQAAAAAAAAAAAAADtmcAQ/original) - -## Quick Start - -### step1:进入案例目录 - -```shell - cd python/knext/examples/riskmining/ -``` - -### step2:项目初始化 - -先对项目进行初始化动作 - -```cypher -knext project create --prj_path . -``` - -### step3:知识建模 - -schema文件已创建好[黑产SPG Schema模型](https://github.com/OpenSPG/openspg/blob/master/python/knext/examples/riskmining/schema/riskmining.schema),可执行如下命令提交 - -```shell -knext schema commit -``` - -```shell -# 提交风险用户、风险APP的分类概念 -knext builder submit TaxOfRiskUser,TaxOfRiskApp -knext schema reg_concept_rule --file ./schema/concept.rule -``` - -### step4:知识构建 - -**第一步:提交自定义实体链指算子** - -```shell -knext operator publish CertLinkerOperator -``` - -**第二步:提交知识导入任务** - -```bash -knext builder submit Cert,Company,CompanyHasCert -knext builder submit App,Device,Person,PersonFundTrans,PersonHasDevice,PersonHoldShare -``` - -### step5:执行图谱任务 - -SPG支持ISO GQL写法,可用如下命令行执行查询任务 - -```cypher -knext reasoner query --dsl "${ql}" -``` - -#### 场景1:语义属性对比文本属性 - -![image.png](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*uKcjRqTdy7cAAAAAAAAAAAAADtmcAQ/original) - -电话号码:标准属性 vs 文本属性。 - -编辑dsl_task.txt,输入如下内容: - -``` -MATCH - (phone:STD.ChinaMobile)<-[:hasPhone]-(u:RiskMining.Person) -RETURN - u.id,phone.id -``` - -执行脚本: - -``` -knext reasoner query --file ./reasoner/dsl_task.dsl -``` - -#### 场景2:实体动态多类型 - -注意:本节定义的分类规则已经在前面的“step3:知识建模”章节里通过命令`knext schema reg_concept_rule`提交。 - -以下规则的详细内容也可以在:[黑产分类概念规则](https://github.com/OpenSPG/openspg/blob/master/python/knext/examples/riskmining/schema/concept.rule) 中查看。 - -**赌博App的分类** - -``` -Define (s:App)-[p:belongTo]->(o:`TaxOfRiskApp`/`赌博应用`) { - Structure { - (s) - } - Constraint { - R1("风险标记为赌博") s.riskMark like "%赌博%" - } -} -``` - -王武为赌博应用开发者,李四为赌博应用老板,两个用户实体对应了不同的概念类型。 - -赌博开发者认定规则: - -rule: 用户存在大于5台设备,且这些设备中安装了相同的APP,则存在开发关系。 - -``` -Define (s:Person)-[p:developed]->(o:App) { - Structure { - (s)-[:hasDevice]->(d:Device)-[:install]->(o) - } - Constraint { - deviceNum = group(s,o).count(d) - R1("设备超过5"): deviceNum > 5 - } -} -``` - -``` -Define (s:Person)-[p:belongTo]->(o:`TaxOfRiskUser`/`赌博App开发者`) { - Structure { - (s)-[:developed]->(app:`TaxOfRiskApp`/`赌博应用`) - } - Constraint { - } -} -``` - -**认定赌博APP老板** - -规则1:人和APP存在发布关系。 - -``` -Define (s:Person)-[p:release]->(o:App) { - Structure { - (s)-[:holdShare]->(c:Company), - (c)-[:hasCert]->(cert:Cert)<-[useCert]-(o) - } - Constraint { - } -} -``` - -规则2:用户给该赌博App开发者转账,并且存在发布赌博应用行为。 - -``` -Define (s:Person)-[p:belongTo]->(o:`TaxOfRiskApp`/`赌博App老板`) { - Structure { - (s)-[:release]->(a:`TaxOfRiskApp`/`赌博应用`), - (u:Person)-[:developed]->(a), - (s)-[:fundTrans]->(u) - } - Constraint { - } -} -``` - -#### 场景3:面向业务知识和事实数据分层下的知识应用 - -基于GQL获取黑产应用对应的团伙信息。 - -**获取所有的赌博应用** - -编辑dsl_task1.txt,输入如下内容: - -``` -MATCH (s:`RiskMining.TaxOfRiskApp`/`赌博应用`) RETURN s.id -``` - -执行脚本: - -``` -knext reasoner query --file ./reasoner/dsl_task1.dsl -``` - -**获取赌博APP背后的开发者和老板** - -编辑dsl_task2.txt,输入如下内容: - -``` -MATCH - (u:`RiskMining.TaxOfRiskUser`/`赌博App开发者`)-[:developed]->(app:`RiskMining.TaxOfRiskApp`/`赌博应用`), - (b:`RiskMining.TaxOfRiskUser`/`赌博App老板`)-[:release]->(app) -RETURN - u.id, b.id ,app.id -``` - -执行脚本: - -``` -knext reasoner query --file ./reasoner/dsl_task2.dsl -``` diff --git a/docs/_quick-start/contribution.md b/docs/_quick-start/contribution.md deleted file mode 100644 index 21cec7c..0000000 --- a/docs/_quick-start/contribution.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: 参与贡献 -order: 3 ---- - -## 提交 Bug - -如果您在OpenSPG中发现了一个 非安全问题相关的 Bug, 请先到 Issues 中搜索,以防止该 Bug 已被提交。 - -如果找不到,请创建一个Issue来描述这个Bug。 - -## 提交安全性问题 - -如果您在OpenSPG中发现了一个 安全性问题,请不要公开,通过邮件联系 owner, 并在邮件中详细描述该安全问题。 - -## 解决现有问题 - -通过查看仓库 Issues 列表发现需要处理的问题信息,可以尝试解决其中的某个问题。 - -## 代码规范 - -### Python - -#### Code Style - -python 的 code style 总体上要求符合pep8的标准。 - -如果使用 PyCharm开发,可以通过 [BlackConnect](https://black.readthedocs.io/en/stable/integrations/editors.html) 插件进行format。 - -#### Docstring - -使用 Google style format。 - -如果使用 Pycharm 开发,可以在 `Preferences -> Tools -> Python Integrated Tools -> Docstrings` 进行配置。 - -### Java - -#### Code style - -使用 Google Style。 - -如果使用 Intellij 开发,通过如下方式进行进行配置和 format: - -(1) 下载 [intellij-java-google-style.xml](https://github.com/google/styleguide/blob/gh-pages/intellij-java-google-style.xml)。 - -(2) 在 Intellij 中, `Settings -> Editor -> Code Style -> import schemes-> intellij idea code style xml` 进行配置。 - -## Issue 与 PR - -对于功能优化,功能扩展,Bug fix 等方面的问题, 我们非常欢迎进行讨论和相应的修改。 - -## 开发流程 - -- 切换到你的开发分支 - - ``` - git checkout -b your-branch - .... - git add xxx - git commit -m "xxx" - ``` - -- 开发你的功能 -- 添加单测 -- 提交PR -- 处理冲突 - - ``` - git checkout your-branch - git rebase master # 确保本地 master 是最新的 - ``` - -- Code review - - 你提交的代码需要通过 code review 才能合入到 master, 请耐心等待。 - 我们将分配相关同学进行 code review。 - 如果相关同学2个工作日仍然没有回应你的PR,请在你的PR中 @ 相关同学。 - code review的相关评论会直接贴到相关的 PR 或 issue 中。 如果你觉得相关建议是合理的,请更新你的代码。 - -- 合入到 master - - code review 通过后,我们会安排新的同学进一步review, 确保每个 PR 至少有两个同意后才能合入到主线。 - 这个过程中可能也会出现一些需要修改的意见,请耐心修改。 - 都通过后,PR将会合入到 master。 diff --git a/docs/_quick-start/index.md b/docs/_quick-start/index.md deleted file mode 100644 index fa96439..0000000 --- a/docs/_quick-start/index.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: SPG介绍 -order: 1 ---- - -## OpenSPG - -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](./LICENSE) - -OpenSPG 是蚂蚁集团结合多年金融领域多元场景知识图谱构建与应用业务经验的总结,并与OpenKG联合推出的基于SPG(Semantic-enhanced Programmable Graph)框架研发的知识图谱引擎。 - -![OpenSPG Architecture](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*YYSpQoItezMAAAAAAAAAAAAADtmcAQ/original) - -## 背景介绍 - -SPG(Semantic-enhanced Programmable Graph):语义增强可编程框架,是蚂蚁知识图谱平台经过多年金融领域业务的支撑,沉淀的一套基于属性图的语义表示框架。它创造性地融合了LPG结构性与RDF语义性,既克服了RDF/OWL语义复杂无法工业落地的问题,又充分继承了LPG结构简单与大数据体系兼容的优势。该框架从三个方面来定义和表示知识语义。首先,SPG明确定义了"知识"的形式化表示和可编程框架,使其可定义、可编程,机器可理解和处理。其次,SPG实现了知识层级间的兼容递进,支持工业级场景下非完备数据状态的图谱构建和持续迭代演化。最后,SPG有效衔接大数据与AI技术体系,支持对海量数据进行高效的知识化转换,帮助提高数据价值和应用价值。通过SPG框架,我们可以更加高效地构建和管理图谱数据,同时可以更好地支持业务需求和应用场景。由于SPG框架具有良好的可扩展性和灵活性,新的业务场景可以通过扩展领域知识模型及开发新算子,快速构建其领域模型和解决方案。 - -SPG的详细介绍请参考**蚂蚁集团和OpenKG联合发布**的[《SPG白皮书》](download)。 - -## 能力模型 - -OpenSPG是以SPG框架为基础设计和实现的知识图谱开放引擎,它为领域图谱构建提供了明确的语义表示、逻辑规则定义、算子框架( -构建、推理)等能力,支持各厂商可插拔的适配基础引擎、算法服务,构建自定义的解决方案。 - -OpenSPG核心能力模型包括: - -- SPG-Schema语义建模 - - 负责属性图语义增强的Schema框架设计,如主体模型、演化模型、谓词模型等。 -- SPG-Builder知识构建 - - 支持结构化和非结构化知识导入。 - - 与大数据架构兼容衔接,提供了知识构建算子框架,实现从数据到知识的转换。 - - 抽象了知识加工SDK框架,提供实体链指、概念标化和实体归一等算子能力,结合自然语言处理(Natural Language Processing, NLP) - 和深度学习算法,提高单个类型(Class)中不同实例(Instance)的唯一性水平,支持领域图谱的持续迭代演化。 -- SPG-Reasoner逻辑规则推理 - - 抽象了KGDSL(Knowledge Graph Domain Specific Language),为逻辑规则提供可编程的符号化表示。 - - 以机器可理解的符号表示支持下游规则推理、神经/符号融合学习、KG2Prompt联动LLM知识抽取/知识推理等。 - - 通过谓词语义和逻辑规则来定义知识之间的依赖和传递,并且支持对复杂的业务场景的建模和分析。 -- 可扩展SDK框架 - - 业务系统通过SDK对接开放引擎,构建自身特色的业务前端 - - 可扩展/适配自定义的图存储/图计算引擎 - - 可扩展/适配适合自身业务特点的机器学习框架 - -## 如何使用 - -### Get Started - -- [安装说明](./install.md) -- 通过案例快速上手: - - [企业供应链图谱](../example/enterprise-supply-chain/index.md) - - [黑产挖掘图谱](../example/risk-mining/index.md) - - [医疗知识图谱](../example/medical/index.md) - -### 进阶教程 - -- [KNext命令行工具和SDK教程](../tutorial/knext/index.md) -- [知识建模Schema教程](../tutorial/spgschema/index.md) -- [逻辑规则推理KGDSL教程](../tutorial/spgreasoner/index.md) -- [适配新的图数据库教程](../tutorial/spg2lpg/index.md) - -## 贡献代码 - -- [Contribution Guidelines](./contribution.md) diff --git a/docs/_quick-start/install.md b/docs/_quick-start/install.md deleted file mode 100644 index 2887cd3..0000000 --- a/docs/_quick-start/install.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: 快速安装 -order: 2 ---- - -## 1 安装简要 - -`OpenSPG`基于`Java`&`Python`开发,其中服务端是基于蚂蚁蚂蚁的开源框架[`SOFABoot`](https://www.sofastack.tech/projects/sofa-boot/overview/)开发,客户端是基于`Python3`开发。 -单机版可运行的环境还包括`Mysql`用于存储服务端元数据,`ElasticSearch`用于索引SPG数据。 - -`OpenSPG`服务端可以通过`Docker Compose`快速安装,相关的镜像地址请[点击](https://hub.docker.com/repositories/baifuyu),该链接中包含了以下2个镜像: - -| 模块名 | 镜像名 | 说明 | -| ------------- | ---------------------------- | ------------------------------------------------ | -| openspg | baifuyu/openspg:latest | OpenSPG服务端镜像,基于Java开发 | -| openspg-mysql | baifuyu/openspg-mysql:latest | OpenSPG Mysql镜像,基于Mysql初始化了一些表和数据 | - -除了以上2个Docker镜像,要启动OpenSPG服务,还需要另外2个Docker镜像: - -| 模块名 | 镜像名 | 说明 | -| ------------- | ------------------------------------- | ------------------------------------ | -| tugraph | tugraph/tugraph-runtime-centos7:4.0.1 | OpenSPG图存储镜像,用于存储图谱数据 | -| elasticsearch | elasticsearch:8.5.3 | OpenSPG搜索存储镜像,用于索引SPG数据 | - -`OpenSPG`客户端通过`Python`包管理工具`pip`工具安装,`Python`版本要求>=3.8; - -## 2 快速安装 - -### 2.1 客户端安装: - -执行以下命令可以快速安装: - -```bash -pip install openspg-knext -``` - -检验`OpenSPG`客户端是否安装成功,其中`knext`是客户端命令; - -```bash -knext --version -``` - -### 2.2 服务端安装: - -1. 本地安装`Docker`
- 环境可参考官方文档:[https://www.docker.com/products/docker-desktop/](https://www.docker.com/products/docker-desktop/) - -2. `Docker Compose`配置文件如下,将该配置复制到本地文件并命名为`docker-compose.yml`,再使用以下命令启动 - -```bash -docker-compose -f docker-compose.yml up -d -``` - -其中`docker-compose.yml`文件内容: - -```yaml -version: '3.7' -services: - openspg: - restart: always - image: baifuyu/openspg:latest - container_name: release-openspg - ports: - - '8887:8887' - depends_on: - - mysql - - tugraph - - elasticsearch - command: - [ - '--cloudext.repository.impl.jdbc.host=mysql', - '--builder.operator.python.exec=/usr/bin/python3.8', - '--builder.operator.python.paths=/usr/lib/python3.8/site-packages;/usr/local/lib/python3.8/dist-packages;', - ] - environment: - - PYTHONPATH=/usr/lib/python3.8/site-packages:/usr/local/lib/python3.8/dist-packages - - mysql: - restart: always - image: baifuyu/openspg-mysql:latest - container_name: release-openspg-mysql - environment: - TZ: Asia/Shanghai - LANG: C.UTF-8 - ports: - - '3306:3306' - command: - [ - '--character-set-server=utf8mb4', - '--collation-server=utf8mb4_general_ci', - ] - - tugraph: - image: tugraph/tugraph-runtime-centos7:4.0.1 - container_name: release-openspg-tugraph - # default username is admin and default password is 73@TuGraph - ports: - - '7070:7070' - - '9090:9090' - command: lgraph_server - - elasticsearch: - image: elasticsearch:8.5.3 - container_name: test-openspg-elasticsearch - ports: - - '9200:9200' - - '9300:9300' - environment: - - discovery.type=single-node - - xpack.security.enabled=false -``` - -第一次使用需要下载以上4个服务的Docker镜像,速度会有点慢,请耐心等待~。 - -等服务端与客户端都安装启动完成后,接下来就可以创建我们的第一个图谱了。 - -**相关文档链接**: - -1. [KNext命令行工具和SDK教程](../tutorial/knext/index.md) -2. [企业供应链图谱](../example/enterprise-supply-chain/index.md) -3. [黑产挖掘图谱](../example/risk-mining/index.md) -4. [医疗知识图谱](../example/medical/index.md) diff --git a/docs/_tutorial/index.md b/docs/_tutorial/index.md deleted file mode 100644 index d156d5a..0000000 --- a/docs/_tutorial/index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: 教程 -order: 2 -nav: - title: 教程 - order: 2 ---- - - diff --git a/docs/_tutorial/knext/index.md b/docs/_tutorial/knext/index.md deleted file mode 100644 index ced6430..0000000 --- a/docs/_tutorial/knext/index.md +++ /dev/null @@ -1,986 +0,0 @@ ---- -title: KNext命令使用 -nav: - second: - title: KNext命令使用 - order: 1 ---- - -本文将会介绍OpenSPG中python SDK -- KNext的使用方法,包括命令行工具,以及可编程SDK。 -使用KNext命令行工具,可以完成创建图谱项目、schema变更和查询、图谱查询和推理等功能。 - -## 1 安装指南 - -### 1.2 支持的Python版本 - -python>=3.8 - -### 1.3 安装 knext - -建议创建虚拟环境后安装knext,避免knext依赖包与系统包的冲突问题。 -使用pip工具安装knext指定版本: - -```bash -pip install openspg-knext -``` - -检验knext是否安装成功,使用以下命令查看knext版本: - -```bash -knext --version -``` - -## 2 快速开始 - -该示例可以帮助快速开始一个简单的图谱数据导入和分析推理。 - -### 2.1 设置服务端地址 - -执行以下命令,设置OpenSPG服务端地址(默认为本地地址 [http://127.0.0.1:8887](http://127.0.0.1:8887) ): - -```bash -knext config set --global host_addr=http://127.0.0.1:8887 -``` - -### 2.2 创建一个示例项目 - -执行以下命令,创建一个项目,会在当前目录下生成示例项目文件夹,文件夹名为namespace的小写: - -```bash -knext project create --name 示例项目 --namespace Prj --desc 这是一个示例项目 -``` - -### 2.3 切换项目 - -执行以下命令,进入项目目录,所有对于该项目的操作需要在项目目录内进行: - -```bash -cd prj -``` - -项目内包含: - -- 一个示例实体 `Prj.Demo`,声明在 `/schema/prj.schema`,用于创建项目schema: - -``` -namespace Prj - -Demo(示例实体): EntityType - properties: - demoProperty(示例属性): Text -``` - -- 一个构建任务 `Demo`,定义在`builder/job/demo.py` ,用于导入 `Prj.Demo`实体: - -```python -# -*- coding: utf-8 -*- - -from knext.core.builder.job.model.builder_job import BuilderJob -from knext.core.builder.job.model.component import SourceCsvComponent, EntityMappingComponent, SinkToKgComponent -from schema.prj_schema_helper import Prj - - -class Demo(BuilderJob): - - def build(self): - source = SourceCsvComponent( - local_path="./builder/job/data/Demo.csv", - columns=["id", 'prop'], - start_row=2 - ) - - mapping = EntityMappingComponent( - spg_type_name=Prj.Demo - ).add_field("id", Prj.Demo.id) - .add_field("prop", Prj.Demo.demoProperty) - - sink = SinkToKgComponent() - - return source >> mapping >> sink - -``` - -- 一个抽取算子 `DemoExtractOp`,定义在 `builder/operator/demo_extract.py` : - -```python -# -*- coding: utf-8 -*- - -from typing import List, Dict - -from knext.core.builder.operator import Vertex -from knext.core.builder.operator.model.op import KnowledgeExtractOp - - -class DemoExtractOp(KnowledgeExtractOp): - - def __init__(self, params: Dict[str, str] = None): - super().__init__(params) - - def eval(self, record: Dict[str, str]) -> List[Vertex]: - - return [Vertex(properties=record)] - -``` - -- 一个DSL查询语句,声明在 `reasoner/demo.dsl`,用于查询所有 `Prj.Demo`实体: - -``` -MATCH (s:Prj.Demo) -RETURN s.id, s.demoProperty -``` - -### 2.4 创建schema - -```bash -knext schema commit -``` - -- 执行此命令后,会将`/schema/prj.schema`内的schema声明,提交到服务端。 - -### 2.5 发布算子 - -```bash -knext operator publish DemoExtractOp -``` - -- 执行此命令后,会扫描 `builder/operator`下的所有算子,并将 `DemoExtractOp` 发布到服务端。 - -### 2.6 知识加工 - -```bash -knext builder submit Demo -``` - -- 执行此命令后,会扫描 `builder/job`下的所有加工任务(需要继承`BuilderJob`类),并将 `Demo`提交到服务端。 - -### 2.7 dsl查询 - -```bash -knext reasoner query --file reasoner/demo.dsl -``` - -- 执行此命令后,会将 `--file` 指定的文件中的dsl查询语句,提交到服务端进行查询,并同步返回查询结果。 - -## 3 命令行工具 - -通过`knext`命令行工具,以及定义的多个子命令,实现完整的图谱构建与使用流程。 - -```bash -Usage: knext [OPTIONS] COMMAND [ARGS]... - -Options: - --version Show the version and exit. - --help Show this message and exit. - -Commands: - builder Builder client. - config Knext config. - operator Operator client - project Project client. - reasoner Reasoner client. - schema Schema client. - -``` - -### 3.1 config - -```bash -Usage: knext config [OPTIONS] COMMAND [ARGS]... - - Knext config. - -Options: - --help Show this message and exit. - -Commands: - list List global and local knext configs. - set Edit global or local configs. - -``` - -#### 3.1.1 修改配置 - -```bash -knext config set [--help] - [--global key=value] - [--local key=value] -``` - -- 【选填】--global 全局配置设置,将在`~/.config`下生成`.knext.cfg`配置文件,并将`key=value`配置写入文件中。该文件配置对所有项目生效。 -- 【选填】--local 项目配置设置,将在项目目录下生成`.knext.cfg`配置文件,并将`key=value`配置写入文件中。该文件配置仅对当前项目生效。 - -使用实例: - -```bash -knext config set --global host_addr=http://127.0.0.1:8887 -``` - -结果: -执行`cat ~/.config/.knext.cfg`展示全局配置信息: - -```bash -[global] -host_addr = http://127.0.0.1:8887 -``` - -#### 3.1.2 展示配置 - -```bash -knext config list [--help] -``` - -使用实例: - -```bash -knext config list -``` - -结果: - -```bash -[global] -host_addr = http://127.0.0.1:8887 -[local] - -``` - -### 3.2 project - -```bash -Usage: knext project [OPTIONS] COMMAND [ARGS]... - - Project client. - -Options: - --help Show this message and exit. - -Commands: - create Create new project with a demo case. - list List all project information. - -``` - -#### 3.2.1 创建项目 - -```bash -knext project create [--help] - [--name name] - [--namespace namespace] - [--desc desc] - [--prj_path prj_path] -``` - -- 【必填】--name 项目名 -- 【必填】--namespace 项目内schema的前缀,限制以大写字母开头,仅包含字母或数字,长度最大为16。 -- 【选填】--desc 项目介绍 -- 【选填】--prj_path 项目路径,用于根据本地项目目录在服务端恢复项目。 - -使用实例: - -```bash -knext project create --name 示例项目 --namespace Prj --desc 这是一个示例项目 -``` - -结果: -执行成功后会在当前目录下创建出prj目录,执行`cd prj`进入示例项目。 - -``` -. -└── prj - ├── builder - │ ├── model - │ ├── operator - │ │ └── demo_extract_op.py - │ └── job - │ ├── data - │ │ └── Demo.csv - │ └── demo.py - ├── reasoner - │ └── demo.dsl - ├── schema - │ ├── prj.schema - └── README.md -``` - -#### 3.2.2 展示所有项目 - -```bash -knext project list [--help] -``` - -执行该命令,会列出当前所有已创建的项目信息。 -使用实例: - -```bash -knext project list -``` - -结果: - -```bash -| ID | Name | Namespace | Description | -|------|----------------|-------------|----------------| -| 1 | defaultProject | DEFAULT | defaultProject | -| 2 | 示例项目 | Prj | 这是一个示例项目 | -``` - -### 3.3 schema - -```bash -Usage: knext schema [OPTIONS] COMMAND [ARGS]... - - Schema client. - -Options: - --help Show this message and exit. - -Commands: - commit Commit local schema and generate schema helper. - diff Print differences of schema between local and server. - reg_concept_rule Register a concept rule according to DSL file. - -``` - -#### 3.3.1 提交schema - -```bash -knext schema commit [--help] -``` - -使用实例: - -```bash -knext schema commit -``` - -结果: - -``` -Create type: Prj.Demo -Schema is successfully committed. -SchemaHelper is created in schema/prj_schema_helper.py. -``` - -#### 3.3.2 展示schema diff(不提交) - -```bash -knext schema diff [--help] -``` - -#### 3.3.3 提交概念规则 - -```bash -knext schema reg_concept_rule [--help] - [--file file] -``` - -- 【必填】--file concept rule文件路径 - -使用实例: - -schema/concept.rule - -``` -namespace DEFAULT - -`TaxOfRiskApp`/`赌博应用`: - rule: [[ - ... - ]] - -``` - -执行命令: - -```bash -knext schema reg_concept_rule --file schema/concept.rule -``` - -结果: - -``` -Defined belongTo rule for ... -... -Concept rule is successfully registered. -``` - -### 3.4 operator - -```bash -Usage: knext operator [OPTIONS] COMMAND [ARGS]... - - Operator client - -Options: - --help Show this message and exit. - -Commands: - list List all server-side operators. - publish Publish an operator to server. - -``` - -#### 3.4.1 发布算子 - -```bash -knext operator publish [OP_NAMES] -``` - -- 【必填】OP_NAMES 发布的算子名,多个算子间用`,`分隔开。所有算子必须实现在 `builder/operator/`下,且需要继承`BaseOp` - 的子类,算子名默认为类名。 - -使用实例: - -builder/operator/demo_extract_op.py - -```python -... - - -class DemoExtractOp(KnowledgeExtractOp): - - -... -``` - -执行命令: - -```bash -knext operator publish DemoExtractOp -``` - -结果: - -```bash -Operator [DemoExtractOp] has been successfully published. The latest version is 1. -``` - -#### 3.4.2 展示所有算子 - -```bash -knext operator list [--help] -``` - -使用实例: - -```bash -knext operator list -``` - -### 3.5 builder - -```bash -Usage: knext builder [OPTIONS] COMMAND [ARGS]... - - Builder client. - -Options: - --help Show this message and exit. - -Commands: - get Query submitted job status. - submit Submit asynchronous builder jobs to server by providing job names. - -``` - -#### 3.5.1 提交构建任务 - -```bash -knext builder submit [JOB_NAMES] -``` - -- 【必填】JOB_NAMES 提交的构建任务名,多个任务间用`,`分隔开。所有任务必须实现在 `builder/job/`下,且需要继承`BuilderJob` - ,任务名默认为类名。 - -使用实例: - -builder/job/demo.py - -```python -... - - -class Demo(BuilderJob): - - -... -``` - -执行命令: - -```bash -knext builder submit Demo -``` - -结果: - -```bash -Operator [DemoExtractOp] has been successfully published. The latest version is 1. -``` - -#### 3.5.2 查询构建任务 - -```bash -knext builder get [--help] - [--id id] -``` - -- 【必填】--id 查询的任务id(成功提交任务后会返回),结果返回单个任务实例。 - -### 3.6 reasoner - -```bash -Usage: knext reasoner [OPTIONS] COMMAND [ARGS]... - - Reasoner client. - -Options: - --help Show this message and exit. - -Commands: - get Query submitted reasoner job status. - query Query dsl by providing a string or file. - submit Submit asynchronous reasoner jobs to server by providing DSL file or string. - -``` - -#### 3.6.1 DSL查询 - -提交DSL查询任务,结果同步返回,查询任务耗时超过3分钟会报错。 - -```bash -knext reasoner query [--help] - [--file file] - [--dsl file] -``` - -- 【二选一】--file 查询的dsl文件。 -- 【二选一】--dsl 查询的dsl语法,用双引号括起来。 - -使用实例: - -reasoner/demo.dsl: - -```bash -MATCH (s:Prj.Demo) -RETURN s.id, s.demoProperty -``` - -执行命令: - -```bash -knext reasoner query --file reasoner/demo.dsl -``` - -结果: - -```bash -| s_id | s_demoProperty | -|--------|------------------| -| 00 | demo | -``` - -#### 3.6.2 提交DSL推理任务 - -提交查询任务,结果异步生成。 - -```bash -knext reasoner submit [--help] - [--file file] - [--dsl file] -``` - -- 【二选一】--file 查询的dsl文件。 -- 【二选一】--dsl 查询的dsl语法,用双引号括起来。 - -#### 3.6.3 查询推理任务 - -```bash -knext reasoner get [--help] - [--id id] -``` - -【必填】--id 查询的任务id(成功提交任务后会返回),结果返回单个任务实例。 - -## 4 默认项目结构 - -``` -. -└── riskmining - ├── builder # 知识加工 - │ ├── model # 算法模型目录 - │ ├── operator # 算子目录 - │ | ├── demo_link_op.py - │ | ├── demo_extract_op.py - │ │ └── ... - │ └── job # 加工任务目录 - │ ├── demo1.py - │ ├── demo2.py - │ ├── data # 数据目录 - │ │ ├── Demo1.csv - │ │ ├── Demo2.csv - │ │ └── ... - │ └── error_record # 错误信息目录 - │ ├── spgbuilder_Demo1_1_errorRecord.csv - │ ├── spgbuilder_Demo1_2_errorRecord.csv - │ └── ... - ├── reasoner # 规则推理 - │ ├── demo.dsl - │ └── result - │ ├── spgreasoner_job_1_result.csv - │ ├── spgreasoner_job_2_result.csv - │ └── ... - ├── schema # schema定义 - │ ├── riskmining.schema - │ ├── riskmining_schema_helper.py - │ └── concept.rule - ├── README.md - └── .knext.cfg -``` - -- `.knext.cfg` - 文件为整个项目的配置文件。配置信息大部分情况下固定,当调整项目目录结构时,需要通过`knext config set --local key=value` - 命令修改配置。 在新建项目时会自动生成,并写入默认配置如下: - -```bash -[local] -project_name = 风险挖掘 -description = 风险挖掘项目 -project_id = 2 -namespace = RiskMining -project_dir = riskmining -schema_dir = schema -schema_file = riskmining.schema -builder_dir = builder -builder_operator_dir = builder/operator -builder_record_dir = builder/error_record -builder_job_dir = builder/job -builder_model_dir = builder/model -reasoner_dir = reasoner -reasoner_result_dir = reasoner/result -``` - -- `project_name` 项目名,新建项目时通过[--name]参数指定,不可修改。 -- `description` 项目介绍,新建项目时通过[--desc]参数指定。 -- `project_id` 项目id,新建项目时自动分配。若使用`knext project create [--prj_pth]`命令,会生成新的id并覆盖原id。 -- `namespace` 项目schema前缀,新建项目时通过[--namespace]参数指定,不可修改。 -- `project_dir` 项目根目录,新建项目时默认为`namespace.lower()`。若文件夹重命名,需要修改此配置。 -- `schema_dir` schema目录,新建项目时默认为`schema`。 -- `schema_file` schema声明文件名,新建项目时默认为 `${namespace.lower()}.schema`。若文件重命名,需要修改此配置。 -- `builder_dir` 加工任务目录,新建项目时默认为 `builder`。若目录变动,需要修改此配置。 -- `builder_operator_dir` 算子目录,新建项目时默认为 `builder/operator`。若目录变动,需要修改此配置。 -- `builder_record_dir` 加工任务记录目录,新建项目时默认为 `builder/record`。若目录变动,需要修改此配置。 -- `builder_job_dir` 算子目录,新建项目时默认为 `builder/job`。若目录变动,需要修改此配置。 -- `builder_model_dir` 算法模型目录,新建项目时默认为 `builder/model`。若目录变动,需要修改此配置。 -- `reasoner_dir` 规则推理目录,新建项目时默认为 `reasoner`。若目录变动,需要修改此配置。 -- `reasoner_result_dir` 规则推理结果目录,新建项目时默认为 `reasoner/result`。若目录变动,需要修改此配置。 -- `builder` 目录用来保存所有知识加工任务以及依赖的源数据、自定义算子、算法模型、执行错误记录。 -- `reasoner` 目录用来保存规则推理相关的DSL语法文件和执行结果。 - - DSL语法文件以`.dsl`为结尾,用来保存DSL查询语句。 -- `schema` 目录用来保存项目schema声明和概念规则。 - - 项目schema声明文件以`.schema`为结尾,通过`knext schema commit`解析schema文件,并提交到服务端。每个项目只允许唯一的schema声明文件。 - - 概念规则以`.rule` 为结尾,通过`knext schema reg_concept_rule [--file]`,将文件中定义的规则注册到对应概念上。 - -## 5 python SDK - -### 5.1 编写一个加工任务 - -`Builderjob`是所有知识加工任务的基类。 -所有在`{builder_job_dir}`下继承了`BuilderJob` -的类,都会被knext识别为一个加工任务。加工任务可以通过`knext builder submit [name]`命令提交到服务端异步执行。 -所有加工任务**必须**实现`build`方法,用来定义任务的执行流程。 - -#### 5.1.1 参数 - -| 参数 | 类型 | 是否必填 | 示例值 | 描述 | -| ------------------ | ----------------- | -------- | ------------------------ | ------------------------------------------------------------ | -| **parallelism** | int | 否 | 1 | 加工任务执行并发度【默认为1】 | -| **operation_type** | OperationTypeEnum | 否 | OperationTypeEnum.Create | 加工任务操作类型【默认为Create,即数据以增量更新的方式写入】 | -| **lead_to** | bool | 否 | True | 加工任务是否执行因果关系【默认为False】 | - -#### 5.1.2 接口 - -##### build(self) - -用来编写加工任务的执行逻辑,本质上是定义各个执行节点间的pipeline流程,每个执行节点都是一个继承了`Component`基类的组件。 -通过`>>`右移符号(knext对`__rshift__`实现了重载),定义各个组件之间的依赖关系,build方法需要返回pipeline结构,以下为示例: - -```python -class App(BuilderJob): - - def build(self): - source = SourceCsvComponent(...) - - mapping = EntityMappingComponent(...) - - sink = SinkToKgComponent(...) - - return source >> mapping >> sink -``` - -### 5.2 组件 - -#### 5.2.1 SourceCsvComponent(CSV数据源) - -csv数据源组件,用来上传本地csv文件,并逐行读取数据 - -##### 5.2.1.1 参数 - -| 名称 | 类型 | 是否必填 | 示例值 | 描述 | -| -------------- | --------- | -------- | ----------------------------- | ------------------------------------------------------------ | -| **local_path** | str | 是 | './builder/job/data/App.csv' | 文件路径 | -| **columns** | list[str] | 是 | ['id', 'riskMark', 'useCert'] | 输入列 | -| **start_row** | int | 是 | 2 | 数据读取起始行数【若希望从csv第一行开始读取,则start_row=1】 | - -##### 5.2.1.2 接口 - -无 - -#### 5.2.2 KnowledgeExtractComponent(知识抽取) - -将非结构化数据转化为结构化数据。抽取组件上必须设置`KnowledgeExtractOp`抽取类型算子。 - -##### 5.2.2.1 参数 - -| 名称 | 类型 | 是否必填 | 示例值 | 描述 | -| ----------------- | --------- | -------- | ----------------------------- | -------- | -| **output_fields** | List[str] | 是 | ['id', 'riskMark', 'useCert'] | 输出字段 | - -##### 5.2.2.2 接口 - -###### set_operator - -设置抽取算子,取已发布的最新版本的算子。 - -| 参数 | 类型 | 是否必填 | 示例值 | 描述 | -| ----------- | -------------- | -------- | -------------------------------- | ----------------------------------------------- | -| **op_name** | str | 是 | Operator("DemoKnowledgeExtract") | 抽取算子名 | -| **params** | Dict[str, str] | 否 | {"": ""} | 抽取算子参数,在算子内可以通过self.params获取。 | - -##### 5.2.2.3 示例 - -```python -extract = KnowledgeExtractComponent( - output_fields=["id", 'riskMark', 'useCert'] -).set_operator("DemoExtractOp") -``` - -#### 5.2.3 EntityMappingComponent(实体映射组件) - -将非标准输入字段映射到SPG实体(EntityType/EventType/ConceptType/StandardType)的属性上(**必须包含到**`**id**`**属性的映射 -**)。若SPG实体的属性类型上绑定了 `EntityLinkOp/PropertyNormalizeOp`,会在字段映射后执行链指拉边和概念标化挂载;否则,会以属性值作为id,召回出目标实体进行拉边和概念挂载。 - -##### 5.2.3.1 参数 - -| 名称 | 类型 | 是否必填 | 示例值 | 描述 | -| ----------------- | ---- | -------- | ----------- | ----------- | -| **spg_type_name** | str | 是 | DEFAULT.App | SPG实体类型 | - -##### 5.2.3.2 接口 - -###### add_field - -添加从源数据字段到SPG属性之间的映射关系。 - -| 参数 | 类型 | 是否必填 | 示例值 | 描述 | -| ---------------- | ---- | -------- | ------------------- | ----------- | -| **source_field** | str | 是 | "useCert" | 源字段 | -| **target_field** | str | 是 | DEFAULT.App.useCert | SPG实体属性 | - -###### add_filter - -添加字段筛选条件,数据满足`column_name=column_value`条件的会执行映射。若不设置筛选条件,则全部数据会执行映射。 - -| 参数 | 类型 | 是否必填 | 示例值 | 描述 | -| ---------------- | ---- | -------- | ------ | -------- | -| **column_name** | str | 是 | "type" | 筛选字段 | -| **column_value** | str | 是 | "App" | 筛选值 | - -##### 5.2.3.3 示例 - -```python -mapping = EntityMappingComponent( - spg_type_name=DEFAULT.App -).add_field("id", DEFAULT.App.id) -.add_field("id", DEFAULT.App.name) -.add_field("riskMark", DEFAULT.App.riskMark) -.add_field("useCert", DEFAULT.App.useCert) -``` - -#### 5.2.4 RelationMappingComponent(关系映射组件) - -将非标准输入字段映射到SPG关系的属性上(**必须包含到**`**srcId**`**和**`**dstId**`**的映射**)。 - -##### 5.2.4.1 参数 - -| 名称 | 类型 | 是否必填 | 示例值 | 描述 | -| ------------------ | ---- | -------- | ------------------- | -------- | -| **subject_name** | str | 是 | DEFAULT.App | 主体类型 | -| **predicate_name** | str | 是 | DEFAULT.App.useCert | 谓词关系 | -| **object_name** | str | 是 | DEFAULT.Cert | 客体类型 | - -##### 5.2.4.2 接口 - -同EntityMappingComponent - -##### 5.2.4.3 示例代码 - -```python -mapping = RelationMappingComponent( - subject_name=DEFAULT.App, - predicate_name=DEFAULT.App.useCert, - object_name=DEFAULT.Cert, -).add_field("src_id", "srcId") -.add_field("dst_id", "dstId") -``` - -#### 5.2.5 SPGMappingComponent(SPG映射组件) - -指定SPG类型作为主体类型,根据schema定义,从长文本中抽取SPO关系组,即以SPG类型为中心的关系子图。 -SPG映射组件需要设置知识抽取算子。 - -##### 5.2.5.1 参数 - -| 名称 | 类型 | 是否必填 | 示例值 | 描述 | -| ----------------- | ---- | -------- | ----------- | ----------- | -| **spg_type_name** | str | 是 | DEFAULT.App | SPG实体类型 | - -##### 5.2.5.2 接口 - -###### set_operator - -设置抽取算子,取已发布的最新版本的算子。 - -| 参数 | 类型 | 是否必填 | 示例值 | 描述 | -| ----------- | -------------- | -------- | ----------------- | ----------------------------------------------- | -| **op_name** | str | 是 | "DemoExtractOp" | 抽取算子名 | -| **params** | Dict[str, str] | 否 | {"hit_num": "10"} | 抽取算子参数,在算子内可以通过self.params获取。 | - -#### 5.2.6 SinkToKgComponent(图谱写入) - -##### 5.2.6.1 参数 - -无 - -##### 5.2.6.2 接口 - -无 - -##### 5.2.6.3 示例 - -```python -sink = SinkToKgComponent() -``` - -### 5.3 算子 - -`BaseOp`是所有算子的基类,`KnowledgeExtractOp/EntityLinkOp/PropertyNormalizeOp/EntityFuseOp` 继承自`BaseOp` -,用于区分不同类型的算子。 -所有在`{builder_operator_dir}`下继承了`BaseOp` -的四个子类的类,都会被knext识别为一个算子。算子可以通过`knext operator publish [op_name]`命令发布到服务端。 -所有算子**必须**实现`eval`方法,用来定义算子的执行逻辑。 - -#### 5.3.1 参数 - -| 参数 | 类型 | 是否必填 | 示例值 | 描述 | -| ----------- | ---- | -------- | ----------------- | ---------------------------------------------------------------- | -| **desc** | str | 否 | "证书链指算子" | 算子描述【默认为空】 | -| **bind_to** | str | 否 | "RiskMining.Cert" | 算子绑定的实体类型名,抽取类型算子不支持绑定实体类型【默认为空】 | - -#### 5.3.2 接口 - -##### 5.3.2.1 **init**(self, params: Dict[str, str] = None) - -所有算子的初始化方法,仅在加工任务提交后的初始化阶段执行一次。不同算子类型继承当前`__init__`方法。 -若自定义算子内不复写初始化方法,默认执行`self.params=params`。当组件通过`set_operator`方法设置了算子参数`params` -时,在算子内可以通过`self.params[key]`获取到对应参数的`value`,从而实现同个算子针对不同加工任务的复用。 -当自定义算子内需要初始化一些外部Client,例如`SearchClient`,可以复写`__init__`方法,避免Client的重复初始化。 - -##### 5.3.2.2 eval(self, \*args) - -所有自定义算子都需要复写`eval` 方法,用来实现你的算子执行逻辑。 -不同算子类型的`eval`方法,输入参数和输出结果类型也存在不同。 - -#### 5.3.3 数据结构 - -##### 5.3.3.1 Vertex - -将算子输入以及输出的实体信息(包括实体id、实体类型、实体属性)封装在`Vertex`类型中。 - -| 名称 | 类型 | 是否必填 | 示例值 | 描述 | -| --------------- | -------------- | -------- | ----------------------------------------------------------------------- | -------- | -| **biz_id** | str | 否 | "1" | 实体id | -| **vertex_type** | str | 否 | DEFAULT.Cert | 实体类型 | -| **properties** | Dict[str, str] | 是 | {"id": "1", "name": "1", "certNum": "68802adde35845d76eeb172ff8ea6825"} | 实体属性 | - -#### 5.3.4 示例 - -```python -class CertLinkerOperator(EntityLinkOp): - bind_to = "DEFAULT.Cert" - - def __init__(self): - super().__init__() - self.search_client = SearchClient("DEFAULT.Cert") - - def eval(self, property: str, record: Vertex) -> List[Vertex]: - query = {"match": {"certNum": property}} - recall_certs = self.search_client.search(query, 0, 10) - if recall_certs is not None: - return [Vertex(biz_id=recall_certs[0].doc_id, vertex_type="RiskMining.Cert")] - return [Vertex(biz_id=has_cert, vertex_type="RiskMining.Cert")] -``` - -执行`knext operator publish CertLinkerOperator`命令,算子将发布一个新版本到服务端,并根据`bind_to` -参数绑定算子新版本到`DEFAULT.Cert`实体schema上。 -在执行包含映射到`DEAFAULT.Cert`类型属性的加工任务时,会在映射后执行eval方法进行链指拉边。 - -#### 5.3.5 KnowledgeExtractOp(知识抽取算子) - -所有知识抽取算子需要继承`KnowledgeExtractOp`,其功能是从非结构化数据中抽取结构化数据,也可进行数据的预处理。 - -##### 5.3.5.1 接口 - -###### eval(self, record: Dict[str, str]) -> List[Vertex]: - -#### 5.3.6 PropertyNormalizeOp(属性标化算子) - -属性标化算子一般绑定在概念类型`ConceptType`上,其功能是将概念属性值标准化后,进行概念挂载。 -`knext.api`提供属性标化算子基础类`PropertyNormalizeOp`,可通过继承并实现`eval`方法,来完成自定义标化算子的开发。knext -pipeline支持在知识映射组件的实体属性上配置链指算子,在当前任务中覆盖schema上已绑定的算子。 - -##### 5.3.6.1 接口 - -###### eval(self, property: str, record: Vertex) -> str: - -输入: - -- property 待标化属性值 -- record 实体信息 - -返回: - -- 标化后的属性值 - -#### 5.3.7 EntityLinkOp(实体链指算子) - -实体链指算子一般绑定在实体类型`EntityType`或事件类型`EventType`上,其功能是根据实体属性值,召回链指目标,并在源实体和目标实体之间生成关系。 -实体链指算子也可用于实体融合去重中,在算子中召回出同类型的实体,根据规则或执行融合算子,进行属性融合或实体去重。 -`knext.api`提供实体链指算子基础类`EntityLinkOp`,可通过继承并实现`eval`方法,来完成链指算子的开发。 - -##### 5.3.7.1 接口 - -##### eval(self, property: str, record: Vertex) -> List[Vertex]: - -输入: - -- property 待链指的实体类型属性值 -- record 实体信息 - -返回: - -- 链指出的实体列表 - -#### 5.3.8 EntityFuseOp(实体融合算子) - -暂未支持 diff --git a/docs/_tutorial/spg2lpg/index.md b/docs/_tutorial/spg2lpg/index.md deleted file mode 100644 index 6bba024..0000000 --- a/docs/_tutorial/spg2lpg/index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: SPG2LPG适配 -nav: - second: - title: SPG2LPG适配 - order: 4 ---- - -OpenSPG框架中,为了适配不同厂商提供的图存储/图计算引擎,我们设计了SPG2LPG-Translator模块,用户基于该模块接口可实现图引擎的扩展。 -我们将在后续的新版本开放该模块,敬请期待! diff --git a/docs/_tutorial/spgreasoner/index.md b/docs/_tutorial/spgreasoner/index.md deleted file mode 100644 index a31e089..0000000 --- a/docs/_tutorial/spgreasoner/index.md +++ /dev/null @@ -1,1031 +0,0 @@ ---- -title: SPG推理语法 -nav: - second: - title: SPG推理语法 - order: 3 ---- - -注:KGDSL不区分大小写 - -## 1 保留关键词 - -### 1.1 常用关键词 - -| 关键词 | 描述 | 作用范围 | -| ------------------------------------------------------- | -------------- | ------------------- | -| Define | 定义关键词 | 全局 | -| Structure | 子图描述关键词 | 全局 | -| Constraint | 规则描述关键词 | 全局 | -| Action | 后置动作关键词 | 全局 | -| / | 概念引用分隔符 | 全局 | -| group | 图分组关键词 | Constraint | -| sum/filter/find/sort/slice
/count/max/min/avg/concat | 图聚合操作算子 | Constraint的group后 | -| and/or/not/xor/optional | 逻辑计算算子 | 全局 | - -### 1.2 特殊关键词 - -| 关键词 | 描述 | 作用范围 | -| ------------------ | ------------------------------- | ----------------- | -| **start** | 起点标志 | Structure | -| **per_node_limit** | 边限制标志 | Structure | -| **label** | 得到点边的类型 | Constraint/Action | -| **property_map** | 将图节点或者边的属性生成map对象 | Constraint/Action | -| **path** | 得到满足的路径 | Constraint/Action | -| **id** | 图谱点内部id(全局唯一) | Constraint/Action | -| **from** | 图谱边的起点内部id | Constraint/Action | -| **to** | 图谱边的终点内部id | Constraint/Action | - -## 2 数据类型 - -### 2.1 基本数据类型 - -| 数据类型 | 描述 | 示例 | -| -------- | -------- | ---------- | -| int | 整型 | 1,2,3 | -| float | 浮点型 | 23.11 | -| string | 字符串 | "abcdef" | -| bool | 布尔类型 | true/false | -| null | 空 | null | - -### 2.2 复杂数据类型 - -| 数据类型 | 描述 | 示例 | -| ------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| list | 数组类型 | [1,2,3] | -| multi_version | 多版本属性 | {
  "20220111":value,
  "20220112":value,
} | -| date | 日期类型 | / | -| node | 点类型 | {
  "id":123456,
  "label":"Film",
  "property":{"name":"Titanic"}
} | -| edge | 边类型 | {
  "from":1234,
  "to":4321,
  "label":"starOfFilm",
  "property":{"year":1989}
} | - -## 3 表达式算子 - -### 3.1 表达式风格 - -我们表达式采用过程式+链式两种方式混合表达 - -> 链式思想:是将多个操作(多行代码)通过点号(.)链接在一起成为一句代码,使代码可读性好。 -> 过程式思想:通过多行的方式,描述一段计算内容 - -链式风格非常适用于数据计算,如下例,我们需要计算一个表达式(1 + 2) \* 3 - 4,约束为一次只能计算一次,则过程式如下 - -> a = 1+2 -> b = a \*3 -> d = b -4 - -使用链式风格 - -> add(1,2).multiply(3).subtract(4) - -一行可以表达一个完整的计算流,我们可以在做数据计算时使用该风格 - -### 3.2 计算运算符 - -| 符号 | 示例 | 含义 | 备注 | -| ---- | ---- | -------- | -------- | -| + | a+b | 加法 | | -| - | a-b | 减法 | | -| \* | a\*b | 乘法 | | -| / | a/b | 除法 | 不可除0 | -| % | a%b | 取模 | b不可为0 | -| = | a=b | 赋值操作 | | - -### 3.3 逻辑运算符 - -| 符号 | 示例 | 含义 | 备注 | -| -------- | --------------------- | -------------- | ---------------------------------------- | -| and | a and b | 且 | | -| or | a or b | 或 | | -| not,! | not a, !a | 非 | not可作用于全局,但!只能作用于Constraint | -| xor | a xor b | 异或 | | -| optional | optional (a)-[e]->(b) | 对路径表示可选 | 只在Structure中对路径生效 | -| | | | | - -### 3.4 比较运算符 - -| 符号 | 示例 | 含义 | 备注 | -| ---- | -------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------ | -| == | a == b | 判等 | 只可比较int、float、string、node、edge,
其中,node、edge以id判断为准 | -| > | a > b | 大于 | | -| >= | a>=b | 大于等于 | | -| < | a < b | 小于 | | -| <= | a<=b | 小于等于 | | -| != | a != b | 不等 | | -| in | a in [1,2,3] | 包含 | | -| BT | a bt [1,5]
a bt (1,5) | between运算符,表示a在1,5之间,
方括号表示闭区间,
圆括号表示开区间 | 只可比较int、float、string | - -### 3.5 字符串运算符 - -| 符号 | 示例 | 含义 | 返回值 | 备注 | -| -------------- | ------------------------------------------------------------------------- | ----------------------------------------------- | ------ | ---------------------- | -| contains | contains(a,b) | 判断a字符串是否包含b字符串 | bool | | -| like,not like | a like b,a not like b | 字符串匹配判断,%为通配符 | bool | "abc" like "a%" 为true | -| concat,+ | concat(a,b),a+b,
concat(a,b,c),a+b+c
concat(a,...,f), a+...+f | 字符串拼接,concat支持n个入参,
也可用+处理 | string | 暂未实现 | -| length | length(a) | 返回字符串长度 | int | | -| strstr | strstr(str,start)
strstr(str,start,end) | 得到字符串子串,从1开始 | string | 暂未实现 | -| lower | lower(a) | 全部转换成小写 | string | 暂未实现 | -| upper | upper(a) | 全部转换成大写 | string | 暂未实现 | -| is_not_blank | is_not_blank(a) | 字符串不为空:"" | bool | 暂未实现 | - -### 3.6 类型转换运算符 - -| 符号 | 示例 | 含义 | 支持情况 | -| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -| cast(a, 'int'/'float'/'string') |
cast(1,'string') //转化成为str
cast('1', 'int') //转换成int | 将基本类型转换成为其他基本类型 | | -| to_date(time_str,format) | to_date('20220101', 'yyMMdd') //转换成为日期 | 将字符串转换成为日志类型
format可以为如下组合
时间类型
- s,秒//unix时间戳起
- m,分
- h,小时
- d,天
- M,月
- y,年
可组合,各种合理格式
- yyMMdd 年月日类型
- yyMMdd hh:mm:ss 为简化使用,支持
数字@日期方式初始化时间 | 暂未实现 | -| window(version_express, unit) | A.cost_every_day //A为用户,cost_every_day为一个多版本属性,表示每日的花销
A.cost_every_day.window(cur in [1@M,2@M,3@M], M) //获取1月、2月、3月的数据,按月取数据
A.cost_every_day.window(start > -30@d, d) //取近30天的数据,按天取数据
A.cost_every_day.window(end <-15@d, d) //取15天天前的所有数据,,按天取数据
A.cost_every_day.window(start > -30@d and end <-15@d, d) //取30天前,到15天前的数据,按天取数据,可进行组合
A.cost_every_day.window( (start > -30@d and end <-15@d) and (start > -7@d), d) //取30天前,到15天前的数据,以及近7天的数据,按天取数据,可进行组合 | 将多版本类型(multi_version)转换成list,方便参与计算。**version_express**包含三个关键词
- start,起始版本号
- end,终点版本号
- cur,当前版本号表达式为逻辑表达式,可通过and/or进行组合
**unit** 为属性单位,有如下类型
- M,按月获取数据
- d,按天获取数据
- seq,默认值,按照序列取数据,当没有unit时,按照seq来处理
注意:若是按月或者按天获取数据,则需要存在按天和按月聚合的数据 | 暂未实现 | - -### 3.7 list运算符(未实现) - -由于list可以支持的类型为有int、float、string、node、edge,故list支持的运算符按照不同类型进行区分。 -针对list对象,我们采用链式风格对列表进行计算。 -假设定义一个数组: - -``` -array = [{age:10},{age:20},{age:30}] -``` - -对该数组的操作预算符用法如下: - -| 符号表示 | 示例 | 含义 | 输入类型 | 输出类型 | 元素类型 | -| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -------- | ---------------- | ------------------------------------------------------------------ | -| max(alias_name) | array.mark_alias(a).max(a.age)
//输出为30 | 取最大值 | list | int/float/string | 支持int、float、string,但node和edge对象的属性为基础类型的可以支持 | -| min(alias_name) | array.mark_alias(a).min(a.age)
//输出为10 | 取最小值 | list | int/float/string | 支持int、float、string,但node和edge对象的属性为基础类型的可以支持 | -| sum(alias_name) | array.mark_alias(a).sum(a.age)
// 输出为60 | 对数组进行累加 | list | int/float | 支持int、float、string,但node和edge对象的属性为基础类型的可以支持 | -| avg(alias_name) | array.mark_alias(a).avg(a.age)
// 输出为20 | 取均值 | list | int/float | 支持int、float、string,但node和edge对象的属性为基础类型的可以支持 | -| count() | array.count()
//输出为3 | 取数组大小 | list | int | 支持所有类型 | -| filter(operator_express) | array.mark_alias(a).filter(a.age <18)
//输出为[{age:10}] | 对数组进行过滤,返回新的数组 | list | list | 支持所有类型 | -| sort(alias_name, 'desc'/'asc') | array.mark_alias(a).sort(a.age, 'desc')
//输出为[{age:30},{age:20},{age:10}] | 排序 | list | list | 支持所有类型 | -| slice(start_index,end_index) | array.mark_alias(a).slice(1,2)
//获取第一个到第二个的内容,输出为[{age:10},{age:20}] | 切片,从指定起点index到终点index,起点为1,取闭区间
- start_index,起点的index
- end_index,终止的index | | | 支持所有类型 | -| get(index) | array.mark_alias(a).get(1)
//获取第一个到第二个的内容,输出为{age:10} | 获取第index个元素,从1开始
若超过大小,则返回null | | | | -| str_join(alias_name, tok) | array.mark_alias(a).str_join(cast(a.age, 'string'), ',')
//将年龄转换成字符串,并且通过逗号生成字符串,输出为"10,20,30" | 字符串连接
- alias_name,数组中元素别名
- tok,连接符 | | | 只支持string | -| accumlate(operator, alias_name) | array.mark_alias(a).accumlate('\*', a.age) //累乘,结果为6000
array.mark_alias(a).accumlate('+', a.age) //累加等同于sun,输出为60 | 累计计算算子
- operator,为\*/
- alias_name,数组中元素别名 | | | 支持\*,+ | - -### 3.8 图聚合运算符 - -由于常常存在对图的聚合计算,此处定义一个图聚合算子,可以将一个子图按照指定模式聚合,并且根据别名进行数组计算,注意 - -| 符号 | 示例 | 含义 | 输入类型 | 输出类型 | 备注 | -| ------- | -------------------- | ---------------------------- | -------- | ---------------------------- | ------------------------------------------ | -| group() | group(a),group(a,b) | 将点或者边进行聚合,返回数组 | 图类型 | 后面需待具体算子,输出为数组 | 输入只能是点类型或者边类型,且必须带上起点 | - -图分组解释,假设我们存在如下数据:
- -![group_a_path](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*72A8QLOzeEcAAAAAAAAAAAAADtmcAQ/original) - -查询的子图模式为:
- -![group_a_data](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*oomuTKurb6UAAAAAAAAAAAAADtmcAQ/original) - -不同的group表达的结果如下: - -#### 3.8.1 示例1:group(A) - -此时对A进行分组,则如下操作返回的值为
- -> 返回类型为列表,由于整个子图分组成为了1个,所以返回的列表长度为1,后续结果只能输出1行数据
-> group(A).count(e1) // 对e1边进行计数,应当返回[2]
-> group(A).count(B) // 对子图的B类型进行统计计数,应当返回[2]
-> group(A).count(C) // 对子图的C类型进行统计计数,应当返回[4]
-> group(A).count(e2) //对e2的边进行计数,应当返回[5], 因为有5条边
- -#### 3.8.2 实例2:group(A,B) - -被分组的图数据变成
-![group_a_b](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*oomuTKurb6UAAAAAAAAAAAAADtmcAQ/original) -
- -> 返回类型为列表,由于整个子图分组成为了2个,所以返回的列表长度为2,后续结果只能输出2行数据
-> group(A,B).count(A) // 返回[1,1]
-> group(A,B),count(B) // 返回[1,1]
-> group(A,B).count(C) // 返回[3,1]
-> group(A,B).count(e1) // 返回[1,1]
-> group(A,B).count(e2) //返回[3,2]
- -#### 3.8.3 实例3:group(A,B,C) - -被分组的图数据变成如下
-![group_a_b_c](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*P7rpSZfyFdoAAAAAAAAAAAAADtmcAQ/original)
- -> 返回类型为列表,由于整个子图被分为了4个子图,所以返回的列表长度为4,后续结果只能输出4行数据
-> group(A,B,C).count(C) // 返回[1,1,1,1]
-> group(A,B,C).count(e2) // 返回[1,1,1,2]
- -注:由于子图可能被划分成为多个子图,并不对最终返回的数组保证顺序 - -#### 3.8.4 约束和限制 - -##### 约束1:不允许不包含起点 - -- group(B)/group(C) ,不允许分组时不包含起点,因为这样分组不能保证正确性 - -##### 约束2:不允许按边分组 - -- group(A, e1)/group(A, e2),不允许按照边进行分组,因为存在两个相同点之间多边场景,如果允许按边聚合,则会出现大量的重复节点,导致后续计算消耗激增,且目前尚未看到有必须按边聚合场景 - -##### 约束3:若使用了多个group,则不允许后出现的group点比前出现的group点多 - -``` -bNum = group(A).count(B) -eNum = group(A,B).count(e1) -``` - -``` -eNum = group(A,B).count(e1) -bNum = group(A).count(B) -``` - -原因为,当group(A)分组后,B会折叠,此时在对A,B进行group会导致结果不正确,这里主要是考虑实现因素的约束 - -### 3.9 取数操作符 - -为方便对图进行取数据,设定算子如下 - -| 符号 | 示例 | 含义 | 备注 | -| ------------- | --------------- | ---------- | ---- | -| . | A.id | 取属性 | | -| **label** | A.**label** | 返回类型 | | -| **from** | e.**from** | 返回起点id | | -| **to** | e.**to** | 返回终点id | | -| **direction** | e.**direction** | 取边的方向 | | - -由于KGDSL中不支持if语法,所以需要针对逻辑判断部分,使用类条件运算符算子代替
-**rule_value**
- -- 范式:rule_value (rule_name, true_value, false_value)
-- 作用:将规则真值转换为指定值,如果rule_name的规则运算结果为true,则返回true_value,如果为false,则返回falsevalue
- 举例: - -``` -//如果OnlineDiscount这个规则的运算结果为true,则返回1,否则返回null。 -rule_value("OnlineDiscount", 1, null) -``` - -**get_first_notnull**
- -- 范式:get_first_notnull (value1, value2, ..., valueN)
-- 作用:表示返回参数里第一个不为null的值,参数区为可变长度,可实现优先级的结果获取
- -``` -Share10("分享超10笔"): rakeBackCount > 10 -Share100("分享超100笔"): rakeBackCount > 100 -Price("定价")= get_first_notnull(rule_value("Share100", 0.5, null), rule_value("Share10", 0.8, null)) -``` - -通过上面两个udf组合,可实现任意if-else组合 - -### 3.10 日期操作符(未实现) - -日期类型支持如下计算操作 - -| 符号表示 | 示例 | 含义 | 输入类型 | 输出类型 | -| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------- | -------- | -| + | date1 = to_date('20220212', 'yyMMdd') //将字符串转换成日期
date2 = to_date('5','d') //将字符串转换成日期
date3 = date1 + date2 //相加,等于20220217 | 增加日期 | date | date | -| - | date1 = to_date('20220212', 'yyMMdd')
date2 = to_date('5','d')
date3 = date1 - date2 //相加,等于20220207 | 减去日志 | date | date | - -#### 3.10.1 日期简化形式 - -由于返回date类型均需要to_date进行转换,为了简化描述,可按照如下格式简化日期初始化
- -> 日期/单位
- -示例1:初始化日期简化模式
- -```sql -1@d -1@h -1@M -20221011@yyMMdd -``` - -示例2:取当前时间的相对时间
-由于存在大量的近30天、近7天等表达需求,故简化now()获取当前时间,示例如下 - -```sql -+1@d --1@d -+1@M -``` - -此外,还有其他日期函数作为补充 - -#### 3.10.2 now - -- 范式:now() -- 作用:日期计算函数,用户返回当前日期 - -#### 3.10.3 date_format - -- 范式:date_format(time, to_format)/date_format(time, from_format, to_format) -- 作用:日期格式化函数,将日期转换成为指定格式字符串,默认为yyyy-MM-dd HH:mm:ss / yyyyMMdd HH:mm:ss - 举例: - -``` -date1 = to_date('20220101', 'yyMMdd') -date_format(date1, 's') //转换成unix时间戳,值为 1640966400 -date_format(date1, 'yyMMdd hh:mm:ss') //转换成为指定格式,应当为 20220101 00:00:00 -``` - -## 4 基本语法 - -本章节使用场景进行语法介绍和应用 - -### 4.1 示例场景和需求 - -#### 4.1.1 示例schema - -假定schema如下
-![schema_example](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*hlQmQIuBBvwAAAAAAAAAAAAADtmcAQ/original) - -**User属性** - -| 属性名 | 类型 | 说明 | -| ------ | -------- | -------- | -| id | string | 主键id | -| name | string | 姓名 | -| age | int | 年龄 | -| gender | 性别概念 | 性别属性 | - -**Shop属性** - -| 属性名 | 类型 | 说明 | -| -------- | -------- | ------------ | -| id | string | 主键id | -| name | string | 店铺名 | -| category | 分类概念 | 店铺经验分类 | - -**(User)-[pay]->(User) 用户向用户转账** - -| 属性名 | 类型 | 说明 | -| ------ | ----- | -------- | -| amount | float | 转账数目 | - -**(User)-[visit]->(Shop) 用户浏览过某个商店** - -| 属性名 | 类型 | 说明 | -| --------- | ---- | ---------------- | -| timestamp | int | 浏览商店的时间戳 | - -**(User)-[own]->(Shop) 用户拥有某个商店** - -无属性 - -**(User)-[consume]->(Shop) 用户消费过某个商店** - -| 属性名 | 类型 | 说明 | -| --------- | ----- | ------------ | -| amount | float | 消费金额 | -| timestamp | int | 消费的时间戳 | - -#### 4.1.2 需求列表 - -| 需求编号 | 需求描述 | -| -------- | --------------------------------------------------- | -| 1 | 判断一个User是否是店主 | -| 3 | 统计一个Shop近7天、30天被浏览的次数 | -| 4 | 根据Shop近7天的次数,分层高关注量Shop和低关注量Shop | -| 5 | 根据Shop的近7天销量,得到消费最高的top3用户 | -| 6 | 判断一个用户转账是否收大于支 | -| 7 | 判断一个用户是否自己给自己转账 | -| 8 | 得到一个用户最近7天转过账的其他用户 | -| 9 | 用户拥有自己的商店,且在自己商店消费 | -| 10 | 统计User近7天有消费或者浏览过的店铺数目 | -| 11 | 统计每个User在某一Shop的消费总额 | - -### 4.2 整体语法描述 - -逻辑规则采用三段式语法表示,其语法结构,如下: - -``` -#Structure:定义匹配的子图结构。 -Structure { - // path desciption -} -#Constraint:定义上述Struct中,对实体和关系的约束条件、以及规则计算的表达式。 -Constraint { - // rule express -} -#Action:指定了对符合Structure和Constraint的结果进行的后置处理。 -Action { - // action desciption -} -``` - -定义新的逻辑谓词的语法结构,如下: - -``` -#Define用于定义新的逻辑谓词。它允许您创建符合特殊Structure和Constraint限制的自定义谓词。 -Define (s:sType)-[p:pType]->(o:oType) { - Structure { - // path desciption - } - Constraint { - // rule express - } -} -``` - -下面的章节里,我们将对Structure、Constraint、Action、Define的用法进行详细介绍。 - -### 4.3 Structure定义 - -该部分结构主要描述路径 - -#### 4.3.1 路径定义 - -路径的基本单元是边,多种边组合起来的连通图成为路径,Structure中可以描述多个路径,方便在不同场景下使用
- -> 在线业务存在多种非连通图需求,离线批量计算场景较少
- -路径描述按照ISO GQL方式进行描述,即如下三种示例 - -``` -Structure { - (s:User)-[p:own]->(o:Shop) -} -``` - -``` -Structure { - (s:User)-[p:own]->(o:Shop), (s)-[c:consume]->(o) -} -``` - -> 注意:别名的类型定义只能在一处定义,通过逗号表示两个边都必须存在
- -``` -Structure { - (s:User)-[p:own|consume]->(o:Shop) -} -``` - -#### 4.3.2 路径别名 - -Structure中主要目的是简化路径描述,多数场景下,我们需要对路径的存在性进行判定,为方面后续的规则计算,我们使用路径别名作为Constraint的路径存在性判断参数,如下 - -``` -Structure { - path: (s:User)-[p:own]->(o:Shop) -} -``` - -> 当s这个用户拥有一家店铺时,path为true,否则为false
- -``` -Structure { - path: (s:User)-[p:own]->(o:Shop), (s)-[c:consume]->(o) -} -``` - -> 当s这个用户拥有一家店铺,且在这个店铺进行了消费时,path为true,否则为false
- -``` -Structure { - path: (s:User)-[p:own|consume]->(o:Shop) -} -``` - -> 当s这个用户没有在任何一家店铺消费,也不拥有任何一家店铺时,path为false,否者为true
- -别名的优势在于可以简化path路径的描述,上述两个可以改成如下描述 - -``` -Structure { - ownPath: (s:User)-[p:own]->(o:Shop) - consumePath: (s)-[c:consume]->(o) -} -``` - -申明两个path
- -- "用户拥有自己的商店,且在自己商店消费" 可以表达成为ownPath and consumePath -- "用户拥有自己的商店或者在商店消费" 可以表达成为ownPath or consumePath - -#### 4.3.3 路径运算符 - -路径定义时,可以要求Structure中路径不是必须存在,ISO GQL的路径表达中已经对且、或、可选、非做了表达,我们和ISO GQL保持一致 - -``` -Structure { - path: (s:User)-[p:own]->(o:Shop), (s)-[c:consume]->(o) -} -``` - -``` -Structure { - path: (s:User)-[p:own|consume]->(o:Shop) -} -``` - -(未实现) - -``` -Structure { - not path: (s:User)-[p:own]->(o:Shop) -} -``` - -(未实现) - -``` -Structure { - optional path:(s:User)-[p:own]->(o:Shop), (s)-[c:consume]->(o) -} -``` - -### 4.4 Constraint语法 - -#### 4.4.1 单规则语法 - -Constraint中每一行作为一个规则,规则分为如下几类 - -- **逻辑规则** - -以 **规则英文名("规则说明"): 表达式** 这种格式进行表达,输出为布尔值。常用运算符有>、<、==、>=、<=、!=、+、-、\*、/、%等,运算符可以进行扩展。 - -- **计算规则** - -以 **规则英文名("规则说明")= 表达式** 进行表达,输出结果为数字或者文本,取决于表达式内容。 - -- **赋值规则** - -以 **别名.属性名=** **表达式** 没有规则名,仅允许Define中定义的别名进行属性赋值表达。此类规则仅在特定谓词的规则定义中有效。 - -以4.3中ownPath和consumePath为例 - -``` -Structure { - ownPath: (s:User)-[p:own]->(o:Shop) - consumePath: (s)-[c:consume]->(o) -} -Constraint { -} -``` - -``` -Structure { - optional ownPath: (s:User)-[p:own]->(o:Shop) - optional consumePath: (s)-[c:consume]->(o) -} -Constraint { - ownAndConsumeUser("用户拥有自己的商店或者在商店消费"): exist(ownPath) or exist(consumePath) -} -``` - -``` -Structure { - (s:Shop)<-[p:visit]-(o:User) -} -Constraint { - R1("7天内是否访问") : p.timestamp >= -7@d -} -``` - -> s可能存在很多个user访问,但是我们只处理7天内的边,第五行中不满足的o会被终止
- -#### 4.4.2 规则组语法 - -规则组可以将逻辑规则进行组合,主要目的是将逻辑计算层次化 - -``` -Structure { - (s:User) -} -Constraint { - R1("成年人"): s.age > 18 - - R2("男性"): s.gender == "男" - - // 下面这句是正确的,R3由R1和R2组合而成,就被视为是一条规则组 - R3("成年男性"): R1 and R2 - - // 下面这句是错误的,规则组里不允许有非规则的变量 - R3("成年男性"): R1 and s.gender == "男" -} -``` - -#### 4.4.3 聚合语法 - -支持聚合的算子有如下特性和限制 - -- 算子的输入必须为list类型 -- group语句可以将图进行分组,将若干条相同模式的路径进行聚合分组,当使用group时,聚合算子对整个图分组的点边进行聚合操作 -- 聚合算子只能针对以一个起点产生的子图进行聚合计算,**若需要一批起点产生的子图进行计算,则不在该文档支持范围内** - -由于需求中存在多种聚合类需求,4.1.2中存在统计需求列表如下 - -| 需求编号 | 需求描述 | -| -------- | --------------------------------------------------- | -| 3 | 统计一个Shop近7天、30天被浏览的次数 | -| 4 | 根据Shop近7天的次数,分层高关注量Shop和低关注量Shop | -| 5 | 根据Shop的近7天销量,得到消费最高的top3用户 | -| 6 | 判断一个用户转账是否收大于支 | -| 10 | 统计User近7天有消费或者浏览过的店铺数目 | -| 11 | 统计每个User在某一Shop的消费总额 | - -**示例1:需求10、需求3、需求4**
-![group_4_4_3_p1](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*FROwTLCV4HcAAAAAAAAAAAAADtmcAQ/original)
-假设当前时间为2023.1.10日,那么Alice近7天有消费或者浏览过的店铺数目应当为2,语法表达如下
- -``` -Structure { - (s:User)-[p:visit|consume]->(o:Shop) -} -Constraint { - R1("近7天内有访问或消费") : p.timestamp >= -7@d - // 忽略group(s)场景 - visitOrConsumeShopNum("统计User近7天有消费或者浏览过的店铺数目") = count(o) - - //显示表达 - visitOrConsumeShopNum("统计User近7天有消费或者浏览过的店铺数目") = group(s).count(o) -} -``` - -**示例2:判断用户是否收大于支**
-![group_4_4_3_p2](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*kJMiRbdw0BYAAAAAAAAAAAAADtmcAQ/original)
-上图中,Jobs、Alice、Mike属于收大于支,Bob属于支大于收,那么规则如下表示
- -``` -Structure { - outPath: (s:User)-[outP:pay]->(outU:User) - inPath: (inU:User)-[inP:pay]->(s) -} -Constraint { - // inPath不存在,则返回0,否则进行聚合计算 - inAmount("收入") = rule_value(inPath, group(s).sum(inP.amount), 0) - // outPath不存在,则返回0,否则进行聚合计算 - outAmount("支出") = rule_value(outPath, group(s).sum(outP.amount), 0) - - R2("收大于支"): inAmount > outAmount -} -``` - -**示例3:根据Shop的近7天销量,得到消费最高的top3用户(未实现)**
- -![group_4_4_3_p3](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*e6ijSZWfOUEAAAAAAAAAAAAADtmcAQ/original)
-上面数据实例中,top3为:Jobs、Mike、Alice
- -``` -Structure { - (s:Shop)<-[p:consume]-(o:User) -} -Constraint { - R1("7天内消费"): p.timestamp >= -7@d - R2("top3的用户"): group(s).desc(p.amount).limit(3) //注意,此时只会保留Jobs、Mike、Alice节点 -} -``` - -**示例4:统计每个User在某一Shop的销售量**
-假定数据如下
-![group_4_4_3_p4](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*PsPlR40fUAEAAAAAAAAAAAAADtmcAQ/original)
-该里需要统计Shop近7天浏览的次数,值得注意的是,Bob存在2条边,这两个需要进行聚合统计
- -``` -Structure { - (s:Shop)<-[p:consume]-(o:User) -} -Constraint { - R("7天内消费"): p.timestamp >= -7@d - // 用户消费总额上赋值 - userConsumeAmount('店铺销售总额') = group(s,o).sum(p.amount) //注意,此时会输出4个结果 -} -Action { - get(s.name, userConsumeAmount) -} -``` - -### 4.5 Define谓词规则语法 - -前面几个章节主要目的为路径、规则描述,本节主要目标是对谓词进行定义。谓词主要分为三个场景进行表达 - -- 实体类型和概念的归纳语义定义 -- 实体类型之间的逻辑谓词定义 -- 实体类型和基本类型之间的逻辑谓词定义 - -#### 4.5.1 实体类型和概念的归纳语义定义 - -关于实体和概念的介绍可以参见 [schema建模手册中的说明](./spgschema_tutorial.md)。
- -归纳语义(Induction),是指从一类有共同特征的实体中得出对这些实体概括性的概念,这种个体和概念之间的关系就是归纳关系。
-实体类型和概念间的归纳语义,通过语法规则表达如下:
- -``` -Define (s:TypeA)-[p:TypeP]->(o:TaxonomyOfTypeA/ConceptA) { - Structure { - // path desciption - } - Constraint { - // rule express - } -} -``` - -ConceptA是属于TaxonomyOfTypeA类型,上述规则表达含义为,TypeA类型的s在满足上述规则表达的前提下,可以通过TypeP谓词链接到ConceptA概念上。下面以示例举例:
-根据4.1.2的需求,我们可以将如下需求转化成为概念进行定义
- -| 需求编号 | 需求描述 | -| -------- | --------------------------------------------------- | -| 1 | 判断一个User是否是店主 | -| 4 | 根据Shop近7天的次数,分层高关注量Shop和低关注量Shop | -| 7 | 判断一个用户是否自己给自己转账 | - -示例1:判断一个User是否是店主
-判断是否是店主主要看名下是否有店铺
-假定已经按照概念建模创建了ShopKeeper概念,如下
-![concept_4_5_1_p1](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*LY8cSqBhYF8AAAAAAAAAAAAADtmcAQ/original)
-从实例图上可以看出,bob没有店不属于ShopKeeper,Alice有一个Hotel,所以应该属于ShopKeeper,我们可以通过语法将Alice归纳为ShopKeeper用户类别
- -``` -Define (s:User)-[p:belongTo]->(o:TaxonomyOfUser/ShopKeeper) { - Structure { - path: (s)-[ownP:own]->(shop:Shop) - } - Constraint { - R1("拥有店铺"): path - } -} -``` - -通过如上规则,则可以将概念和实体实例建立挂载关系
-示例2:根据Shop近7天的次数,分层高关注量Shop和低关注量Shop
-![concept_4_5_1_p2](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*RvHESr9YexsAAAAAAAAAAAAADtmcAQ/original)
-上图中Hotel被访问的较多,Drug Store访问很少,我们需要按照业务要求将他们和PopularShop和NamelessShop分别挂载上
- -``` -Define (s:Shop)-[p:belongTo]->(o:TaxonomyOfShop/PopularShop) { - Structure { - path: (s)<-[vP:visit]-(u:User) - } - Constraint { - R1("7天内消费"): vP.timestamp >= -7@d - // 当路径不存在时,浏览次数为0,否则对u进行统计 - visitsNum("浏览次数") = rule_value(path, group(s).count(u),0) - R2("热点商户"): visitsNum > ${hot_shop_threashold} - } -} -``` - -> 注:${hot_shop_threashold} 为阈值参数,需要在谓词使用时将具体值填入
- -``` -Define (s:Shop)-[p:belongTo]->(o:TaxonomyOfShop/NamelessShop) { - Structure { - path: (s)<-[vP:visit]-(u:User) - } - Constraint { - R1("7天内消费"): vP.timestamp >= -7@d - // 当路径不存在时,浏览次数为0,否则对u进行统计 - visitsNum("浏览次数") = rule_value(path, group(s).count(u),0) - R2("低关注量商户"): visitsNum < ${nameless_shop_threashold} - } -} -``` - -> 注:${nameless_shop_threashold} 为阈值参数,需要在谓词使用时将具体值填入
- -#### 4.5.2 实体类型之间逻辑谓词定义 - -可使用类型之间定义需求如下
- -| 需求编号 | 需求描述 | -| -------- | ----------------------------------- | -| 7 | 判断一个用户是否自己给自己转账 | -| 8 | 得到一个用户最近7天转过账的其他用户 | -| 11 | 统计每个User在某一Shop的销售量 | - -基本定义和4.5.1中基本一致,按照需求新增schema
-![schema_4_5_2](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*3c--RL7N-9gAAAAAAAAAAAAADtmcAQ/original)
- -主要三种 - -- (s:User)-[p:transSelf]->(s) 自己向自己转账 -- (s:User)-[p:trans7Days]->(o:User) 7天内有转账的用户 -- (s:Shop)-[p:consumeAmount]->(o:User) 商铺某个用户的销售额 - -示例1:判断一个用户是否自己给自己转账
- -``` -Define (s:User)-[p:transSelf]->(s) { - Structure { - path: (s)-[pp:pay]->(s) - } - Constraint { - R1("自己向自己转账"): path - } -} -``` - -示例2:7天内有转账的用户
- -``` -Define (s:User)-[p:trans7Days]->(o:User) { - Structure { - path: (s)-[pp:pay]->(o) - } - Constraint { - R1("7天内消费"): p.timestamp > -7@d - R2("存在转账"): path - } -} -``` - -示例3:商铺对一个用户的销售总额
- -``` -Define (s:Shop)-[p:consumeAmount]->(o:User) { - Structure { - path: (s)<-[cp:consume]-(o) - } - Constraint { - R1("存在交易用户"): path - p.amount = group(s,o).sum(cp.amount) //统计所有的交易额 - } -} -``` - -#### 4.5.3 实体类型和基本类型之间逻辑谓词定义 - -前两章节主要是和实体类型和概念之间语义链接,实际上存在部分需求,和任何其他类型没有交互,例如如下需求
- -| 需求编号 | 需求描述 | -| -------- | --------------------------------------- | -| 1 | 判断一个User是否是店主 | -| 3 | 统计一个Shop近7天、30天被浏览的次数 | -| 6 | 判断一个用户转账是否收大于支 | -| 7 | 判断一个用户是否自己给自己转账 | -| 9 | 用户拥有自己的商店,且在自己商店消费 | -| 10 | 统计User近7天有消费或者浏览过的店铺数目 | - -如上需求,我们可以增加User属性
- -| 属性名 | 类型 | 说明 | -| -------------------------- | ------- | ------------------------------- | -| isShopOwner | boolean | 是否是店主 | -| isIncomeLargeOutcome | boolean | 是否收大于支 | -| 7daysVisitOrConsumeShopNum | int | 近7天有消费或者浏览过的店铺数目 | - -Shop可以增加属性
- -| 属性名 | 类型 | 说明 | -| -------------- | ---- | -------------- | -| 7daysVisitNum | int | 近7天浏览人数 | -| 30daysVisitNum | int | 近30天浏览人数 | - -这些新增属性,可通过规则进行定义,避免出现实际的数据新导入
-示例1:近7天有消费或者浏览过的店铺数目
- -``` -Define (s:User)-[p:7daysVisitOrConsumeShopNum]->(o:int) { - Structure { - path: (s)-[vc:visit|consume]->(shop:Shop) - } - Constraint { - R("7天内消费or浏览"): p.timestamp > -7@d - o = group(s).count(shop) //赋值 - } -} -``` - -示例2:近7天浏览店铺的用户
- -``` -Define (s:Shop)-[p:7daysVisitNum]->(o:int) { - Structure { - path: (s)<-[p:visit]-(u:User) - } - Constraint { - R("7天内浏览"): p.timestamp > -7@d - o = group(s).count(u) //赋值 - } -} -``` - -示例3:近30天浏览店铺的用户
- -``` -Define (s:Shop)-[p:30daysVisitNum]->(o:int) { - Structure { - path: (s)<-[p:visit]-(u:User) - } - Constraint { - R("30天内浏览"): p.timestamp > -30@d - o = group(s).count(u) //赋值 - } -} -``` - -### 4.6 Action语法 - -Action中支持多种操作: - -- createNodeInstance/createEdgeInstance:用于因果的逻辑结果的语义表达 -- get :输出匹配的结果,包括实体、关系以及属性等内容。 - -具体用法如下面的例子展示:
- -#### 4.6.1 Causal logic semantics - -在事理图谱中,因果关系基本需要在满足一定条件才成立,本例引用SPG白皮书中金融事理图谱章节的案例进行表述。事理描述如下图:
-![cau_4_6](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*Kt8mQpZQpfYAAAAAAAAAAAAADtmcAQ/original)
- -#### 4.6.1.1 createNodeInstance - -当概念之间满足因果语义的条件时,createNodeInstance将创建一个新的实例。本例中创建新的事件实例,具体使用方式如下: - -``` -Define (s: `ProductChain.TaxonomyOfCompanyAccident`/`周期性行业头部上市公司停产事故`)-[p: leadTo]->(o: `ProductChain.TaxonomyOfIndustryInfluence`/`成本上升`) { - Structure { - (s)-[:subject]->(c:ProductChain.Company) - (c)-[:belongIndustry]->(d:ProductChain.Industry) - (d)-[:downstream]->(down:ProductChain.Industry) - } - Constraint { - // 这里没有定义约束条件 - } - Action { - downEvent = createNodeInstance( - type=ProductChain.IndustryInfluence, - value={ - subject=down.id - objectWho="上升" - influenceDegree="上升" - indexTag="成本" - } - ) - } -} -``` - -**createNodeInstance参数说明:**
- -- type:这里需要指定我们创建一个什么样的实体类型实例 -- value:此处为实例的具体属性值,由kv对构成,k为schema中定义的属性名,v为具体值,可为常量,也可以为Structure和Constraint中的各种变量。注意:若k不存在于schema中或者值不满足schema定义,则为非法值 - **返回值:**
-- 具体实例别名,不能和Structure、Constraint中的变量重合 - -本例中创建一个新的事件实例downEvent,该事件类型为ProductChain.IndustryInfluence,主体为Structure中的down实体,属性代表该产业成本上升 - -##### 4.6.1.2 createEdgeInstance - -也可以通过createEdgeInstance创建一条新的关系,可将触发的事件实例和具有因果关系的事件实例进行关联。具体使用方式如下: - -``` -Define (s: `ProductChain.TaxonomyOfCompanyAccident`/`周期性行业头部上市公司停产事故`)-[p: leadTo]->(o: `ProductChain.TaxonomyOfIndustryInfluence`/`成本上升`) { - Structure { - (s)-[:subject]->(c:ProductChain.Company)-[:belongIndustry]->(d:ProductChain.Industry)-[:downstream]->(down:ProductChain.Industry) - } - Constraint { - - } - Action { - downEvent = createNodeInstance( - type=ProductChain.IndustryInfluence, - value={ - subject=down.id - objectWho="上升" - influenceDegree="上升" - indexTag="成本" - } - ) - #在事件s和新生成的downEvent建立一条leadTo边,代表一个事件实例导致了另外一个事件实例 - createEdgeInstance( - src=s, - dst=downEvent, - type=leadTo, - value={} - ) - } -} -``` - -**createEdgeInstance参数说明:**
- -- type:指定边类型 -- src:起点的别名,必须存在Structure中,或者是Action中通过createNodeInstance创建的实例 -- dst:终点的别名,同样满足src的约束 -- value:边的属性值,也为kv对,可为空 - -**返回值:**
- -- 无,主要原因为,在Action中,边实例不会被再次引用 - -#### 4.6.2 数据输出 - -get的作用是获取Structure或者Constraint中的实体、关系、属性或者临时变量,具体使用方式如下: - -``` -//可通过get获取Structure或者Constraint中的属性或者临时变量 - -Structure { - path: (s:Shop)<-[vP:visit]-(u:User) -} -Constraint { - R("7天内消费"): vP.timestamp >= -7@d - visitsNum("浏览次数") = rule_value(path, group(s).count(u),0) - R2("热点商铺"): visitsNum > 1000 -} -Action { - // 获取shop和user点的id,并且返回Constraint中的visitsNum变量 - get(s.id, u.id, visitsNum) -} -``` diff --git a/docs/_tutorial/spgschema/index.md b/docs/_tutorial/spgschema/index.md deleted file mode 100644 index 67c639e..0000000 --- a/docs/_tutorial/spgschema/index.md +++ /dev/null @@ -1,523 +0,0 @@ ---- -title: SPG知识建模 -nav: - second: - title: SPG知识建模 - order: 2 ---- - -## 1 Schema类型 - -在这个章节里,我们将介绍SPG里的实体、事件和概念类型等基础知识。 - -### 1.1 实体类型 (EntityType) - -实体类型,定义了具有共同数据结构(特征)的一类实例的集合,是一种多元要素的复合节点类型。通常实体类型用于描述客观世界中的一个具体事物,比如公司、学校、书籍等等。再以学校这个实体类型举例,它的实例可以有“xxx市第一小学”、“xxx大学”等。 - -实体类型的定义主要由属性和关系组成,属性的值域可以是文本、整数和浮点数这样的基础类型,也可以是概念、实体等高级类型。使用了高级类型做值域的属性,会同时产生从自身指向高级类型的关系。这也是SPGSchema的一个重要特性。 - -关系的定义需要在起点实体类型上定义,方向始终为出边方向。关系上也可以再定义属性,但值域只允许是基础类型。 - -实体类型会包含几个默认属性,在知识建模中无须额外定义: - -- id (主键,必填) -- name (实体名称) -- description (实体描述) - -以学校举例,实体类型的属性可以有如下: - -```yaml -enName(英文名): Text -shortName(简称): Text -founder(创办人): Person -foundDate(创立日期): STD.Date -category(类别): TaxonomySchool -address(地址): Text -``` - -那学校实体类型的实例可以是: - -```json -{ - "id": "zjdx", - "name": "浙江大学", - "enName": "Zhejiang University", - "shortName": "浙大、ZJU", - "founder": "林启", - "foundDate": "18970521", - "category": "公立大学", - "address": "西溪校区:杭州市西湖区天目山路148号" -} -``` - -### 1.2 事件类型 (EventType) - -在实体类型的基础上,加入主体、客体、时间、空间这四类要素,是对动态行为的建模,旨在反映在不同空间、时间区间上事物的状态。例如政策事件、行业事件、用户行为事件,都属于事件类型。其中主体要素是必须具备的,其余要素是可选的。 - -事件类型跟实体类型都是对客观事物的抽象描述,但实体类型包含的是相对静态的客观属性和关系,缺少了随时间、空间的发展而产生的动态变化,从而存在片面性,缺乏了深层语义信息。例如表达“XX公司在10月28日在深交所挂牌上市”。 - -以企业事件类型举例,其属性可以有如下: - -```yaml -subject(主体): Company -object(客体): Text -time(时间): STD.Date -location(地点): Text -behavior(行为): Behavior -``` - -那学校实体类型的实例可以是: - -```json -{ - "id": "2023100820394930", - "name": "XX公司在10月28日在深交所挂牌上市", - "subject": "XX公司", - "object": "深交所", - "time": "20231028", - "location": "深交所", - "behavior": "上市" -} -``` - -### 1.3 概念类型 (ConceptType) - -概念是对一类具有共同特征的实体的抽象化描述,通常是用于描述实体/事件类型的分类。比如学校分类概念:小学、中学、大学。概念跟实体的区别是概念无法指代一个客观世界的具体事物,它是对一类事物的总结概括型描述。 - -同时,概念和概念之间还默认具备上位关系(可以在建模时候选择上位关系谓词),通过该关系形成往上泛化、往下具化的抽象描述。比如学校分类概念的“初级中学”、“高级中学”的上位关系是“中学”。 - -实体类型和概念类型的区别,实体类型往往跟业务强相关,比如电商业务的用户、商户和商品等。而概念类型则通常和行业共识、领域常识强相关,比如学生、白领、公务员这些个概念是从职业角度对用户的分类概括,又比如五星商户、高信用商户这些概念是对商户的分类概括,再比如数码产品、母婴产品是对商品的分类概括。 - -概念类型在创建时,会默认包含如下属性: - -- name (概念名称,必填) -- alias (概念别名,选填) -- stdId (标准ID,选填) - -概念在导入的时候,使用短横-符号作为上位关系分隔符,每个概念需要完整给出所有的上位关系。 -以学校分类概念举例概念实例: - -```json -[ - { - "name": "公立院校", - "alias": "公立,公立学校" - }, - { - "name": "公立院校-公立大学", - "alias": null - }, - { - "name": "公立院校-公立大学-公立综合类大学", - "alias": "公立综合大学" - } -] -``` - -### 1.4 类型间的语义关联 - -![image.png](https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*3s79QouHNicAAAAAAAAAAAAADtmcAQ/original) - -- HYP: 上位关系(Hypernym),是指一种更广泛或更一般的概念包含或包括另一种更具体或更特定的概念的关系。目前可用的谓词为isA、locateAt,其他谓词尚待扩展。 -- SYNANT: 同义反义关系(Synonymy/Antonymy),表达概念之间是同义还是反义的关系。目前可用的谓词有synonym、antonym,其他谓词尚待扩展。 -- CAU: 因果关系(Causal),表示指一个事件或行为(原因)导致另一个事件或行为(结果)发生的一类关系。目前可用的谓词有leadTo,其他谓词尚待扩展。 -- SEQ: 顺承关系(Sequential),是连续发生的事情或动作,这些事情或动作有先后顺序。目前可用的谓词有happenedBefore,其他谓词尚待扩展。 -- IND: 归纳关系(Induction),是指从一类有共同特征的实体中得出对这些实体概括性的概念,这种个体和概念之间的关系就是归纳关系。目前可用的谓词有belongTo,其他谓词尚待扩展。 -- INC: 包含关系(Inclusion),表达部分与整体的关系。目前可用的谓词有isPartOf,其他谓词尚待扩展。 - -## 2 声明式Schema - -在声明式Schema里不定义算子,算子由KNext的发布来绑定(算子开发参考[KNext教程](../knext/index.md))。 - -### 2.1 关键字 - -``` -namespace - -EntityType, ConceptType, EventType, ->, STD.*, Text, Float, Integer - -desc, constraint, value, properties, relations, rule, hypernymPredicate - -NotNull, MultiValue, Enum, Regular -``` - -> -> 用于表达类型的继承关系,A -> B -> -> STD.\*表示以STD.开头的都是预留关键字,作标准类型名称 - -### 2.2 基础句法 - -类似YAML,以缩进作为作用域的表示。缩进建议使用4个空格(Tab符会被当做两个空格) - -- **A(B): C** - - A为类型/属性的英文名 - - B为类型/属性的中文名称 - - C为取值 -- **A(B)->P** - - A为类型的英文名 - - B为类型的中文名称 - - P为要继承自的父类型 -- **namespace A** - - A表示项目前缀,在Schema文件的第一行必须出现。项目前缀会在Schema提交的时候自动拼接到实体类型名称的前面 -- **[[...]]** - - 规则脚本的定界符,仅用于rule的定义,类似于Python的"""用法 - -声明式Schema脚本采用逐行解析的方式,定义上要遵循顺序原则,即父类型要在子类型之前定义、属性上使用的类型也需要在其所属类型定义之前先定义好。 - -### 2.3 语法结构 - -总共分类6层缩进,按缩进的多少依次为: - -- 第一层(无缩进):定义类型、命名空间 -- 第二层:定义类型的元信息,比如描述、属性、关系等 -- 第三层:定义属性/关系的名称和类型 -- 第四层:定义属性/关系的元信息,比如约束、子属性、逻辑规则等 -- 第五层:定义子属性的名称和类型 -- 第六层:定义子属性的元信息,比如描述、约束 - -```yaml -namespace DEFAULT - -TypeA(实体类型A): EntityType - desc: 实体类型描述 - properties: - property1(属性1): STD.ChinaMobile - desc: 属性1的描述 - constraint: NotNull, MultiValue - properties: - property2(属性1的子属性): Text - desc: 属性1的子属性,枚举约束 - constraint: NotNull, Enum="A,B,C" - property3(属性1的子属性): Text - desc: 属性1的子属性,正则约束 - constraint: Regular="^abc[0-9]+$" - property4(属性4): Text - rule: [[ - Define property4... - ]] - relations: - relation1(关系1): TypeA - desc: 关系1的描述 - properties: - confidence(置信度): Float - rule: [[ - Define relation1... - ]] - -TypeB(实体类型B) -> TypeA: - desc: 这是实体类型A的子类型 -``` - -#### 2.3.1 定义实体类型 - -```yaml -# 以下定义一个公司的实体类型 -Company(公司): EntityType - -# 以下是定义一个继承自公司的实体类型 -ListedCompany(上市公司) -> Company: -``` - -##### 2.3.1.1 定义属性和关系 - -```yaml -Company(公司): EntityType - # 这里是公司的描述 - desc: 公司的描述 - properties: - # 这里定义属性 - address(地址): Text - # 这里定义地址属性为非空约束,除此还可以定义MultiValue(多值,英文逗号分割)、Enum(枚举)和Regular(正则) - constraint: NotNull - industry(行业): Industry - # 每个类型会默认创建id、name和description属性,都是Text类型 - # id(主键): Text - # name(名称): Text - # description(描述): Text - relations: - # 这里定义关系 - subCompany(子公司): Company -``` - -##### 2.3.1.2 定义子属性 - -```yaml -Company(公司): EntityType - desc: 公司的描述 - properties: - address(地址): Text - # 这里定义地址的子属性置信度 - confidence(置信度): Float - industry(行业): Industry -``` - -##### 2.3.1.3 定义谓词逻辑 - -```yaml -Company(公司): EntityType - desc: 公司的描述 - relations: - risk(风险关联): Company - # 这里定义关系的谓词逻辑,使用 [[ 和 ]] 作为逻辑规则的定界符 - rule: [[ - Define (s:Comapny)-[p:risk]->(o:Company) { - ... ... - } - ]] -``` - -#### 2.3.2 定义概念类型 - -```yaml -Industry(公司行业分类): ConceptType - # 这里定义概念的上下位关系谓词,默认为isA,可以指定isA和locateAt - hypernymPredicate: isA -``` - -#### 2.3.3 定义事件类型 - -```yaml -CompanyRiskEvent(公司风险事件): EventType - properties: - # 这里定义事件类型的主体为公司,事件类型必须定义主体subject - subject: Company -``` - -### 2.4 建模示例 - -```yaml -namespace Medical - -Symptom(症状): EntityType - -Drug(药品): EntityType - -Indicator(医学指征): EntityType - -BodyPart(人体部位): ConceptType - hypernymPredicate: isA - -HospitalDepartment(医院科室): ConceptType - hypernymPredicate: isA - -Disease(疾病): EntityType - properties: - complication(并发症): Disease - constraint: MultiValue - - commonSymptom(常见症状): Symptom - constraint: MultiValue - - applicableDrug(适用药品): Drug - constraint: MultiValue - - department(就诊科室): HospitalDepartment - constraint: MultiValue - - diseaseSite(发病部位): BodyPart - constraint: MultiValue - - relations: - abnormal(异常指征): Indicator - properties: - range(指标范围): Text - color(颜色): Text - shape(性状): Text -``` - -## 3 对象化Schema - -每次Schema变更发布后,根据项目前缀生成一个python类,比如medical例子:
-knext/examples/medical/schema/medical_schema_helper.py - -> 类名为项目前缀名称 -> 类的成员变量为该项目下的类型名称 - -```python -class Medical: - def __init__(self): - self.Disease = self.Disease() - self.Symptom = self.Symptom() - self.Drug = self.Drug() - self.BodyPart = self.BodyPart() - self.HospitalDepartment = self.HospitalDepartment() - pass - - class Disease: - __typename__ = "Medical.Disease" - id = "id" - name = "name" - commonSymptom = "commonSymptom" - complication = "complication" - applicableDrug = "applicableDrug" - department = "department" - diseaseSite = "diseaseSite" - - def __init__(self): - pass - - class Symptom: - __typename__ = "Medical.Symptom" - id = "id" - name = "name" - - def __init__(self): - pass - - class Drug: - __typename__ = "Medical.Drug" - id = "id" - name = "name" - - def __init__(self): - pass - - class BodyPart: - __typename__ = "Medical.BodyPart" - id = "id" - name = "name" - alias = "alias" - stdId = "stdId" - - def __init__(self): - pass - - class HospitalDepartment: - __typename__ = "Medical.HospitalDepartment" - id = "id" - name = "name" - alias = "alias" - stdId = "stdId" - - def __init__(self): - pass -``` - -用户使用的时候,代码如此写: - -> 需要先import项目schema类 - -```python -from knext.examples.medical.schema.medical_schema_helper import Medical - -if __name__ == '__main__': - - disease_name = Medical.Disease.name - ... ... - common_symptom = Medical.Disease.commomSymptom - ... ... - - # 加工链路映射组件定义 - mapping_disease = EntityMappingComponent( - spg_type=MEDICAL.Disease - ).add_field("id", "id") \ - .add_field("name", Medical.Disease.name) \ - .add_field("commonSymptom", Medical.Disease.commonSymptom) \ - .add_field("applicableDrug", Medical.Disease.applicableDrug) \ - .add_field("complication", Medical.Disease.complication) -``` - -## 4 通过python API创建schema - -### 4.1 接口 - -#### 4.1.1 初始化 - -```python -schema = Schema() -``` - -#### 4.1.2 Schema类接口 - -```python -session = schema.create_session() -``` - -> create_session代表创建一个Schema变更的Session,在Session里会包含所有当前项目的Schema信息 - -#### 4.1.3 Session类接口 - -```python -session.create_type(disease) -session.update_type(disease) -session.delete_type(disease) -session.commit() -``` - -> create_type代表创建类型、update_type代表更新类型、delete_type代表删除类型 -> -> commit为提交Schema变更 - -### 4.2 完整例子 - -```python -schema = Schema() - -# 创建session -session = schema.create_session() - -# 以上面的建模例子,用代码实现 -hospital_department = ConceptType( - name="Medical.HospitalDepartment", - name_zh="医院科室", - hypernym_predicate=HypernymPredicateEnum.IsA -) - -body_part = ConceptType( - name="Medical.BodyPart", - name_zh="人体部位", - hypernym_predicate=HypernymPredicateEnum.IsA -) - -drug = EntityType( - name="Medical.Drug", - name_zh="药品" -) - -symptom = EntityType( - name="Medical.Symptom", - name_zh="症状" -) - -disease = EntityType( - name="Medical.Disease", - name_zh="疾病", - properties=[ - Property( - name="commonSymptom", - name_zh="常见症状", - object_type_name="Medical.Symptom" - ), - Property( - name="applicableDrug", - name_zh="适用药品", - object_type_name="Medical.Drug" - ), - Property( - name="department", - name_zh="就诊科室", - object_type_name="Medical.HospitalDepartment" - ), - Property( - name="diseaseSite", - name_zh="发病部位", - object_type_name="Medical.BodyPart" - ), - Property( - name="complication", - name_zh="并发症", - object_type_name="Medical.Disease" - ) - ] -) - -# 定义创建类型 -session.create_type(hospital_department) -session.create_type(body_part) -session.create_type(drug) -session.create_type(symptom) -session.create_type(disease) - -# 提交Schema变更 -session.commit() -``` diff --git a/docs/_example/enterprise-supply-chain/builder.en-US.md b/docs/old_example/enterprise-supply-chain/builder.en-US.md similarity index 100% rename from docs/_example/enterprise-supply-chain/builder.en-US.md rename to docs/old_example/enterprise-supply-chain/builder.en-US.md diff --git a/docs/_example/enterprise-supply-chain/data.en-US.md b/docs/old_example/enterprise-supply-chain/data.en-US.md similarity index 100% rename from docs/_example/enterprise-supply-chain/data.en-US.md rename to docs/old_example/enterprise-supply-chain/data.en-US.md diff --git a/docs/_example/enterprise-supply-chain/index.en-US.md b/docs/old_example/enterprise-supply-chain/index.en-US.md similarity index 100% rename from docs/_example/enterprise-supply-chain/index.en-US.md rename to docs/old_example/enterprise-supply-chain/index.en-US.md diff --git a/docs/_example/enterprise-supply-chain/model.en-US.md b/docs/old_example/enterprise-supply-chain/model.en-US.md similarity index 100% rename from docs/_example/enterprise-supply-chain/model.en-US.md rename to docs/old_example/enterprise-supply-chain/model.en-US.md diff --git a/docs/_example/enterprise-supply-chain/query.en-US.md b/docs/old_example/enterprise-supply-chain/query.en-US.md similarity index 100% rename from docs/_example/enterprise-supply-chain/query.en-US.md rename to docs/old_example/enterprise-supply-chain/query.en-US.md diff --git a/docs/_example/index.en-US.md b/docs/old_example/index.en-US.md similarity index 100% rename from docs/_example/index.en-US.md rename to docs/old_example/index.en-US.md diff --git a/docs/_example/medical/index.en-US.md b/docs/old_example/medical/index.en-US.md similarity index 100% rename from docs/_example/medical/index.en-US.md rename to docs/old_example/medical/index.en-US.md diff --git a/docs/_example/risk-mining/index.en-US.md b/docs/old_example/risk-mining/index.en-US.md similarity index 100% rename from docs/_example/risk-mining/index.en-US.md rename to docs/old_example/risk-mining/index.en-US.md diff --git a/docs/_quick-start/contribution.en-US.md b/docs/old_quick-start/contribution.en-US.md similarity index 100% rename from docs/_quick-start/contribution.en-US.md rename to docs/old_quick-start/contribution.en-US.md diff --git a/docs/_quick-start/index.en-US.md b/docs/old_quick-start/index.en-US.md similarity index 100% rename from docs/_quick-start/index.en-US.md rename to docs/old_quick-start/index.en-US.md diff --git a/docs/_quick-start/install.en-US.md b/docs/old_quick-start/install.en-US.md similarity index 100% rename from docs/_quick-start/install.en-US.md rename to docs/old_quick-start/install.en-US.md diff --git a/docs/_tutorial/index.en-US.md b/docs/old_tutorial/index.en-US.md similarity index 100% rename from docs/_tutorial/index.en-US.md rename to docs/old_tutorial/index.en-US.md diff --git a/docs/_tutorial/knext/index.en-US.md b/docs/old_tutorial/knext/index.en-US.md similarity index 100% rename from docs/_tutorial/knext/index.en-US.md rename to docs/old_tutorial/knext/index.en-US.md diff --git a/docs/_tutorial/spg2lpg/index.en-US.md b/docs/old_tutorial/spg2lpg/index.en-US.md similarity index 100% rename from docs/_tutorial/spg2lpg/index.en-US.md rename to docs/old_tutorial/spg2lpg/index.en-US.md diff --git a/docs/_tutorial/spgreasoner/index.en-US.md b/docs/old_tutorial/spgreasoner/index.en-US.md similarity index 100% rename from docs/_tutorial/spgreasoner/index.en-US.md rename to docs/old_tutorial/spgreasoner/index.en-US.md diff --git a/docs/_tutorial/spgschema/index.en-US.md b/docs/old_tutorial/spgschema/index.en-US.md similarity index 100% rename from docs/_tutorial/spgschema/index.en-US.md rename to docs/old_tutorial/spgschema/index.en-US.md