在XQuery中为多个值计算出现次数的最有效方法

时间:2016-06-27 14:35:49

标签: xml perl xpath xquery basex

我需要在荷兰语的XML语料库(5亿字)中查找1581个单词。该语料库本身在许多数据库中被分开。 (您可以阅读here的原因。)我们使用BaseX作为服务器(版本7.9),它使用XQuery作为输入。

我有兴趣通过中性判定器( het )或非中性判断器( de )找出每个单词在语料库中的次数 - 这是通过寻找一个由两个女儿的NP(名词短语)组成的XPath结构来完成,即一个带有引理 de het 的限定词,以及一个头部,是我感兴趣的词。

de

的示例结构
/node[@cat="np" and node[@rel="det" and @pt="lid" and @lemma="de"] and node[@rel="hd" and @pt="n" and @word="accelerator"]]
/node[@cat="np" and node[@rel="det" and @pt="lid" and @lemma="de"] and node[@rel="hd" and @pt="n" and @word="accountant"]]
/node[@cat="np" and node[@rel="det" and @pt="lid" and @lemma="de"] and node[@rel="hd" and @pt="n" and @word="ace"]]
/node[@cat="np" and node[@rel="det" and @pt="lid" and @lemma="de"] and node[@rel="hd" and @pt="n" and @word="acroniem"]]

het的示例结构

/node[@cat="np" and node[@rel="det" and @pt="lid" and @lemma="het"] and node[@rel="hd" and @pt="n" and @word="accelerator"]]
/node[@cat="np" and node[@rel="det" and @pt="lid" and @lemma="het"] and node[@rel="hd" and @pt="n" and @word="accountant"]]
/node[@cat="np" and node[@rel="det" and @pt="lid" and @lemma="het"] and node[@rel="hd" and @pt="n" and @word="ace"]]
/node[@cat="np" and node[@rel="det" and @pt="lid" and @lemma="het"] and node[@rel="hd" and @pt="n" and @word="acroniem"]]

在XQuery中,我会这样做,对于每个XPath结构:

count(for $node in db:open("mydatabase")/treebank/tree/node[@cat="np" and node[@rel="det" and @pt="lid" and @lemma="het"] and node[@rel="hd" and @pt="n" and @word="accelerator"]] return $node)

这很好用。问题是,这需要很长时间。每次都需要按顺序打开相同(数千个)数据库,并对每个单词重复此过程。我的问题是,是不是有办法连接一些查询。我有一些想法,但我不确定如何执行它们 - 另外,我不确定BaseX可以处理多少个参数。

  1. 合并 de het 查询。
  2. 这可能是最直接的案例。通过这样做,我至少减少了一半的查询需求。但我不知道在找到结果时如何区分这两者。例如,如果我将我的XPath代码更改为:

    ... (@lemma="de" or @lemma="het") ...
    

    我应该找到所有情况,但我怎么能区分其中一个呢?换句话说,如果我使用那个XPath,我将从XQuery中的count函数返回一个数字但是我无法知道哪些是 de 哪个

    1. 同样的想法可以应用于结尾附近的单词属性
    2. 我可以将它们连接起来,而不是为每个单词执行新的查询:

      ... (@word="accelerator" or @word="accountant" or @word="ace" or ...) ...
      

      但是,我怎样才能区分这些价值观呢?我可以将所有1581值放在一个XPath中吗? BaseX可以处理吗?

      1. 带有一个单词列表的for循环,然后以XML格式返回结果以获取大量单词(如果BaseX可以处理,则可能全部返回)。
      2. 我不是XQuery的专家,但在伪代码中,我猜这样的事情是可能的:

        $wordlist = ['accelerator', 'accountant', 'ace', 'acroniem'];
        $determinerlist = ['de', 'het'];
        $db = 'mydatabase';
        foreach ($wordlist as $word) {
          foreach ($determinerlist as $det) {
            count(for $node in db:open("'.$db.'")/treebank/tree/node[@cat="np" and node[@rel="det" and @pt="lid" and @lemma="'.$det.'"] and node[@rel="hd" and @pt="n" and @word="'.$word.'"]] return $node);
          }
        }
        

        我不确定如何将计数分配给XQuery中的数组变量,如果可能的话,但XML输出看起来像这样(但当然欢迎更好的变体):

        <results>
          <result word="accelerator">
            <neuter>12</neuter>
            <nonneuter>3</nonneuter>
          </result>
          <result word="accountant">
            <neuter>4</neuter>
            <nonneuter>0</nonneuter>
          </result>
          <result word="ace">
            <neuter>14</neuter>
            <nonneuter>2</nonneuter>
          </result>
          <result word="acroniem">
            <neuter>3</neuter>
            <nonneuter>7</nonneuter>
          </result>
        </results>
        

        然后我可以使用Perl运行正则表达式或XML twig来获取我需要的值。

        正如你所看到的那样,问题是找到一个有效的XQuery代码,并考虑到我在一个庞大的语料库中查找了1581个单词,并且要经历的数据库数量很多(数千)。对于每个数据库查找,通过Perl建立新连接。

        如果您有任何疑问,请发表评论,我会尽可能地回答。

1 个答案:

答案 0 :(得分:1)

一般情况下,如果您利用索引而不是让查询遍历一万亿个节点,BaseX查询将是最快的(通常,非常快)。除非您修改了默认的数据库创建选项,否则BaseX默认为您创建TEXT,ATTRIBUTE和TOKEN索引。 (BaseX还尝试重新编写查询以利用索引 - 虽然它并不总是成功的。)

因此,假设您的数据库是使用ATTRIBUTE索引构建的,您应该能够按以下方式重新编写查询:

db:attribute('dbname', 'accelerator', 'word')/parent::*

上面使用的db:attribute函数将返回数据库&#39; dbname&#39;,任何属性的父元素,加速器&#39;作为@word的值。显然你可以根据需要预测这个查询,就像这样,从你之前的例子来看:

db:attribute('dbname', 'accelerator', 'word')
      [parent::node[@rel="hd" and @pt="n"]]
      [ancestor::node
        [@cat="np"]
        [child::node[@rel="det" and @pt="lid" and @lemma="het"]
      ]
    ]

以下是有关BaseX索引功能的详细文档。我已经将它用于快速查询大型(> 20 GB)数据库。

http://docs.basex.org/wiki/Indexes