You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pyshacl无法验证并序列化新推断图问题求助

pyshacl执行SPARQL Construct规则无输出排查

我在用pyshacl(Python的RDF图与SHACL验证库)时遇到问题:SHACL规则图中的SPARQL Construct子句本该创建新实例并关联现有实例,生成包含新数据的图,但验证返回成功后却没有任何输出实例;相同的SPARQL查询在GraphDB查询编辑器中能得到预期结果。

相关代码

from rdflib import *
from pyshacl import validate

ontology = Graph().parse("./graphs/DMN-RDF-Dicon-OCQA-Tbox.ttl",
                             format="ttl")
example_building = Graph().parse("./graphs/Duplex_A_20110505_LBD.ttl",
                                     format="ttl")

combined_graph = ontology + example_building  # 合并本体与实例图
rules_graph = Graph().parse("testing.ttl",
                                format="ttl")  # 加载SHACL规则图

# 执行验证并应用规则
conforms, inferred_graph, string = validate(combined_graph, shacl_graph=rules_graph,
                                            data_graph_format='turtle', shacl_graph_format='turtle',
                                            debug=True, advanced=True, inplace=True)

# 合并原始图与推断图
new_graph = combined_graph + inferred_graph

# 序列化新图
new_graph.serialize(
        destination="Inferred_geometry_inspections.ttl", format="ttl")

SHACL规则图(省略部分前缀)

{prefixes}
      dmn:prepare_inspections
    a sh:NodeShape ;
    sh:targetNode owl:Thing ;
    
    sh:rule [
        a sh:SPARQLRule ;
        sh:comment "Select all of eligible objects and create inspections";
        sh:construct """        
 {prefixes}

        CONSTRUCT {
            ?this ocqa:hasInspection ?Inspection_Number_Of_Risers.
?Inspection_Number_Of_Risers a <http://www.DMN-RDF.org/DMN#Inspection_Number_Of_Risers>.
?ISCode a <http://www.DMN-RDF.org/DMN#ISCode>.
?Agent a <https://w3id.org/digitalconstruction/0.5/Agents#Agent>.
?InspectionEquipment a <https://w3id.org/ocqa#InspectionEquipment>.
?one_time a <http://www.DMN-RDF.org/DMN#one_time>.
?Location a <https://w3id.org/digitalconstruction/0.5/Entities#Location>.
?InspectionProcedure a <https://w3id.org/ocqa#InspectionProcedure>.
}

    WHERE{
        SELECT ?this ?Inspection_Number_Of_Risers ?ISCode ?Agent ?InspectionEquipment ?one_time ?Location ?InspectionProcedure
 WHERE {
BIND(IRI(CONCAT("inst:Inspection_Number_Of_Risers_", STR(CEIL((RAND() * 30000))))) as ?Inspection_Number_Of_Risers)
BIND(IRI(CONCAT("inst:ISCode_", STR(CEIL((RAND() * 30000))))) as ?ISCode)
BIND(IRI(CONCAT("inst:Agent_", STR(CEIL((RAND() * 30000))))) as ?Agent)
BIND(IRI(CONCAT("inst:InspectionEquipment_", STR(CEIL((RAND() * 30000))))) as ?InspectionEquipment)
BIND(IRI(CONCAT("inst:one_time_", STR(CEIL((RAND() * 30000))))) as ?one_time)
BIND(IRI(CONCAT("inst:Location_", STR(CEIL((RAND() * 30000))))) as ?Location)
BIND(IRI(CONCAT("inst:InspectionProcedure_", STR(CEIL((RAND() * 30000))))) as ?InspectionProcedure)
?this a <https://pi.pauwel.be/voc/buildingelement#Stair> .
?Property a <https://w3id.org/opm#Property> .
        ?this <http://lbd.arch.rwth-aachen.de/props#actualNumberOfRisers> ?Property .
        }
    }
   """ ;
    ] ;
.

排查与解决方法

1. 修正inplace=True参数的误用

代码中设置了inplace=True,这会让pyshacl直接将推断结果写入原始的combined_graph,导致inferred_graph为空。后续合并空图等于没有添加新数据。

  • 解决:要么移除inplace=True(默认值为False),让inferred_graph接收推断结果;要么直接序列化combined_graph,无需再合并inferred_graph。

修改后的验证代码示例:

conforms, inferred_graph, string = validate(
    combined_graph,
    shacl_graph=rules_graph,
    data_graph_format='turtle',
    shacl_graph_format='turtle',
    debug=True,
    advanced=True
)

2. 检查数据匹配条件

规则的WHERE子句仅匹配https://pi.pauwel.be/voc/buildingelement#Stair类型且带有actualNumberOfRisers属性的实例,需确认:

  • combined_graph中确实存在符合条件的实例
  • IRI拼写、大小写完全一致(比如本体中的类IRI是否和规则中的完全匹配)
  • 可以单独用rdflib查询combined_graph,验证是否能返回预期的?this实例:
query = """
SELECT ?this WHERE {
    ?this a <https://pi.pauwel.be/voc/buildingelement#Stair> .
    ?this <http://lbd.arch.rwth-aachen.de/props#actualNumberOfRisers> ?p .
}
"""
results = combined_graph.query(query)
print([row for row in results])  # 查看是否有结果

3. 显式定义SPARQL Construct中的前缀

规则中用{prefixes}占位符,但pyshacl对SPARQL规则内的前缀解析可能依赖显式定义。建议在Construct字符串开头直接写出所有用到的前缀,避免依赖外部前缀:

sh:construct """        
@prefix dmn: <http://www.DMN-RDF.org/DMN#> .
@prefix ocqa: <https://w3id.org/ocqa#> .
@prefix inst: <http://example.org/inst/> .
@prefix dc-agents: <https://w3id.org/digitalconstruction/0.5/Agents#> .
@prefix dc-entities: <https://w3id.org/digitalconstruction/0.5/Entities#> .

CONSTRUCT {
    ?this ocqa:hasInspection ?Inspection_Number_Of_Risers.
    ?Inspection_Number_Of_Risers a dmn:Inspection_Number_Of_Risers.
    ?ISCode a dmn:ISCode.
    ?Agent a dc-agents:Agent.
    ?InspectionEquipment a ocqa:InspectionEquipment.
    ?one_time a dmn:one_time.
    ?Location a dc-entities:Location.
    ?InspectionProcedure a ocqa:InspectionProcedure.
}
...
""" ;

4. 测试随机数函数兼容性

虽然GraphDB支持RAND(),但rdflib的SPARQL引擎对部分函数的支持可能有差异。可以先把随机数替换为固定值测试,看是否能生成实例:

BIND(IRI("inst:Inspection_Number_Of_Risers_123") as ?Inspection_Number_Of_Risers)
BIND(IRI("inst:ISCode_456") as ?ISCode)
# 其他BIND同理

5. 查看debug日志定位问题

代码中开启了debug=True,运行时会输出详细日志,重点关注:

  • 规则是否被触发(日志中会显示Applying rule...相关内容)
  • SPARQL查询是否返回结果(日志中会显示查询的结果行数)
  • 是否有前缀解析错误或IRI绑定异常

内容的提问来源于stack exchange,提问作者Kuladeep

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 14:47:03