将许多语句加载到 Jena 数据集中的最有效方法是啥?

Posted

技术标签:

【中文标题】将许多语句加载到 Jena 数据集中的最有效方法是啥?【英文标题】:What's the most efficient way to load many statements into a Jena dataset?将许多语句加载到 Jena 数据集中的最有效方法是什么? 【发布时间】:2016-11-14 08:29:54 【问题描述】:

我正在使用Jena TDB 来维护各种软件项目的调用依赖结构。在对大型项目进行静态分析后,我可能需要将 100k 语句添加到 TDB 支持的数据集中的专用 Jena 模型中,在极端情况下可能甚至数百万。

问题

添加 300k 语句大约需要 11 分钟。想象一下添加 3M 需要多长时间。 我想知道是否有其他方法可以添加这么多语句,或者完全使用其他技术。

我尝试过的

添加了所有使用 model.add(List<Statement> stmts) 的语句 - 抛出 java.lang.OutOfMemoryError 并由于获得的写锁而占用数据集。 以块的形式添加了所有语句,例如1000,同时在两者之间提交和释放锁。工作,但如上所述,我认为是由于事务性预写日志记录的开销。 以非事务方式将语句添加到临时、新鲜和 TDB 支持的模型中,然后用新模型替换旧模型。 RAM 使用率急剧上升,并降低了整个系统的速度。

附带问题

您是否会为此用例推荐 Jena/RDF 的替代品? Jena 是否可以缩放 w.r.t.分布式文件系统/计算?

其他信息

我正在使用事务,这可能是由于大量 I/O 而导致的主要减速因素。但无法避免这种情况,因为它是“一次交易,总是交易”。

TDB 支持的数据集可以非事务性使用,但一旦在事务中使用,之后必须以事务性方式使用

感谢任何提示,非常感谢。


代码和测试

根据@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))

将堆空间增加到 4GB 可以规避此问题,但仍会占用数据集近两分钟。

Statement count: 3233481
Transaction took 108.682 seconds.

使用TDBLoader 很可能会以相同的方式运行(表示为here),但除此之外不支持我希望防止数据集损坏的事务。

【问题讨论】:

JDWP exit error 是一种平台系统错误 - 它与耶拿无关。有很多谷歌热。 【参考方案1】:

Jena TDB 插入成本高昂,因为它会创建大量索引(或多或少是图、主语、谓词、宾语的所有组合)。重点是快速数据访问,而不是快速数据插入。

为了获得可接受的插入时间,我最终使用了 SSD。

至于我可以指出的替代方案:

RDF4J(以前称为 SESAME)允许在数据库中选择所需的索引。 议会 (http://parliament.semwebcentral.org/) 基于 Berkeley DB 作为 NoSQL 数据库后端,插入速度似乎相当快。

【讨论】:

RDF4J 是一个很好的提示,非常感谢。您是否有机会知道多个应用程序实例是否可以同时访问同一个数据存储(例如使用 Cumulus RDF)? 我可以在https://code.google.com/archive/p/cumulusrdf/ 上看到:“CumulusRDF 包含一个 SesameSail 实现,请参阅 CodeExamples wiki 页面。”这是连接到 RDF4J 四存储所需的。 Cumulus RDF 看起来很有趣,我会进一步研究。 去过那里,做到了。它绝对比 Jena 好,因为它允许分布式存储后端(如 Apache Cassandra),但由于缺乏资金而有一段时间没有维护。我目前正在切换到带有 DynamoDB 后端的 Titan(也支持 Cassandra)。没有 RDF,只有 Graph DB;就我的目的而言,更多更有用且具有极大的可扩展性。不过感谢您的见解,我不妨将此标记为正确答案。【参考方案2】:

如果您使用事务,请使用一个事务来覆盖整个加载 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() ; 
 

Jena 3.1.1 中有一个新的 API。 http://jena.apache.org/documentation/txn/txn.html

【讨论】:

非常感谢您的建议;我在增加堆大小后再次尝试了您的方法(请参阅更新的问题),但是单个事务仍然需要很长时间(其他事务在此期间被阻止)。是的,这是List 不是Collection,我的错。【参考方案3】:

我在使用远程 Jena TDB 和 Fuseki 时遇到了同样的问题。我所做的是将(http post)整个数据作为文件发布到远程 Jena Data 端点,即

http://FusekiIP:3030/yourdataset/data

【讨论】:

以上是关于将许多语句加载到 Jena 数据集中的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

将数据从hdfs加载到本地系统的有效方法?

在每一帧上更新整个 VBO 是绘制许多变化的独特三角形的最有效方法吗?

从其他数据库更新表数据的最有效方法是啥?

Python - 如何将时间序列存储到数据集中

将短字符串转换为32位整数的最有效方法是什么?

在NodeJS中将许多文件中的JSON对象插入MongoDB的最有效方法