使用Python向Apache Jena Fuseki上传大RDF文件遇表单过大错误
我按官方文档搭建了独立运行的Apache Jena Fuseki服务器,localhost:3030访问正常。Python代码能上传小体积.ttl格式RDF文件,但大文件上传失败,服务器日志报错:
Caused by: java.lang.IllegalStateException: form too large > 20000000
at org.eclipse.jetty.server.FormFields.checkMaxLength(FormFields.java:318) ~[fuseki-server.jar:5.0.0]
at org.eclipse.jetty.server.FormFields.parse(FormFields.java:307) ~[fuseki-server.jar:5.0.0]
at org.eclipse.jetty.server.FormFields.parse(FormFields.java:39) ~[fuseki-server.jar:5.0.0]
at org.eclipse.jetty.io.content.ContentSourceCompletableFuture.parse(ContentSourceCompletableFuture.java:104) ~[fuseki-server.jar:5.0.0]
at org.eclipse.jetty.server.handler.ContextHandler$ScopedContext.run(ContextHandler.java:1212) ~[fuseki-server.jar:5.0.0]
at org.eclipse.jetty.server.handler.ContextRequest$OnContextDemand.run(ContextRequest.java:74) ~[fuseki-server.jar:5.0.0]
at org.eclipse.jetty.util.thread.SerializedInvoker$Link.run(SerializedInvoker.java:191) ~[fuseki-server.jar:5.0.0]
at org.eclipse.jetty.server.internal.HttpConnection$DemandContentCallback.succeeded(HttpConnection.java:679) ~[fuseki-server.jar:5.0.0]
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:99) ~[fuseki-server.jar:5.0.0]
at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53) ~[fuseki-server.jar:5.0.0]
最初采用SPARQL INSERT DATA方式上传,代码如下:
input_location = "C:/......../Added_Triples.ttl" with open(input_location, 'r') as f: content = f.read() rdf_string_no_prefixes = "\n".join(line for line in content.split("\n") if not line.startswith("@prefix")) update_query = """ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> PREFIX CSRO: <http://www.semanticweb.org/aagr657/ontologies/2023/9/CraneSpaceRepresentationOntology#> PREFIX LinkOnt: <http://purl.org/ConstructLinkOnt/LinkOnt#> PREFIX bot: <https://w3id.org/bot#> PREFIX expr: <https://w3id.org/express#> PREFIX geo: <http://www.opengis.net/ont/geosparql#> PREFIX geom: <http://rdf.bg/geometry.ttl#> PREFIX ifc: <https://standards.buildingsmart.org/IFC/DEV/IFC2X3/TC1/OWL> PREFIX inst: <https://www.ugent.be/myAwesomeFirstBIMProject#> PREFIX owl: <http://www.w3.org/2002/07/owl#> PREFIX sf: <http://www.opengis.net/ont/sf#> PREFIX omg: <https://w3id.org/omg#> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> PREFIX lbd: <https://linkedbuildingdata.org/LBD#> PREFIX props: <http://lbd.arch.rwth-aachen.de/props#> PREFIX unit: <http://qudt.org/vocab/unit/> PREFIX IFC4-PSD: <https://www.linkedbuildingdata.net/IFC4-PSD#> PREFIX smls: <https://w3id.org/def/smls-owl#> PREFIX fog: <https://w3id.org/fog#> PREFIX cc: <http://creativecommons.org/ns#> PREFIX dce: <http://purl.org/dc/elements/1.1/> PREFIX express: <https://w3id.org/express#> PREFIX list: <https://w3id.org/list#> PREFIX vann: <http://purl.org/vocab/vann/> PREFIX expr: <https://w3id.org/express#> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX : <https://standards.buildingsmart.org/IFC/DEV/IFC2x3/TC1/OWL#> INSERT DATA { %s } """ % (rdf_string_no_prefixes) sparql = SPARQLWrapper("http://localhost:3030/your-dataset/update") sparql.setMethod(POST) sparql.setQuery(update_query) sparql.query()
尝试修改jetty.xml解决但未找到该文件,临时分块上传耗时过长,不想采用。之后换requests.post方式上传,代码如下:
import requests file_location = "C:/.........../Added_Triples.ttl" sparql_endpoint = "http://localhost:3030/construction_dataset_2/update" headers = {'Content-Type': 'text/turtle;charset=utf-8'} data = open(file_location, 'r').read() response = requests.post(sparql_endpoint, headers=headers, data=data)
出现错误:
Exception has occurred: ConnectionError
('Connection aborted.', ConnectionAbortedError(10053, 'An established connection was aborted by the software in your host machine', None, 10053, None))
ConnectionAbortedError: [WinError 10053] An established connection was aborted by the software in your host machine
服务器日志显示:
11:40:03 INFO Fuseki :: [23] 415 Unsupported Media Type (0 ms)
11:40:03 INFO Fuseki :: [24] POST http://localhost:3030/construction_dataset_2/update
11:40:03 INFO Fuseki :: [24] 415 Unsupported Media Type (0 ms)
11:42:17 INFO Fuseki :: [25] POST http://localhost:3030/construction_dataset_2/update
需要无需分块、可一次性上传大RDF文件的解决方案。
1. 调整Jetty表单大小限制(适配SPARQL Update方式)
Fuseki 5.x使用内嵌Jetty服务器,默认表单大小限制为20MB,可通过启动参数直接调整,无需寻找jetty.xml:
- Windows环境:修改
fuseki.bat中的启动命令,添加Jetty参数:java -Dorg.eclipse.jetty.server.FormFields.maxSize=100000000 -jar fuseki-server.jar --update /your-dataset - Linux/macOS环境:修改
fuseki.sh中的启动命令,添加Jetty参数:
其中java -Dorg.eclipse.jetty.server.FormFields.maxSize=100000000 -jar fuseki-server.jar --update /your-dataset100000000代表100MB,可根据实际文件大小调整为对应数值(如500MB写500000000)。
2. 使用Fuseki原生文件上传端点(推荐大文件)
Fuseki提供专门的文件上传接口,比SPARQL INSERT DATA更高效,且原生支持大文件:
Python代码示例
import requests file_path = "C:/......../Added_Triples.ttl" # 上传到默认图,若需指定命名图,在URL后追加?graph=<你的命名图URI> upload_endpoint = "http://localhost:3030/construction_dataset_2/data" with open(file_path, 'rb') as f: # 采用multipart/form-data格式上传文件 files = {'file': ('Added_Triples.ttl', f, 'text/turtle')} # 若需要覆盖目标图现有数据,添加参数?overwrite=true response = requests.post(upload_endpoint, files=files) print(response.status_code) print(response.text)
3. 修复直接POST Turtle数据的错误
之前的415错误是因为/update端点仅接受SPARQL Update请求,而非直接的Turtle数据。若要直接提交Turtle内容,需使用数据集的/data端点:
正确代码示例
import requests file_path = "C:/......../Added_Triples.ttl" data_endpoint = "http://localhost:3030/construction_dataset_2/data" headers = {'Content-Type': 'text/turtle; charset=utf-8'} # PUT会替换目标图所有数据,POST会追加数据;指定命名图加?graph=<URI> with open(file_path, 'r', encoding='utf-8') as f: response = requests.post(data_endpoint, headers=headers, data=f) print(response.status_code) print(response.text)
注意:若文件过大,仍需先按方案1调整Jetty的请求大小限制,可同时添加两个参数确保覆盖:
java -Dorg.eclipse.jetty.server.FormFields.maxSize=100000000 -Dorg.eclipse.jetty.server.Request.maxFormContentSize=100000000 -jar fuseki-server.jar --update /your-dataset
内容的提问来源于stack exchange,提问作者AJAY AGRAWAL

