我需要在荷兰语的XML语料库中查找1581个单词(5亿个单词)。该语料本身在许多数据库中均被拆分。 (您可以了解为什么使用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可以处理多少个参数。
  • 合并de和het查询。

  • 这可能是最直接的情况。这样,我至少将查询需求减少了一半。但是我不知道发现结果时如何区分两者。例如,如果我将XPath代码更改为:
    ... (@lemma="de" or @lemma="het") ...
    

    我应该找到所有情况,但是如何区分一个或另一个呢?换句话说,如果使用该XPath,我将从XQuery中的count函数返回一个数字,但是我无法知道哪个是de,哪个是the?
  • 可以将相同的想法应用于
  • 末尾附近的word属性

    我可以对每个单词进行以下连接,而不是对每个单词执行新的查询:
    ... (@word="accelerator" or @word="accountant" or @word="ace" or ...) ...
    

    但是,我又如何区分这些值?我可以将所有1581个值放在一个XPath中吗? BaseX可以处理吗?
  • 一个带有单词列表的for循环,然后它将以XML格式返回很多单词的结果(如果BaseX可以处理,则可能全部返回)。

  • 我不是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>
    

    然后,我可以使用带有正则表达式或XML Twig 的Perl来运行以获得所需的值。

    如您所见,可能的问题是找到一个合适的XQuery代码,该代码高效,并且考虑到我有1581个单词要在庞大的语料库中查找,并且要通过的数据库数量也很多(千)。对于每个数据库查找,将通过Perl建立新的连接。

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

    最佳答案

    通常,如果您利用索引而不是使查询遍历一万亿个节点,那么BaseX查询将是最快的(通常是令人眼花fast乱的)。除非您已修改默认的数据库创建选项,否则默认情况下,BaseX会为您创建TEXT,ATTRIBUTE和TOKEN索引。 (BaseX还尝试重新编写查询以利用索引,尽管这种方法并不总是成功的)。

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

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

    对于数据库'dbname',上面使用的db:attribute函数将返回任何以'accelerator'作为@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

    10-08 07:32