【问题标题】:Performance optimizations of information retrieval in PrologProlog中信息检索的性能优化
【发布时间】:2013-04-12 20:12:42
【问题描述】:

我想用 Prolog 做一些信息检索任务。目前,我有一组(大量)不同的 Prolog 理论,它们表示句子中的依赖关系(顺便说一下,我将这些 Prolog 代码存储在一个文本文件中)——我只想找到那些与用户定义的目标子句匹配的理论。

例如,我有这样的 Prolog 代码:

rel("nsubjpass","seen","It",S):-S is 1.
rel("aux","seen","can",S):-S is 1.
rel("auxpass","seen","be",S):-S is 1.
...
rel("prep", X, Y, S):-rel("dobj", Z, X, SCORE1), rel("prep", Z, Y, SCORE2), S is SCORE1*SCORE2.
...
rel(_,_,_, S):-S is 0.0001.

我想搜索这样的目标子句:

?- rel("nsubj", WRONG, "Russell", SCORE1), 
   rel("nsubj", WRONG, "Russell", SCORE2), 
   ... , 
   rel("dobj",DOING,SOMETHING, SCORE9).

如果我对理论做一个简单的foreach-like 循环,搜索时间会随着理论数量的增加而变慢,所以我必须引入一些优化。

我的想法是创建一个倒排索引,我可以在其中维护每个术语的频率,以及它们发生的理论的 ID。然后在搜索时,我会首先过滤掉那些不会包含在结果中的不必要的理论。

在信息检索领域有没有其他行之有效的方法或好的模式和算法可以很好地处理这个问题?

【问题讨论】:

  • 你是否故意使用双引号字符串?
  • 此数据来自解析器。元组的第一个组件是依赖项的标识符(我可以在那里使用原子,这会提高性能,很好) - 但是其他组件可以包含撇号和其他“字符串”的东西,所以这些不会是有效的原子。
  • writeq(或格式中的说明符 ~q)负责处理有关原子表示的细节。
  • 由于第一个参数索引,使用原子的性能真的可以好多更好(我猜 - 帮助页面并不简单)
  • 嗯,谢谢你的提示! :) 我会试试看。也许重新排序参数会有所帮助?哦,我想提一下我使用的是从 Java 代码运行的 TuProlog。我不知道它是否是一个超级全功能的 Prolog 引擎,但我会在文档中检查它。

标签: algorithm data-structures prolog information-retrieval inverted-index


【解决方案1】:

我写这篇文章是为了回答而不是评论,只是因为 cmets 非常有限。

首先,如果你确实打算使用 Prolog,那么做一些研究是值得的

  1. 语言本身:
    • 它的优点和缺点是什么?
    • 我可以在惯用的 Prolog 中实现我的目标吗(已经解决了类似的问题)
  2. 不同的实现:
    • 一个特定的实现比其他实现提供了什么
    • 实现与其他语言的接口是多么容易

在刚开始短暂的挣扎之后,我一直在独家使用SWI-Prolog,所以我有偏见。但是 SWI 提供了一个非常完整、通用、相当高效的实现、优秀的文档,并且是完全开源的。

继续前进,您似乎正在使用 Prolog 事实来表示您的数据。 Prolog 事实的形式:

foo(a,b,1).
foo(a,d,10).
...

构建Prolog 数据库。大多数实现都提供了某种事实索引,因此像“给我 'foo's 和 'a' 作为第一个参数”这样的查询:

?- foo(a,B,X).
B = b, X = 3;
B = d, X = 10.

对所有可用的事实进行非常有效的搜索,并返回与您的查询匹配的事实。您绝对不需要使用 for 循环搜索事实,或编写事实搜索算法。但请注意,事实索引可能因实现而异。

此外,根据您的用例,将字符串表示为 Prolog 原子可能是最佳解决方案,高效且易于实现。看看here,尤其是在结尾处,一些非常有用的关于原子的“字符串操作”谓词。

继续前进,在 Prolog 中编写自上而下、从左到右的解析器是该语言的一个特性,使用 DCG(定句语法)。

最后,如果您熟悉 Java 并且只需要添加一个高效的(动态)数据存储,Java + SQL 可能是更好的选择。

【讨论】:

    【解决方案2】:

    我认为 Boris 的回答从 Prolog 开发人员的角度来看是合理的,但我不想花太多时间研究如何从 Prolog 调用 Java 函数,反之亦然,更不用说创建一个来自 Prolog 脚本的独立可执行文件,这是我的要求。

    所以我有点固执,我尝试实现我最初的想法,即从 Prolog 术语创建倒排索引,并且它完美无缺。所以现在当我想搜索某个 Prolog 目标时,第一步我可以过滤相关理论的“数据库”:我计算术语出现的交集,然后只使用这些理论运行 Prolog 引擎. 另一个大的性能优化是在各个搜索之间共享一个单例 TuProlog 引擎,它还减少了内存开销。 哦,我也重构了规则,例如现在我写这个:

    rel(nsubjpass, "seen","It", 1).
    

    而不是这个:

    rel("nsubjpass","seen","It",S):-S is 1.
    

    我没有注意到这个变化对性能有任何显着提升,但至少它没有变慢 :)

    通过这些更改,现在可以看出性能的真正瓶颈不是运行 Prolog 引擎,而是使用 NLP 库……但这是另一个问题。 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-16
      相关资源
      最近更新 更多