将许多语句加载到 Jena 数据集中的最有效方法是什么?
What's the most efficient way to load many statements into a Jena dataset?
我正在使用 Jena TDB 来维护各种软件项目的调用依赖结构。在对大型项目进行静态分析后,可能需要向 TDB 支持的数据集中的专用 Jena 模型添加 100k 条语句,在极端情况下甚至可能达到数百万条。
问题
添加 300k 语句大约需要 11 分钟。想象一下添加 3M 需要多长时间。 我想知道是否有另一种方法可以添加这么多语句,或者完全是另一种技术。
我试过的
- 添加了所有使用
model.add(List<Statement> stmts)
的语句 - 抛出一个 java.lang.OutOfMemoryError
并由于获得写锁而占用数据集。
- 以块的形式添加了所有语句,例如1000,同时提交和释放之间的锁。可以工作,但如上所述需要很长时间,我推测是由于事务性预写日志记录的开销。
- 以非事务方式将语句添加到临时的、全新的和 TDB 支持的模型中,然后用新模型替换旧模型。 RAM 使用率急剧上升并降低了整个系统的速度。
附带问题
- 对于此用例,您会推荐 Jena/RDF 的替代方案吗?
- 耶拿是否可以扩展 w.r.t。分发文件 systems/computing?
其他信息
我正在使用事务,这可能是由于繁重 I/O 导致的主要减速因素。但这无法避免,因为它是“一次交易,永远交易”。
A TDB-backed dataset can be used non-transactionally but once used in a transaction, it must be used transactionally after that.
感谢任何提示,非常感谢。
代码和测试
根据@AndyS 的建议,我尝试在单个事务中添加所有语句,如下所示:
List<Statement> statements = ...;
//Print statistics
System.out.println("Statement count: " + statements.size());
//Log the start of the operation to measure its duration
Long start = System.currentTimeMillis();
//Add all statements in one transaction
workspace.beginTransaction(ReadWrite.WRITE); //forwards to dataset.begin(ReadWrite rw)
try {
model.add(statements);
} catch (Exception e) {
e.printStackTrace();
workspace.abortTransaction(); //forwards to dataset.abort()
} finally {
workspace.commitTransaction(); //forwards to dataset.commit()
}
//Check how long the operation took
double durationS = (System.currentTimeMillis() - start) / 1000.0;
System.out.println("Transaction took " + durationS + " seconds.");
这是输出:
Statement count: 3233481
运行此事务的线程崩溃并在调试器中显示以下消息:
Daemon Thread [ForkJoinPool-1-worker-1] (Suspended (exception OutOfMemoryError))
将堆 space 增加到 4GB 可以避免这个问题,但仍然占用数据集将近两分钟。
Statement count: 3233481
Transaction took 108.682 seconds.
使用 TDBLoader
很可能会以相同的方式表现(表示 here),但除此之外不支持交易,我想必须防止数据集损坏。
如果您正在使用事务,请使用一个事务来覆盖整个加载 300k 语句。 300k 通常不是很大(3M 也不是),除非它有很多很多非常大的文字。
单个 Model.add(Coillection)
应该可以。
或者从文件加载:
dataset.begin(ReadWrite.WRITE) ;
try {
RDFDataMgr.read(dataset, FILENAME);
dataset.commit() ;
} finally {
dataset.end() ;
}
还有一个用于离线加载的bulkloader。它是一个单独的程序 tdbloader
。
没有 Model.add(Collection)
- 有 Model.add(List)
。将其放入事务循环中。
dataset.begin(ReadWrite.WRITE) ;
try {
dataset.getDefaultModel().add(...)
dataset.commit() ;
} finally {
dataset.end() ;
}
耶拿 3.1.1 中有一个新的 API。
http://jena.apache.org/documentation/txn/txn.html
Jena TDB 插入的成本很高,因为它会创建大量索引(或多或少是图、主语、谓语、宾语的所有组合)。重点是快速数据访问,而不是快速数据插入。
为了获得可接受的插入时间,我最终使用了 SSD。
至于替代方案,我可以指出:
- RDF4J(以前称为 SESAME)允许 select 数据库中所需的索引。
- Parliament (http://parliament.semwebcentral.org/),基于 Berkeley DB 作为 NoSQL 数据库后端,插入速度似乎相当快。
我在使用远程 Jena TDB 和 Fuseki 时遇到了同样的问题。我所做的是 posting(http post) 整个数据作为文件发送到远程 Jena Data 端点,即
我正在使用 Jena TDB 来维护各种软件项目的调用依赖结构。在对大型项目进行静态分析后,可能需要向 TDB 支持的数据集中的专用 Jena 模型添加 100k 条语句,在极端情况下甚至可能达到数百万条。
问题
添加 300k 语句大约需要 11 分钟。想象一下添加 3M 需要多长时间。 我想知道是否有另一种方法可以添加这么多语句,或者完全是另一种技术。
我试过的
- 添加了所有使用
model.add(List<Statement> stmts)
的语句 - 抛出一个java.lang.OutOfMemoryError
并由于获得写锁而占用数据集。 - 以块的形式添加了所有语句,例如1000,同时提交和释放之间的锁。可以工作,但如上所述需要很长时间,我推测是由于事务性预写日志记录的开销。
- 以非事务方式将语句添加到临时的、全新的和 TDB 支持的模型中,然后用新模型替换旧模型。 RAM 使用率急剧上升并降低了整个系统的速度。
附带问题
- 对于此用例,您会推荐 Jena/RDF 的替代方案吗?
- 耶拿是否可以扩展 w.r.t。分发文件 systems/computing?
其他信息
我正在使用事务,这可能是由于繁重 I/O 导致的主要减速因素。但这无法避免,因为它是“一次交易,永远交易”。
A TDB-backed dataset can be used non-transactionally but once used in a transaction, it must be used transactionally after that.
感谢任何提示,非常感谢。
代码和测试
根据@AndyS 的建议,我尝试在单个事务中添加所有语句,如下所示:
List<Statement> statements = ...;
//Print statistics
System.out.println("Statement count: " + statements.size());
//Log the start of the operation to measure its duration
Long start = System.currentTimeMillis();
//Add all statements in one transaction
workspace.beginTransaction(ReadWrite.WRITE); //forwards to dataset.begin(ReadWrite rw)
try {
model.add(statements);
} catch (Exception e) {
e.printStackTrace();
workspace.abortTransaction(); //forwards to dataset.abort()
} finally {
workspace.commitTransaction(); //forwards to dataset.commit()
}
//Check how long the operation took
double durationS = (System.currentTimeMillis() - start) / 1000.0;
System.out.println("Transaction took " + durationS + " seconds.");
这是输出:
Statement count: 3233481
运行此事务的线程崩溃并在调试器中显示以下消息:
Daemon Thread [ForkJoinPool-1-worker-1] (Suspended (exception OutOfMemoryError))
将堆 space 增加到 4GB 可以避免这个问题,但仍然占用数据集将近两分钟。
Statement count: 3233481
Transaction took 108.682 seconds.
使用 TDBLoader
很可能会以相同的方式表现(表示 here),但除此之外不支持交易,我想必须防止数据集损坏。
如果您正在使用事务,请使用一个事务来覆盖整个加载 300k 语句。 300k 通常不是很大(3M 也不是),除非它有很多很多非常大的文字。
单个 Model.add(Coillection)
应该可以。
或者从文件加载:
dataset.begin(ReadWrite.WRITE) ;
try {
RDFDataMgr.read(dataset, FILENAME);
dataset.commit() ;
} finally {
dataset.end() ;
}
还有一个用于离线加载的bulkloader。它是一个单独的程序 tdbloader
。
没有 Model.add(Collection)
- 有 Model.add(List)
。将其放入事务循环中。
dataset.begin(ReadWrite.WRITE) ;
try {
dataset.getDefaultModel().add(...)
dataset.commit() ;
} finally {
dataset.end() ;
}
耶拿 3.1.1 中有一个新的 API。 http://jena.apache.org/documentation/txn/txn.html
Jena TDB 插入的成本很高,因为它会创建大量索引(或多或少是图、主语、谓语、宾语的所有组合)。重点是快速数据访问,而不是快速数据插入。
为了获得可接受的插入时间,我最终使用了 SSD。
至于替代方案,我可以指出:
- RDF4J(以前称为 SESAME)允许 select 数据库中所需的索引。
- Parliament (http://parliament.semwebcentral.org/),基于 Berkeley DB 作为 NoSQL 数据库后端,插入速度似乎相当快。
我在使用远程 Jena TDB 和 Fuseki 时遇到了同样的问题。我所做的是 posting(http post) 整个数据作为文件发送到远程 Jena Data 端点,即