
RDFLib 默认将 JSON-LD 中的数组属性解析为无序、去重的 RDF 多值谓词,导致重复数值被合并;要完整保留原始顺序与重复项,需显式声明 "@container": "@list",使 rdflib 构建 rdf:List 而非多个独立三元组。
rdflib 默认将 json-ld 中的数组属性解析为无序、去重的 rdf 多值谓词,导致重复数值被合并;要完整保留原始顺序与重复项,需显式声明 `"@container": "@list"`,使 rdflib 构建 `rdf:list` 而非多个独立三元组。
在 RDF 数据模型中,三元组本身不具备顺序性,也不允许“重复断言”具有语义差异——即 (s, p, o1) 出现一次或十次,在逻辑上完全等价。因此,当 rdflib 解析形如 "my_field": [a, b, a, b] 的 JSON-LD 时,它会为每个数组元素生成一个独立三元组:
<some-id> <http://example.com/test/my_field> "a"^^xsd:double . <some-id> <http://example.com/test/my_field> "b"^^xsd:double . <some-id> <http://example.com/test/my_field> "a"^^xsd:double . <some-id> <http://example.com/test/my_field> "b"^^xsd:double .
但 RDF 规范要求图结构去重(canonicalization),最终存储/序列化时仅保留唯一三元组,故重复值被静默合并——这并非 rdflib 的 bug,而是对 RDF 语义的严格遵循。
✅ 正确解决方案:使用 @container: "@list" 声明有序列表
JSON-LD 提供 @list 容器机制,可将数组映射为 RDF 标准的 rdf:List(即由 rdf:first/rdf:rest/rdf:nil 构成的链表结构),从而同时保留顺序、重复性和结构完整性。
修改你的上下文(@context)如下:
import json
from rdflib import Graph
jsonld_data = {
"@id": "some-id",
"@type": "Row",
"attendance": 74439,
"my_field": [-0.0368623323738575, 0.06313438713550568,
-0.05376605689525604, -0.0368623323738575,
0.06313438713550568, -0.05376605689525604]
}
context = {
"@vocab": "http://example.com/test/",
"@language": "en",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"my_field": {
"@id": "http://example.com/test/my_field",
"@container": "@list" # ← 关键:启用 rdf:List 语义
}
}
g = Graph()
g.parse(
data=json.dumps({"@context": context, **jsonld_data}),
format="json-ld"
)
# 序列化为 Turtle 可清晰看到 rdf:List 结构
print(g.serialize(format="turtle").decode())输出将包含类似以下结构(节选):
<some-id> test:my_field _:b0 .
_:b0 rdf:first -0.0368623323738575 ;
rdf:rest _:b1 .
_:b1 rdf:first 0.06313438713550568 ;
rdf:rest _:b2 .
_:b2 rdf:first -0.05376605689525604 ;
rdf:rest _:b3 .
_:b3 rdf:first -0.0368623323738575 ;
rdf:rest _:b4 .
_:b4 rdf:first 0.06313438713550568 ;
rdf:rest _:b5 .
_:b5 rdf:first -0.05376605689525604 ;
rdf:rest rdf:nil .⚠️ 注意事项:
-
@container: "@list"必须在@context中为对应字段显式声明,不能依赖全局@vocab; - 使用
rdf:List后,SPARQL 查询需用rdf:rest*/rdf:first路径或LIST扩展函数(如 Apache Jena)提取元素,标准?s test:my_field ?o将只匹配列表节点(blank node),而非具体数值; - 若需兼顾 RDF 兼容性与业务可读性,也可采用“索引属性”模式(如
"my_field_0": a, "my_field_1": b...),但牺牲了语义规范性; -
@list是 JSON-LD 1.1 标准特性,确保你使用的rdflib-jsonld>=0.6.0(推荐rdflib==6.3.2+rdflib-jsonld==0.6.1组合)。
总结:RDF 的本质是陈述事实,而非记录序列;当业务强依赖数组顺序与重复时,必须升维到 rdf:List 这一更高阶结构。这是语义网工程中“用正确模型表达正确意图”的典型实践——不是绕过标准,而是深入运用标准。


















