MarkLogic 中的路径表达式 cts.search

Path expression in MarkLogic cts.search

我的印象是 MarkLogic 中的 XQuery 和服务器端 JavaScript API 在很大程度上是等效的。但是 cts:searchcts.search 似乎有很大的不同。在 cts:search 中,我可以指定要搜索和 return 的元素。例如,我可以从食谱书中检索所有使用肉桂作为原料的食谱:

cts:search(//recipe, cts:element-word-query(xs:QName('ingredients'), 'cinnamon'))

cts.search 不接受路径表达式并将 return 整个食谱书文档:

cts.search(cts.elementWordQuery(xs.QName('ingredients'), 'cinnamon'))

同样的问题已在 MarkLogic 邮件列表中提出,但我在那里没有看到答案:https://developer.marklogic.com/pipermail/general/2015-March/016508.html

下面是一个最小的例子:

<book>
  <recipe>
    <ingredients>cinnamon, peppermint</ingredients>
    <instruction/>
  </recipe>
  <recipe>
    <ingredients>sugar, peppermint</ingredients>
    <instruction/>
  </recipe>
  <recipe>
    <ingredients>coconut oil</ingredients>
    <instruction/>
  </recipe>
</book>

xquery 将是:

cts:search(//recipe, cts:element-word-query(xs:QName('ingredients'), 'cinnamon'))

和响应:

<recipe>
  <ingredients>cinnamon, peppermint</ingredients>
  <instruction></instruction>
</recipe>

这是有技术原因的。 XQuery 中的 cts:search 函数实际上不是函数,而是具有函数语法的特殊形式。这意味着第一个参数实际上并没有得到评估然后传递给函数(如果你考虑一下,那将是一种非常低效的处理方式!)。在Javascript中,cts.search函数是一个实函数。为了避免效率低下,我们删除了第一个参数,因此您需要将您关心的部分从结果中拉出来。

如果您想将结果集限制在元素 recipe 内,请用 cts:element-query(xs:QName("recipe"), $your-query)

包裹您的查询

这会让你们更接近

https://docs.marklogic.com/cts.elementQuery

根据需要应用 cts.andQuery。

在很大程度上,JS 和 XQuery 接口在功能上是等价的,但有几个地方(这是一个)语言本身不直接支持等价。另一个是 XQuery 序列,它在 JS 中没有本机等效项——因此通过额外的 JS 类.

提供

任何 cts(复杂)查询都可以从原始 cts 查询中构造出来 objects/methods。 XQuery cts::search() 中的第一个参数是 'searchable expression' —— 它与约束范围本质上相同 —— 可以与 cts.andQuery 结合产生相同的效果(在两个 XQuery 中和JS)。根据您在 XQuery 中使用的确切表达式,您需要为 JS(或 xquery)找到等效的 cts.query。

因此 cts.elementQuery 类似于 cts::search(//element-name, ..)

考虑到 cts:search() 的 javascript 版本缺少 xquery 版本的第一个参数——我看不出它怎么能 return 除了文档节点之外的任何东西。 cts:search 和 cts.search 使用的索引优化具有 'fragments' 的粒度(通常是文档)——旨在找到潜在无限集合中的少数匹配文档。从那里您需要遍历文档的结构。 XQuery 特别擅长这一点——路径遍历是该语言的原生特性,JavaScript 没那么多。

我建议您使用 search.search 而不是 cts:search -- 它是更高级别的 API,旨在简化此类任务。

在 DALDEI 的回答的基础上,您可以使用搜索 api 到 return 只有配方元素:

const search = require('/MarkLogic/appservices/search/search');

let options = fn.head(xdmp.unquote(`
<options xmlns="http://marklogic.com/appservices/search">
  <return-results>true</return-results>
  <searchable-expression>//recipe</searchable-expression>
  <extract-document-data>all</extract-document-data>
  <additional-query>
    <cts:element-word-query xmlns:cts="http://marklogic.com/cts">
      <cts:element>ingredients</cts:element>
      <cts:text xml:lang="en">cinnamon</cts:text>
    </cts:element-word-query>
  </additional-query>
</options>`)).root;

search.search("", options)        // returns a Sequence of search:response
  .toArray()[0]                   // get the first result
  .getElementsByTagName("recipe") // find all recipe elements 

此代码return是配方元素的节点列表。您提供的书的结果将是这个单一元素节点:

<recipe xmlns:search="http://marklogic.com/appservices/search">
  <ingredients>cinnamon, peppermint</ingredients>
  <instruction/>
</recipe>

这不是一个很好的解决方案(就快速和简单而言),但它可以作为一种解决方法。

我也尝试过使用 jsearch 函数,但没有找到传递 searchable-expression 参数的方法。我可能错过了,因为我还没有经常使用它。

进一步阅读:

Query Options Reference search:search