过滤 TTL 文件过大,rdflib 无法解析内存中的文件,否则

Filter a TTL file too large for rdflib to parse in-memory otherwise

提问人:Alexandra 提问时间:10/23/2023 最后编辑:Charles DuffyAlexandra 更新时间:10/24/2023 访问量:59

问:

我正在处理一个 20 GB 的大型 ttl 文件,我尝试使用 rdflib 读入,但我收到错误

killed

为了避免这种情况,我正在尝试使用 grep 命令从该文件创建一个较小的文件。


示例数据为 yagoTransitiveType.ttl;开头包含如下所示的行:


@base <http://yago-knowledge.org/resource/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

<1908_St._Louis_Browns_season>  rdf:type        <wikicat_St._Louis_Browns_seasons> .
<1908_St._Louis_Browns_season>  rdf:type        <wordnet_abstraction_100002137> .
<A1086_road>    rdf:type        <wikicat_Roads_in_the_United_Kingdom> .
<A1086_road>    rdf:type        <wordnet_artifact_100021939> .

我只想保留顶部标题中的行,或包含 .wordnet_


到目前为止,我尝试过的是:

grep "wordnet_" yagoTransitiveType.ttl >wordnet_yagoTransitiveType.ttl

问题是该文件没有像 yago: 和其他那样读取初始前缀,因此 rdflib 无法解析 ttl 文件。

import rdflib
g = rdflib.Graph()
g.parse('yagoTransitiveType.ttl', format='ttl')

如何通过在运行 grep 命令或任何其他方式后添加 10 行来解决问题?

linux grep sparql rdflib sparqlwrapper

评论

1赞 UninformedUser 10/23/2023
为什么不能手动将前缀声明行添加到文件中?
1赞 UninformedUser 10/23/2023
此外,内存中 20GB 的 Turtle 文件对您的计算机来说可能太多了。这需要大量的RAM。但是我不明白为什么您要使用这样的文件而不是三重存储?加载到 rdflib 后,您如何处理数据?

答:

1赞 Charles Duffy 10/23/2023 #1

据我了解,您希望保留以下两种类型的数据之一:

  • 不包含的数据rdf:type
  • 同时包含 和 的数据(按此顺序)rdf:typewordnet_

效率较低(因为它读取输入文件两次),这可能如下所示:

{
  grep -v rdf:type yagoTransitiveType.ttl
  grep -Ee 'rdf:type.*wordnet' yagoTransitiveType.ttl
} >filtered.ttl

...或者,以稳健性换取效率(读取文件两次,但在第一次通过时只读取前 10 行 -- 但取决于你是否提供要保留的行数的准确计数):

keep_count=10
{
  head -n "$keep_count" yagoTransitiveType.ttl
  grep -Ee 'rdf:type.*wordnet' yagoTransitiveType.ttl
} >filtered.ttl

请注意,在上述两个工具中,我们提供了两次输入文件名,因此第二个工具从文件的开头重新开始,而不是共享输入文件句柄并指望第一个工具在文件中的正确位置读取光标。我们稍后会看到替代方案。


作为更有效的替代方法(仅读取输入文件一次并使用同一工具执行这两个操作):

awk '
  ! /rdf:type/ { print; next }
  /rdf:type/ && /wordnet_/ { print }
' <yagoTransitiveType.ttl >filtered.ttl

awk是一种功能齐全的编程语言;因此,它可以执行任意操作,而 grep 只对单个行进行正则表达式匹配。


如果您真的只想复制前 10 行未过滤,然后使用 grep 过滤其余行,则如下所示:

keep_count=10
{
  for ((i=0; i<keep_count; i++)); do
    IFS= read -r line && printf '%s\n' "$line"
  done
  grep -e wordnet_
} <yagoTransitiveType.ttl >filtered.ttl

所有这些都将生成一个 .filtered.ttl

评论

0赞 Ed Morton 10/24/2023
您不需要开始 awk 脚本的第二行,因为只有当从上面的行是 false 时,才能到达该行。当然,你可以把它改写成。/rdf:type/ &&!/rdf:type/awk '/wordnet_/ || !/rdf:type/'
0赞 Ed Morton 10/24/2023 #2

这是你想做的吗?

$ grep -E '^@|wordnet_' yagoTransitiveType.ttl
@base <http://yago-knowledge.org/resource/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
<1908_St._Louis_Browns_season>  rdf:type        <wordnet_abstraction_100002137> .
<A1086_road>    rdf:type        <wordnet_artifact_100021939> .