MarkLogic执行SPARQL查询返回错误结果的技术问询
MarkLogic SPARQL查询反向路径+exists子句返回错误结果问题
问题背景
在MarkLogic查询控制台执行SPARQL查询时,涉及反向路径(^)与exists子句结合的场景下,出现不符合预期的错误结果,且结果存在高度不一致性。官方已确认这是MarkLogic的产品bug,影响版本包括MarkLogic 10及11.0.2。
初始测试场景
测试数据
场景:存在Folder对象包含File子对象,所有对象带有标签,每个Folder/File通过WritePermission关联拥有修改权限的Group。
prefix ex: <http://example.com/ns#> prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> insert data { ex:ID0 rdfs:label "Root" . ex:ID0 rdf:type ex:Folder . ex:ID0 ex:WritePermission ex:GROUP1 . ex:ID1 rdfs:label "File1" . ex:ID1 rdf:type ex:File . ex:ID1 ex:Parent ex:ID0 . ex:ID1 ex:WritePermission ex:GROUP2 . ex:ID2 rdfs:label "File2" . ex:ID2 rdf:type ex:File . ex:ID2 ex:Parent ex:ID0 . ex:ID2 ex:WritePermission ex:GROUP2 . ex:ID3 rdfs:label "File3" . ex:ID3 rdf:type ex:File . ex:ID3 ex:Parent ex:ID0 . ex:ID3 ex:WritePermission ex:GROUP2 . ex:GROUP1 rdf:type ex:Group . ex:GROUP1 rdfs:label "Admin" . ex:GROUP1 ex:Member ex:USER1 . ex:GROUP2 rdf:type ex:Group . ex:GROUP2 rdfs:label "Users" . ex:GROUP2 ex:Member ex:USER2 . ex:USER1 rdf:type ex:User . ex:USER1 rdfs:label "User1" . ex:USER2 rdf:type ex:User . ex:USER2 rdfs:label "User2" . }
查询语句
该查询用于判断指定名称是否存在于父对象"Root"下,同时检查用户所属Group是否拥有父对象的写入权限:
prefix ex: <http://example.com/ns#> prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> select ?nameConflict ?hasWritePermissionToParent where { bind(ex:ID0 as ?parent) bind("ZZZ" as ?nameToCheck) bind(ex:USER2 as ?userId) bind(exists { ?parent ^ex:Parent/rdfs:label ?nameToCheck } as ?nameConflict) bind(exists { ?userId ^ex:Member+/^ex:WritePermission ?parent } as ?hasWritePermissionToParent) }
结果对比
- 预期结果:
?nameConflict和?hasWritePermissionToParent均返回false - 实际结果:两者均返回
true
扩展测试场景(更新内容)
新增ReadPermission三元组后,尝试select *的临时方案无效,结果仍存在高度不一致性。
测试数据
prefix ex: <http://example.com/ns#> prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> insert data { ex:ID0 rdfs:label "Root" . ex:ID0 rdf:type ex:Folder . ex:ID0 ex:ReadPermission ex:GROUP1 . ex:ID0 ex:WritePermission ex:GROUP1 . ex:ID1 rdfs:label "File1" . ex:ID1 rdf:type ex:File . ex:ID1 ex:Parent ex:ID0 . ex:ID1 ex:ReadPermission ex:GROUP2 . ex:ID1 ex:WritePermission ex:GROUP2 . ex:ID2 rdfs:label "File2" . ex:ID2 rdf:type ex:File . ex:ID2 ex:Parent ex:ID0 . ex:ID2 ex:ReadPermission ex:GROUP2 . ex:ID2 ex:WritePermission ex:GROUP2 . ex:ID3 rdfs:label "File3" . ex:ID3 rdf:type ex:File . ex:ID3 ex:Parent ex:ID0 . ex:ID3 ex:ReadPermission ex:GROUP2 . ex:ID3 ex:WritePermission ex:GROUP2 . ex:GROUP1 rdf:type ex:Group . ex:GROUP1 rdfs:label "Admin" . ex:GROUP1 ex:Member ex:USER1 . ex:GROUP2 rdf:type ex:Group . ex:GROUP2 rdfs:label "Users" . ex:GROUP2 ex:Member ex:USER2 . ex:USER1 rdf:type ex:User . ex:USER1 rdfs:label "User1" . ex:USER2 rdf:type ex:User . ex:USER2 rdfs:label "User2" . }
查询语句
prefix ex: <http://example.com/ns#> prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> select * where { bind(ex:ID0 as ?id) ex:USER1 ^ex:Member+ ?groups . bind(exists{?id ex:ReadPermission ?groups} as ?hasReadPermission) bind(exists{?id ex:Source/ex:ReadPermission ?groups ; ex:Destination/ex:ReadPermission ?groups .} as ?linkHasReadPermission) }
预期结果
| ?id | 用户 | 预期?hasReadPermission值 |
|---|---|---|
| ID0 | ex:USER1 | true |
| ID0 | ex:USER2 | false |
| ID1/ID2/ID3 | ex:USER1 | false |
| ID1/ID2/ID3 | ex:USER2 | true |
实际情况
部分组合初始看似符合预期,但遍历所有组合时总会出现错误结果,输出高度不一致。
临时解决方案建议
在官方修复bug前,可通过拆分路径表达式、避免复合反向路径直接嵌套在exists子句中的方式规避问题:
以初始查询为例,修改后的查询如下:
prefix ex: <http://example.com/ns#> prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> select ?nameConflict ?hasWritePermissionToParent where { bind(ex:ID0 as ?parent) bind("ZZZ" as ?nameToCheck) bind(ex:USER2 as ?userId) # 拆分名称冲突检查逻辑 bind(exists { ?file ex:Parent ?parent ; rdfs:label ?nameToCheck . } as ?nameConflict) # 先提取用户所属Group,再单独检查权限关联 optional { ?userId ^ex:Member ?group . ?parent ex:WritePermission ?group . } bind(bound(?group) as ?hasWritePermissionToParent) }
这种拆分方式可避开MarkLogic对复合反向路径的解析bug,得到符合预期的结果。
内容的提问来源于stack exchange,提问作者Vishal
相关产品推荐
相关产品推荐

