Xquery 几个xml文档的组合搜索查询

Xquery 几个xml文档的组合搜索查询,xquery,marklogic,Xquery,Marklogic,我在每个图书目录/books/{book\u id}/中都有一些xml文档。 /books/{book\u id}/basic.xml和/books/{book\u id}/formats.xml。 第一个是 <document book_id="{book_id}"> <title>The book</title> </document> 书 第二个是 <document book_id="{boo

我在每个图书目录
/books/{book\u id}/
中都有一些xml文档。
/books/{book\u id}/basic.xml
/books/{book\u id}/formats.xml
。 第一个是

    <document book_id="{book_id}">
      <title>The book</title>
    </document>
第二个是

    <document book_id="{book_id}">
      <format>a</format>
      <format>b</format>
      <format>c</format>
    </document>

A.
B
C
如何通过一次查询找到
/books/
目录下
格式为eq'a'
标题为eq*'book'*
的所有书籍?当我首先通过
cts:search()
按格式查找所有书籍,然后通过检查basic.xml文件中的标题在“for循环”中过滤结果时,我做了一个变体

谢谢大家!

如何通过一次查询找到/books/目录中格式为eq'a'和标题为eq'book'的所有书籍

尝试:

最后一个谓词如果变为空,将导致找不到
标题
。如果它存在,则将返回
title

当然,您应该将
X
替换为您的ID。您可以设置包含ID的相对路径。如果您有一组想要查看的ID,您可以执行以下操作:

for $id in ('{book_id1}', '{book_id2}')
return 
    doc(concat($id, '/basic.xml'))/document[@book_id=$id]/title[contains(., 'book')]]
    [doc(concat($id, '/format.xml'))/document[@book_id=$id][format = 'a']
你会明白的;)


PS:我不确定
{…}
是否是合法的URI路径部分,但我假设您将用一些合理的东西替换它。否则,请使用适当的百分比编码对其进行转义。

可能是显而易见的,最好的方法是更改模型,使格式与标题位于同一文档中,并且可以通过单个查询进行匹配

如果不可能,一种替代方法是在数据库配置中打开uri词典(如果尚未启用)

假设标题比格式更具选择性,那么可以采用以下方法

let $title-uris := cts:uris((), (), cts:and-query((
    cts:directory-query("/books/", "infinity"),
    cts:element-word-query(xs:QName("title"), "book")
    )))
let $title-dirs := 
    for $uri in $title-uris
    return fn:replace($uri, "/basic\.xml$", "/")
let $format-uris := cts:uris((), (), cts:and-query((
    cts:directory-query($title-dirs),
    cts:element-value-query(xs:QName("format"), "a")
    )))
let $book-docs := 
    for $uri in $format-uris
    return fn:replace($uri, "/format\.xml$", "/basic.xml")
for $doc in fn:doc($book-docs)
return ... do something with the basic document ...
文档读取之外的额外成本包括两个uri词典查找和字符串操作。好处在于只读取匹配的文档

一般来说,使用索引匹配相关文档比将文档读入内存并过滤掉不相关的文档更好。cts:uris()和cts:search()函数始终首先使用索引进行匹配(并且仅在指定搜索选项时进行筛选)。XPath尽可能通过匹配索引进行优化,但必须回退到筛选某些谓词。除非您非常小心,否则通常最好将XPath限制为在内存中导航节点


希望能有所帮助,

这个问题被列为MarkLogic和xQuery。为了完整起见,我提供了一个MarkLogic解决方案,它是一个单独的语句:

let $res := cts:search(doc(), cts:and-query(
       (
         cts:element-word-query(xs:QName("title"), '*book*', ('wildcarded'))
         ,
         cts:element-attribute-range-query(xs:QName("document"), xs:QName("book_id"), '=', cts:element-attribute-values(xs:QName("document"), xs:QName("book_id"), (), (), cts:element-value-query(xs:QName("format"), 'b')))
          )
         ) 
)
嗯。现在,让我们将其分解并看一看

注意:此示例需要属性书id上的单个范围索引

我认为该工具的优势在于,在这两种类型的文档中,在同一名称空间中具有相同的属性。这使得:

  • 我可以使用一个索引
    • 然后,我对图书ID列表使用元素属性值
      --这受到“格式”元素的约束
    • 上面的图书ID列表用于筛选图书(范围查询)
    • 然后通过标题进一步过滤
    • 这种方法使用一个极快的范围索引连接两个文档,特别是在book_id的整数值上
应该注意的是,在这种特殊情况下,我能够隔离适当的文档,因为标题元素只存在于一种类型的文档中

现在,让我们看一个相同查询的更清晰的示例

(: I used a word-query so that I could do wildcarded searches for document with 'book' in the title.  This is because your sample has a title 'The Book', yet you search for 'book' so I can olnly conclude that you meant to have wildcard searches :)
let $title-constraint := "*book*"
(: This could also be a sequence :)
let $format-constraint := "a"
(: used for the right-side of the element-range-query :)
let $format-filter := cts:element-attribute-values(xs:QName("document"), xs:QName("book_id"), (), (), cts:element-value-query(xs:QName("format"), $format-constraint))
(: final results :)
let $res := cts:search(doc(), cts:and-query((
                                            cts:element-word-query(xs:QName("title"), $title-constraint, ('wildcarded'))
                                            ,
                                            cts:element-attribute-range-query(xs:QName("document"), xs:QName("book_id"), '=', $format-filter)
                                            )
                             ) )
return $res

我想我找到了更好的解决办法

let $book_ids := cts:values(
  cts:element-attribute-reference(xs:QName("document"), xs:QName("book_id") ), 
  (), 
  ("map"), 
  cts:and-query((
    cts:directory-query(("/books/"), "infinity"),
    cts:element-query(xs:QName("title"),"book")
  ))
)
return 
  cts:search(
    /, 
    cts:and-query((
      cts:element-attribute-value-query(xs:QName("document"), xs:QName("book_id"), map:keys($book_ids)),
      cts:element-value-query(xs:QName("format"), "a"),
    ))
  )

非常感谢。我昨天错过了你的答案,今天贴了一些和你一样的东西。
let $book_ids := cts:values(
  cts:element-attribute-reference(xs:QName("document"), xs:QName("book_id") ), 
  (), 
  ("map"), 
  cts:and-query((
    cts:directory-query(("/books/"), "infinity"),
    cts:element-query(xs:QName("title"),"book")
  ))
)
return 
  cts:search(
    /, 
    cts:and-query((
      cts:element-attribute-value-query(xs:QName("document"), xs:QName("book_id"), map:keys($book_ids)),
      cts:element-value-query(xs:QName("format"), "a"),
    ))
  )