PAYATHON 2026

MarkLogic 如何仅返回最近10天的 URI,并解决范围索引错误?

数据阿明

需要解决两个问题:让日期参数的类型与元素范围索引匹配,并将时间条件改为“晚于或等于 10 天前,早于或等于当前时间”。原查询的日期上下界写反了;报错则表明查询正在查找 string 类型的元素范围索引。

为什么配置了索引仍然报错?

报错中的关键部分是:

No string element range index for {http://nl.abnamro.com/cre}ingestTime
collation=http://marklogic.com/collation/

这说明查询没有找到所需的 string 元素范围索引,不能据此断定所有类型的索引都不存在。如果实际配置的是 dateTime 索引,而日期变量以字符串传入,就可能出现类型不匹配。

原问题没有给出变量绑定代码和索引的 scalar type,因此还不能确定具体原因。建议检查:

  1. 脚本实际查询的数据库是否就是配置索引的数据库。若通过 Query Console 执行,检查当前选择的 Content Source。
  2. 索引是否为 Element Range Index,元素 namespace URI 是否为 http://nl.abnamro.com/cre,localname 是否为 ingestTime。
  3. 索引的 scalar type 是 dateTime、date 还是 string,以及两个日期变量的实际类型。

cts:element-range-query 要求存在对应 QName 的元素范围索引;字符串索引还涉及 collation 匹配。参见 MarkLogic 9 的函数说明。

先修正日期条件

按照问题中的变量含义,原条件实际表达的是:

cre:ingestTime <= 3月17日
且
cre:ingestTime >= 3月27日

对于只有一个 cre:ingestTime 值的文档,这两个条件无法同时满足。正确的方向是:

cts:element-range-query(xs:QName("cre:ingestTime"), ">=", $selectedDate),
cts:element-range-query(xs:QName("cre:ingestTime"), "<=", $chooseDate)

调整比较符号后,还需要确保变量类型与索引匹配。

dateTime 索引下的完整示例

以下示例假设 cre:ingestTime 已配置 dateTime 元素范围索引,并将“最近 10 天”定义为从当前时刻向前推 10 天。代码保留三个 collection 条件,以及原查询对当前主机所属数据库 forests 的限制:

xquery version "1.0-ml";

declare namespace cre = "http://nl.abnamro.com/cre";

let $end as xs:dateTime := fn:current-dateTime()
let $start as xs:dateTime := $end - xs:dayTimeDuration("P10D")
let $forests :=
  xdmp:host-forests(xdmp:host())[
    . = xdmp:database-forests(xdmp:database())
  ]
let $query :=
  cts:and-query((
    cts:collection-query("http://nl.abnamro.com/cre/canonical"),
    cts:collection-query("http://nl.abnamro.com/cre/source/rapid"),
    cts:collection-query("latest"),
    cts:element-range-query(
      xs:QName("cre:ingestTime"), ">=", $start
    ),
    cts:element-range-query(
      xs:QName("cre:ingestTime"), "<=", $end
    )
  ))
return
  cts:uris((), (), $query, (), $forests)

两个边界都使用 xs:dateTime,避免将日期文本直接作为 string 传入。如果继续使用外部传入的变量,可以在构造查询前转换:

let $start := xs:dateTime($selectedDate)
let $end := xs:dateTime($chooseDate)

输入需要能转换成合法的 xs:dateTime;只有日期的字符串不能直接当作完整时间戳使用。如果实际索引是 date,应使用 xs:date 边界,不能直接套用上述 dateTime 示例。

仍需注意哪些边界?

  • 时间段含义:从 3 月 17 日某一时刻到 3 月 27 日同一时刻是 10 天;若按整日同时包含 3 月 17 日和 3 月 27 日,则覆盖 11 个日期。若需求是“包含今天的最近 10 个自然日”,应从今天零点向前推 9 天,并以明天零点作为排他的上界,使用 <。
  • 时区:自然日边界应按业务时区计算。缺少时区的日期时间会涉及隐式时区,需要确认执行环境与业务要求一致。
  • 索引生效:新建或调整范围索引后,要确认已有数据完成重新索引。相关要求见 MarkLogic 9 范围查询指南。
  • 查询范围:原查询限制了 forests,可能只覆盖数据库的一部分。若目标是整个当前数据库,可使用 cts:uris((), (), $query)。
  • 多个时间值:如果一个文档包含多个 cre:ingestTime,上下界条件可能分别命中不同值。应确认数据结构是否保证单值,必要时进一步验证同一个时间值是否落在区间内。

此外,cts:uris 依赖 URI lexicon,应确认目标数据库已启用它;这是与日期范围索引不同的配置。参见 MarkLogic 9 lexicon 使用说明。

备注:内容仅供参考。