PAYATHON 2026

MarkLogic temporal:document-insert 报 XDMP-NOMATCH 如何解决?

数据阿明

结论

应先修正系统时间轴的字段和索引配置。贴出的代码有三处问题:使用了普通字段而非 metadata 字段;创建字段后没有保存函数返回的新配置;admin:database-range-field-index 中字段名和 collation 参数的顺序写反了。

XDMP-NOMATCH 表示插入过程中无法根据 systemStart 的引用找到匹配项。结合配置中的问题,应先检查系统时间的存储位置和字段定义。仅凭这条错误,不能认定是 MarkLogic 11.3.4 的版本缺陷。

为什么自动生成系统时间仍会报错?

MarkLogic 管理系统时间的值,但仍需为时间轴正确配置存储映射。如果希望 XML 中只保留业务内容,并将系统时间存入 metadata,应使用 admin:database-metadata-field 创建对应字段。即使将普通字段命名为 systemStart,它也不会成为 metadata 字段。参见官方的 metadata 字段 API。

也可以将系统时间存入文档正文。此时,文档必须包含能够匹配时间轴引用的起止元素或属性,由 MarkLogic 填入系统时间。官方说明,这些位置可以使用空值或时间戳占位。参见 时态文档管理说明。

当前 XML 只有 content,配置也没有正确建立 metadata 字段,因此需要先修正时间轴与存储位置的映射。

原配置需要修改哪些地方?

保存字段创建函数返回的新配置

admin:database-add-field 返回更新后的配置对象。原代码两次传入同一个旧 $config,最后保存的仍是旧配置,新增字段的结果没有传递给后续操作。

应将每次返回值赋给后续使用的配置变量,再调用 admin:save-configuration。这是 Admin API 文档 中规定的使用方式。

调整 range field index 的参数顺序

前四个参数依次是 scalar type、field name、collation、range value positions。原调用:

admin:database-range-field-index("dateTime", "", "systemStart", false())

应改为:

admin:database-range-field-index("dateTime", "systemStart", "", false())

systemEnd 同样需要修改。官方 Temporal Quick Start 使用的也是这一参数顺序。

如何按 metadata 方式重新配置?

以下示例适用于尚未存在同名字段、索引、时间轴和集合的测试数据库。已有配置时,先检查实际定义,再修正对应项;不要直接重复创建或删除已有时态集合。

这些代码依据官方 API 定义整理,未在题述的 11.3.4 环境中实际运行。

1. 创建 metadata 字段和 dateTime 索引

在目标内容数据库的上下文中执行:

xquery version "1.0-ml";

import module namespace admin = "http://marklogic.com/xdmp/admin"
  at "/MarkLogic/admin.xqy";

let $dbid := xdmp:database()
let $config := admin:get-configuration()
let $config := admin:database-add-field(
  $config,
  $dbid,
  (
    admin:database-metadata-field("systemStart"),
    admin:database-metadata-field("systemEnd")
  )
)
let $config := admin:database-add-range-field-index(
  $config,
  $dbid,
  admin:database-range-field-index(
    "dateTime", "systemStart", "", fn:false()
  )
)
let $config := admin:database-add-range-field-index(
  $config,
  $dbid,
  admin:database-range-field-index(
    "dateTime", "systemEnd", "", fn:false()
  )
)
return admin:save-configuration($config)

配置保存完成后,再执行下面的时间轴创建语句。

2. 创建系统时间轴

xquery version "1.0-ml";

import module namespace temporal = "http://marklogic.com/xdmp/temporal"
  at "/MarkLogic/temporal.xqy";

temporal:axis-create(
  "systemAxes",
  cts:field-reference("systemStart", "type=dateTime"),
  cts:field-reference("systemEnd", "type=dateTime")
)

显式写出 type=dateTime,便于核对引用与索引是否一致。

3. 创建只使用系统时间轴的集合

单独执行:

xquery version "1.0-ml";

import module namespace temporal = "http://marklogic.com/xdmp/temporal"
  at "/MarkLogic/temporal.xqy";

temporal:collection-create("entity:person", "systemAxes")

4. 插入业务文档

完成 metadata 配置后,插入语句可以保留原来的 XML 结构:

xquery version "1.0-ml";

import module namespace temporal = "http://marklogic.com/xdmp/temporal"
  at "/MarkLogic/temporal.xqy";

let $root :=
  <tempdoc>
    <content>v1-content here</content>
  </tempdoc>
return
  temporal:document-insert("entity:person", "koolorder.xml", $root)

仍然报错时检查什么?

先核对数据库中的实际配置。报错中已经出现 systemStart 的 dateTime 引用,而贴出的创建脚本存在保存和参数问题,因此不能直接假定现有配置完全由这些脚本生成。

按以下顺序检查:

  1. 配置脚本、时间轴创建和插入操作是否使用同一个目标内容数据库。
  2. systemStart、systemEnd 是否确实为 metadata 字段,并各自具有 dateTime range field index。
  3. systemAxes 是否引用这两个字段,entity:person 是否使用该时间轴。
  4. 使用 ml-gradle 部署后,检查数据库最终生效的字段类型和索引定义;部署工具的变化本身无法修正错误的配置内容。

不要继续通过 options 随意填入系统时间来绕过错误。官方插入 API 说明,metadata 中尝试设置系统时间的值会被忽略。如果需要由应用控制系统时间,应使用 temporal:statement-set-system-time,并满足相应的 LSQT 条件。参见 插入 API 说明 和 系统时间控制说明。

如果改用 bi-temporal collection,还必须配置 valid 时间轴并提供有效的 valid start/end。增加 valid 时间轴不会自动修复系统时间字段的映射问题。

备注:内容仅供参考。