搜索 Business Object 和节点
RealityConnect API 提供两个作用域不同的搜索路由:business object 搜索在孪生体内部查找 POI、区域、资产及其元数据,而节点搜索在你组织的节点层级结构(站点、文件夹、孪生体和文件)中查找。两个路由都是实验性的,可能会发生变化。
| 方法 | 路径 | 作用域 | 用途 |
|---|---|---|---|
GET | /v1/twin/{contextId}/search | Basic | 搜索孪生体内部的 business object 与元数据 |
GET | /v1/nodes/search | ReadHierarchy | 搜索组织的节点层级结构 |
搜索 business object
Section titled “搜索 business object”GET /v1/twin/{contextId}/search 在单个孪生体(或由 contextId 标识的其站点/草稿)内部搜索 POI、区域、box asset、测量及其他 business object,匹配依据为名称、保留字段、资产元数据以及对象特定属性。
| 参数 | 类型 | 说明 |
|---|---|---|
fieldFilters | JSON 对象数组 | 保留键过滤器。见下文。 |
metadataFilters | JSON 对象数组 | 匹配孪生体的资产元数据属性。见下文。 |
additionalPropertyFilters | JSON 对象数组 | 匹配对象类型特定的属性(例如 POI 的 icon)。见下文。 |
page | 整数 | 正整数,默认 1。 |
limit | 整数 | 1–50,默认 50。 |
searchNameQuery | string | 独立于 fieldFilters 中名称的专用名称过滤器。 |
nameMatch | exact | contains | searchNameQuery 的匹配模式,默认 contains。 |
createdById | uuid | 按创建者过滤。 |
createdBefore / createdAfter | timestamp | 严格早于/晚于。格式为 YYYY-MM-DDTHH:mm:ss(无时区偏移,无毫秒)。 |
updatedBefore / updatedAfter | timestamp | 格式相同。 |
sortBy | name | createdAt | updatedAt | 排序字段。 |
sortDir | ASC | DESC | 排序方向。 |
fieldFilters、metadataFilters 和 additionalPropertyFilters 各自以一个 JSON 对象字符串表示一个过滤器,多个过滤器时重复该查询参数:
?fieldFilters={"key":"type","values":["poi"]}&fieldFilters={"key":"type","values":["zone"]}每个过滤器对象的形状为 { "key": string, "values": string[] }。同一个过滤器 values 数组中的多个值以 OR 组合。
fieldFilters 仅接受以下保留键 —— 其他键会被静默忽略:
| 键 | 匹配对象 |
|---|---|
type | Business object 类型。可以是枚举值(Poi、Zone、BoxAsset、CubePrimitive、PlanePrimitive、DistanceMeasure、CoordinateMeasure、DiameterMeasure、SurfaceMeasure、OrthogonalMeasure、Cut、ModelAsset),也可以是其规范化的 kebab-case 令牌 —— 即将 PascalCase 名称转为带连字符的小写形式,例如 BoxAsset → box-asset。 |
asset-type | 对象的资产类型(映射到 assetTypeId)。精确匹配。 |
name | 仅对名称进行前缀匹配,无模糊性。 |
id | 精确匹配对象 id。 |
fieldFilters 的值始终是纯字符串或枚举令牌 —— 下文的数值/范围语法不适用于它。
metadataFilters 和 additionalPropertyFilters 通过键来定位一个由 schema 定义的元数据属性(metadataFilters),或一个不属于通用元数据的对象类型特定属性(additionalPropertyFilters,例如 POI 的 icon)。values 中的每个值支持:
| 值语法 | 含义 |
|---|---|
| 纯字符串 | 精确匹配。values 中的多个纯字符串以 OR 组合。 |
* 或空字符串 | 被忽略 —— 若这是唯一的值,过滤器仅按键是否存在进行匹配。 |
=123、!=123、>123、>=123、<123、<=123 | 数值比较。支持整数、小数和科学计数法(例如 1.5e+35)。 |
range:[1..10] | 闭区间数值范围。 |
range:(1..10) | 开区间数值范围。 |
range:[1..10) / range:(1..10] | 半开区间的混合边界。 |
true / false | 仅 additionalPropertyFilters —— 按字面量匹配布尔属性。 |
fieldFilters、metadataFilters 和 additionalPropertyFilters 都以 AND 语义组合:结果必须满足每一个过滤器。在单个过滤器内部,其 values 数组中的多个值以 OR 组合 —— 因此两个共享同一 key 的 fieldFilters 对象表现为”满足任一值即可”,而作用于不同键(或不同过滤器数组)的过滤器则会进一步收窄结果集。
类型过滤器与数值元数据范围结合(检测压力记录在 80 到 120 之间的 POI):
GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%5D%7D&metadataFilters=%7B%22key%22%3A%22inspection.pressure%22%2C%22values%22%3A%5B%22range%3A%5B80..120%5D%22%5D%7DAuthorization: Bearer {access_token}资产类型与名称过滤器结合,按最近更新排序:
GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22asset-type%22%2C%22values%22%3A%5B%22pump%22%5D%7D&fieldFilters=%7B%22key%22%3A%22name%22%2C%22values%22%3A%5B%22vibration%22%5D%7D&sortBy=updatedAt&sortDir=DESCAuthorization: Bearer {access_token}含义为:资产类型为 pump 且 名称以 “vibration” 开头的对象,按最近更新排序。
同一键上的两个 fieldFilters(OR 组合)与不同键上的 fieldFilters(AND 组合)结合 —— POI 或区域,限定为 pump 资产类型:
GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%2C%22zone%22%5D%7D&fieldFilters=%7B%22key%22%3A%22asset-type%22%2C%22values%22%3A%5B%22pump%22%5D%7DAuthorization: Bearer {access_token}布尔型 additionalPropertyFilters 字面量与字符串型 metadataFilters 匹配结合 —— 元数据中检测状态记录为 “warning” 的活动 POI:
GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%5D%7D&additionalPropertyFilters=%7B%22key%22%3A%22isActive%22%2C%22values%22%3A%5B%22true%22%5D%7D&metadataFilters=%7B%22key%22%3A%22inspection.status%22%2C%22values%22%3A%5B%22warning%22%5D%7DAuthorization: Bearer {access_token}同时使用全部三种过滤输入、一个专用名称过滤器、一个日期范围、分页和排序的完整请求 —— 展示完整的请求形状:
GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%2C%22zone%22%5D%7D&metadataFilters=%7B%22key%22%3A%22inspection.pressure%22%2C%22values%22%3A%5B%22range%3A%5B80..120%5D%22%5D%7D&additionalPropertyFilters=%7B%22key%22%3A%22isActive%22%2C%22values%22%3A%5B%22true%22%5D%7D&searchNameQuery=Pump&nameMatch=contains&updatedAfter=2026-01-01T00%3A00%3A00&updatedBefore=2026-12-31T23%3A59%3A59&page=1&limit=25&sortBy=updatedAt&sortDir=DESCAuthorization: Bearer {access_token}sortBy | 排序依据 |
|---|---|
name | 对象名称 |
createdAt | 创建时间戳 |
updatedAt | 最后更新时间戳 |
每个 sortBy 值都可以与任意 sortDir 值组合:
GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%5D%7D&sortBy=name&sortDir=ASCAuthorization: Bearer {access_token}GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%5D%7D&sortBy=createdAt&sortDir=DESCAuthorization: Bearer {access_token}GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%5D%7D&sortBy=updatedAt&sortDir=DESCAuthorization: Bearer {access_token}省略 sortDir 时默认为 ASC。sortBy 没有文档化的默认字段 —— 省略它时会按内部相关性得分(降序)排序,并以 id(升序)作为平局判定依据。只有 key: "name" 的 fieldFilters 会影响该得分;其他所有过滤器都只是纯粹的是/否匹配,对排名没有影响,因此在实践中,如果省略 sortBy 且没有 name 过滤器,结果将按 id 顺序返回。这是一项实现细节,而非有保证的约定 —— 当特定的字段顺序对你的集成很重要时,请始终显式设置 sortBy。
数值和范围过滤器
Section titled “数值和范围过滤器”在 metadataFilters 和 additionalPropertyFilters 的值内部,一个值可以携带比较运算符或范围,而不是进行字面量匹配。此语法不适用于 fieldFilters —— 那些始终是字面量/枚举匹配(type、asset-type、name、id)。
| 运算符 | 示例 | 含义 |
|---|---|---|
= | =123 | 等于 |
!= | !=123 | 不等于 |
> | >123 | 大于 |
>= | >=123 | 大于或等于 |
< | <123 | 小于 |
<= | <=123 | 小于或等于 |
range:[a..b] | range:[80..120] | 两端均为闭区间 |
range:(a..b) | range:(80..120) | 两端均为开区间 |
range:[a..b) | range:[80..120) | 下界闭区间,上界开区间 |
range:(a..b] | range:(80..120] | 下界开区间,上界闭区间 |
支持整数、小数、负数和科学计数法,例如 >=-40、=3.14 或 range:[1.5e+35..2.0e+35]。
名称过滤器与名称查询的对比
Section titled “名称过滤器与名称查询的对比”按名称匹配有两种不同的方式,它们的行为各不相同:
| 参数 | 匹配方式 | 是否可与其他过滤器组合? |
|---|---|---|
fieldFilters={"key":"name",...} | 前缀匹配,无模糊性 | 是 —— 始终以 AND 组合 |
searchNameQuery + nameMatch | contains(默认)或 exact,无模糊性 | 是 —— 始终以 AND 组合 |
使用 key: "name" 的 fieldFilters 进行仅名称的前缀匹配,它会按与 type 或 asset-type 相同的 AND/OR 规则组合。当你需要不带模糊容错的精确子字符串或精确名称查找时(例如验证某个名称是否逐字存在),使用带 nameMatch 的 searchNameQuery。
{ "results": [ { "id": "5e1c0b3a-2d9a-4b7d-8f0b-9a2c8f1b7a10", "name": "Fire extinguisher 12", "type": "Poi", "matchedFields": [ { "matchKey": "name", "highlight": "Fire <em>extinguisher</em> 12" } ], "createdAt": "2026-06-01T10:00:00.000Z", "updatedAt": "2026-06-01T10:00:00.000Z", "createdById": "8f0b9a2c-8f1b-4a10-9e1c-0b3a2d9a4b7d" } ], "count": 1}matchedFields 显示哪个字段或元数据属性匹配,匹配到的文本用 <em> 包裹。matchKey 要么是根字段名称(例如 name),要么是匹配到的嵌套元数据/属性值对应的 @<metadata-path>。
单个结果可以携带多个 matchedFields 条目 —— 每个匹配的字段或元数据属性对应一条。例如,一个同时匹配对象名称和检测元数据值的 fieldFilters 名称匹配与 metadataFilters 组合请求会返回:
{ "id": "5e1c0b3a-2d9a-4b7d-8f0b-9a2c8f1b7a10", "name": "Pressure gauge 04", "type": "Poi", "matchedFields": [ { "matchKey": "name", "highlight": "<em>Pressure</em> gauge 04" }, { "matchKey": "@inspection.status", "highlight": "<em>Warning</em>: recalibration due" } ], "createdAt": "2026-06-01T10:00:00.000Z", "updatedAt": "2026-06-01T10:00:00.000Z", "createdById": "8f0b9a2c-8f1b-4a10-9e1c-0b3a2d9a4b7d"}高亮片段在插入 <em> 标记之前会先进行 HTML 转义,因此匹配文本中的任何 <、> 或 & 会以 <、> 或 & 的形式出现,而不是原始标记 —— 可以直接安全地渲染为 HTML,无需二次转义,但如果你需要纯文本值,请先解码它。
| 情况 | 行为 |
|---|---|
| 没有任何过滤器(或全部为空) | 返回孪生体内的所有 business object,最多 limit 条,不进行排名(match_all)。 |
无法识别的 fieldFilters 键 | 被静默忽略 —— 该过滤器对查询没有任何贡献,不会引发 400。 |
metadataFilters/additionalPropertyFilters 的值为 * 或 "" | 被跳过。如果该过滤器 values 数组中的每个值都以这种方式被跳过,该过滤器仍会要求对象在该键上存在属性 —— 它变成一个不带值约束的键存在性检查。 |
名称前缀搜索:
GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22name%22%2C%22values%22%3A%5B%22extinguisher%22%5D%7DAuthorization: Bearer {access_token}按名称排序的名称包含搜索:
GET {api_url}/v1/twin/{contextId}/search?searchNameQuery=Pump&nameMatch=contains&sortBy=name&sortDir=ASCAuthorization: Bearer {access_token}| 状态 | 原因 |
|---|---|
400 Bad Request | fieldFilters、metadataFilters 或 additionalPropertyFilters 的某个值不是合法 JSON,或不符合 { key, values } 的形状。 |
重复的过滤器参数(多个带有不同 JSON 值的 fieldFilters、metadataFilters 或 additionalPropertyFilters)无法用 requests 基于字典的 params 构建 —— 一个字典每个键只能保存一个值。请改用 urllib.parse.urlencode 和元组列表自行构建查询字符串:
import jsonimport requestsfrom urllib.parse import urlencode
API_URL = "https://<your-regional-api-url>"TOKEN = "<access_token>"CONTEXT_ID = "<twin-id>"
headers = {"Authorization": f"Bearer {TOKEN}"}
params = [ ("fieldFilters", json.dumps({"key": "type", "values": ["poi"]})), ("metadataFilters", json.dumps({"key": "inspection.pressure", "values": ["range:[80..120]"]})), ("sortBy", "name"), ("sortDir", "ASC"),]
response = requests.get( f"{API_URL}/v1/twin/{CONTEXT_ID}/search?{urlencode(params)}", headers=headers,).json()
for result in response["results"]: print(result["type"], result["name"], result["id"])GET /v1/nodes/search 搜索的是你组织的节点层级结构 —— 分部、站点、文件夹、孪生体、asset library 和数据文件 —— 而不是某个孪生体内部的 business object。组织信息从 access token 中解析,而不是作为参数传入。
| 参数 | 类型 | 说明 |
|---|---|---|
nodeTypes | DataNodeType 数组 | 按一个或多个节点类型过滤。重复该参数,例如 ?nodeTypes=Site&nodeTypes=Folder。取值:Organization、Site、Pointcloud、Mesh、SiteFile、Folder、Project、Division、Artifact、DataBundle、Twin、AssetLibrary。 |
excludeNodeTypes | DataNodeType 数组 | 排除一个或多个节点类型。重复语法相同。 |
searchNameQuery | string | 按节点名称过滤。 |
nameMatch | exact | contains | searchNameQuery 的匹配模式,默认 contains。 |
parentId | uuid | 仅该节点的直接子节点。 |
ancestorId | uuid | 任意深度的后代节点,不含祖先节点本身。用于站点或文件夹下的嵌套内容;如只需直接子节点,使用 parentId。 |
createdById | uuid | 按创建者过滤。 |
createdBefore / createdAfter | timestamp | 严格早于/晚于。格式为 YYYY-MM-DDTHH:mm:ss。 |
updatedBefore / updatedAfter | timestamp | 格式相同。 |
bytesStored | 整数 | 精确匹配。 |
minBytesStored / maxBytesStored | 整数 | 闭区间边界。 |
childrenCount | 整数 | 精确匹配。 |
minChildrenCount / maxChildrenCount | 整数 | 闭区间边界。 |
includesThumbnail | 'true' | 'false' | 在可用时包含带签名的缩略图 URL。默认 'false'。 |
page | 整数 | 默认 1。 |
limit | 整数 | 1–50,默认 20。 |
sortBy | name | createdAt | updatedAt | bytesStored | childrenCount | 排序字段。 |
sortDir | ASC | DESC | 排序方向,默认 ASC。 |
{ "items": [ { "id": "a6f75b3c-f261-4b27-9a2a-9a6cc1234c53", "createdAt": "2026-06-01T10:00:00.000Z", "updatedAt": "2026-06-01T10:00:00.000Z", "name": "Building A", "type": "Site", "createdById": "8f0b9a2c-8f1b-4a10-9e1c-0b3a2d9a4b7d", "parentId": "d2a1c4b7-3e10-4f2c-9a6b-7c1d8e2f3a45", "childrenCount": 4, "bytesStored": 15728640, "thumbnailSignedUrl": null } ], "total": 1}某祖先节点下的所有站点:
GET {api_url}/v1/nodes/search?nodeTypes=Site&ancestorId=d2a1c4b7-3e10-4f2c-9a6b-7c1d8e2f3a45Authorization: Bearer {access_token}名称以 “Archive” 开头的文件夹,按名称排序:
GET {api_url}/v1/nodes/search?nodeTypes=Folder&searchNameQuery=Archive&nameMatch=contains&sortBy=name&sortDir=ASCAuthorization: Bearer {access_token}import requestsfrom urllib.parse import urlencode
API_URL = "https://<your-regional-api-url>"TOKEN = "<access_token>"ANCESTOR_ID = "<division-or-site-id>"
headers = {"Authorization": f"Bearer {TOKEN}"}
params = [ ("nodeTypes", "Site"), ("ancestorId", ANCESTOR_ID), ("sortBy", "name"), ("sortDir", "ASC"),]
response = requests.get( f"{API_URL}/v1/nodes/search?{urlencode(params)}", headers=headers,).json()
for node in response["items"]: print(node["type"], node["name"], node["id"])要在节点搜索返回的节点下创建资源,请参阅创建 Data Bundle。