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,因此还不能确定具体原因。建议检查:
- 脚本实际查询的数据库是否就是配置索引的数据库。若通过 Query Console 执行,检查当前选择的 Content Source。
- 索引是否为 Element Range Index,元素 namespace URI 是否为
http://nl.abnamro.com/cre,localname 是否为ingestTime。 - 索引的 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 使用说明。
备注:内容仅供参考。
