hierarchy_match

Use the `hierarchy_match()` function to determine whether an asset belongs to a specified node in the organizational (org) asset hierarchy. You can match against the hierarchy path (the ordered list of container names from the org root down to a specific node), a specific hierarchy node ID (`id_path`), or both. Calling the function with no arguments matches every asset (equivalent to `*`).

The function is only available when the org asset hierarchy is enabled for your tenant, and it operates on the asset hierarchy fields `xdm.asset.hierarchy.path` (the chain of container names joined by `/`) and `xdm.asset.hierarchy.id_path` (the ID of the deepest node in that path). It is intended for asset datasets (for example, `asset_inventory`) and is not supported inside correlation rules.

## Syntax

```sql
hierarchy_match(<path_segments>, <id_path>)
```

## Parameters

| Name | Type | Required | Description |
| --------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `path_segments` | array | No | An ordered list of the container names from the org root down to the target node (for example, `["Org", "ou1", "ou2"]`). Segments are joined with `/` and matched as a path prefix, so the node and all of its descendants match. The path contains only container levels (organization, OUs, management groups, folders) — not the leaf account/project/subscription. If omitted (or an empty array), no path restriction is applied and all paths match. As a shorthand, passing a single string value is treated as the `id_path` argument. |
| `id_path` | string | No | The resource ID of a specific hierarchy node — the ID of the deepest container in the path (for example, an OU ID, management-group ID, or folder ID). Use it to unambiguously target a node even when names are duplicated. When provided, it must match the asset's `id_path`. If omitted, no ID restriction is applied. |

## Returns

**Type**: boolean

**Description**: The `hierarchy_match()` function returns `true` if the asset belongs to the specified org hierarchy node (satisfying both the path and ID conditions that were supplied), and `false` otherwise.

## Usage notes

* **Path vs. id\_path**: The `path` and `id_path` describe the same container node from two angles: `path` is the chain of container names, and `id_path` is the ID of the deepest node in that chain. Neither includes the account/project/subscription.
* **Disambiguating duplicate names**: Use `id_path` when container names are ambiguous. For example, if two different OUs are both named `Production`, matching on the path name alone is ambiguous — supplying the OU's `id_path` pins the match to exactly the OU you mean.
* **Combinable, optional parameters**: Both parameters are optional and can be combined:
 * `hierarchy_match()` — matches all assets (no restriction).
 * `hierarchy_match(arraycreate("Org", "ou1"))` — path-only match (the node and all its descendants).
 * `hierarchy_match(null, "ou-a1b2-prod01")` — ID-only match (match the node with this exact ID, on any path).
 * `hierarchy_match("ou-a1b2-prod01")` — shorthand for an ID-only match.
 * `hierarchy_match(arraycreate("Org", "ou1"), "ou-a1b2-prod01")` — matches only when both the path prefix and the ID condition are satisfied.
* **Prefix, case-sensitive, literal matching**: The path match is a prefix match: it matches the exact path as well as any child path beneath it. It is case-sensitive and matches literal characters (wildcard characters such as `%` and `_` in path segments are treated literally, not as wildcards).
* **Ambiguous scalar + ID is rejected**: Passing a single scalar/string value together with an explicit `id_path` is ambiguous and is rejected with a validation error. Use an array for the first argument whenever you also supply an ID.
* **Negation**: To negate a match (find assets that do not belong to a node), compare the result to `false` (for example, `hierarchy_match(...) = false`) or use `!= true`.
* **Typical use**: This function is typically used within the `filter` stage to scope results to an org hierarchy node, or within the `alter` stage to tag records with their hierarchy membership.
* **Cloud hierarchy structure**: The org hierarchy mirrors the native resource-organization model of each cloud provider. In every case the hierarchy stops at the container level — the leaf account, project, or subscription is not part of the path or the `id_path`. The `path_segments` argument is the ordered list of the display names of the container levels (not their IDs, and not the leaf), and `id_path` is the ID of the deepest container node in the path. Matching on `path_segments` alone selects the target container node and all of its descendants, which is useful for scoping to an entire OU, management group, or folder subtree.

 | Cloud Provider | Container Levels (org root → node) | Leaf (not part of hierarchy path/id\_path) | Example Path | Example `id_path` (ID of deepest node) |
 | -------------- | --------------------------------------------- | ------------------------------------------ | ---------------------------- | -------------------------------------- |
 | AWS | Organization → Organizational Unit (OU) | Account | `Acme Corp/Production` | OU ID: `ou-a1b2-prod01` |
 | Azure | Management Group → (nested Management Groups) | Subscription | `Tenant Root Group/Platform` | Management Group ID: `mg-platform` |
 | GCP | Organization → Folder(s) | Project | `acme.com/Production` | Folder ID: `folders/574839201122` |

## Examples

### Example 1: Scope to an AWS organizational unit

**Goal**: Return only the assets that belong to the AWS `Production` OU under the `Acme Corp` organization, including every account nested beneath that OU.

**XQL code**:

```sql
config timeframe = 1d
| dataset = asset_inventory
| filter hierarchy_match(arraycreate("Acme Corp", "Production"))
| fields asset_id, asset_name, cloud_provider, xdm.asset.hierarchy.path
| limit 3
```

**Explanation**: You apply a path-only match in a `filter` stage. The path contains only the container levels (organization and OU), so matching on `Acme Corp/Production` returns every asset in any account under the `Production` OU (and its sub-OUs), because the match is a prefix match.

**Output**:

| ASSET\_ID | ASSET\_NAME | CLOUD\_PROVIDER | XDM.ASSET.HIERARCHY.PATH |
| ---------- | ---------------- | --------------- | ---------------------------- |
| i-0a1b2c3d | payments-api-01 | AWS | Acme Corp/Production |
| i-0e4f5g6h | orders-worker-02 | AWS | Acme Corp/Production |
| i-0i7j8k9l | billing-db-01 | AWS | Acme Corp/Production/Billing |

### Example 2: Disambiguate an OU by ID

**Goal**: Two OUs are both named `Production` under different parents. Return only the assets under the specific `Production` OU whose ID is `ou-a1b2-prod01`.

**XQL code**:

```sql
config timeframe = 1d
| dataset = asset_inventory
| filter hierarchy_match(arraycreate("Acme Corp", "Production"), "ou-a1b2-prod01") = true
| fields asset_id, asset_name, xdm.asset.hierarchy.path, xdm.asset.hierarchy.id_path
| limit 3
```

**Explanation**: Because the OU name alone is ambiguous, you combine the path prefix (`Acme Corp/Production`) with the OU's ID as `id_path`. An asset is returned only when its path starts with `Acme Corp/Production` and its `id_path` equals `ou-a1b2-prod01`, so only the intended OU is matched.

**Output**:

| ASSET\_ID | ASSET\_NAME | XDM.ASSET.HIERARCHY.PATH | XDM.ASSET.HIERARCHY.ID\_PATH |
| ---------- | ----------------- | ------------------------ | ---------------------------- |
| i-0a1b2c3d | payments-api-01 | Acme Corp/Production | ou-a1b2-prod01 |
| i-0m1n2o3p | payments-cache-01 | Acme Corp/Production | ou-a1b2-prod01 |
| i-0q4r5s6t | payments-lb-01 | Acme Corp/Production | ou-a1b2-prod01 |

### Example 3: Scope to an Azure management group

**Goal**: Tag assets that live under the Azure `Platform` management group (any subscription beneath it), starting from the `Tenant Root Group`.

**XQL code**:

```sql
config timeframe = 1d
| dataset = asset_inventory
| alter in_platform_mg = hierarchy_match(arraycreate("Tenant Root Group", "Platform"))
| fields asset_id, cloud_provider, xdm.asset.hierarchy.path, in_platform_mg
| limit 3
```

**Explanation**: You use a path-only match in an `alter` stage. In Azure the path contains the management-group chain (Management Group → nested Management Groups) and stops above the subscription, so matching on `Tenant Root Group/Platform` returns `true` for every asset in any subscription nested under the `Platform` management group, and `false` otherwise.

**Output**:

| ASSET\_ID | CLOUD\_PROVIDER | XDM.ASSET.HIERARCHY.PATH | IN\_PLATFORM\_MG |
| ----------- | --------------- | ------------------------------- | ---------------- |
| vm-web-01 | AZURE | Tenant Root Group/Platform | true |
| vm-api-02 | AZURE | Tenant Root Group/Platform/Prod | true |
| vm-sales-03 | AZURE | Tenant Root Group/Business | false |

### Example 4: Pin to a specific Azure management group by ID

**Goal**: Return only the assets under the `Platform` management group whose ID is `mg-platform`.

**XQL code**:

```sql
config timeframe = 1d
| dataset = asset_inventory
| filter hierarchy_match(arraycreate("Tenant Root Group", "Platform"), "mg-platform") = true
| fields asset_id, asset_name, xdm.asset.hierarchy.path, xdm.asset.hierarchy.id_path
| limit 3
```

**Explanation**: You combine the management-group path prefix (`Tenant Root Group/Platform`) with the management group's ID as `id_path`. Only assets whose path starts with `Tenant Root Group/Platform` and whose `id_path` equals `mg-platform` are returned — the ID pins the match to the exact management group.

**Output**:

| ASSET\_ID | ASSET\_NAME | XDM.ASSET.HIERARCHY.PATH | XDM.ASSET.HIERARCHY.ID\_PATH |
| ---------- | ---------------- | -------------------------- | ---------------------------- |
| vm-web-01 | payments-web-01 | Tenant Root Group/Platform | mg-platform |
| vm-web-02 | payments-web-02 | Tenant Root Group/Platform | mg-platform |
| st-blob-01 | payments-storage | Tenant Root Group/Platform | mg-platform |

### Example 5: Scope to a GCP folder

**Goal**: Return only the assets that belong to the GCP `Production` folder under the `acme.com` organization, including every project nested inside that folder.

**XQL code**:

```sql
config timeframe = 1d
| dataset = asset_inventory
| filter hierarchy_match(arraycreate("acme.com", "Production"))
| fields asset_id, asset_name, cloud_provider, xdm.asset.hierarchy.path
| limit 3
```

**Explanation**: In GCP the path contains the organization and its folders and stops above the project. A path-only match on `acme.com/Production` returns every asset in any project inside the `Production` folder (and any sub-folders), because the match is a prefix match.

**Output**:

| ASSET\_ID | ASSET\_NAME | CLOUD\_PROVIDER | XDM.ASSET.HIERARCHY.PATH |
| ------------- | ----------------- | --------------- | --------------------------- |
| gce-inst-01 | payments-prod-vm | GCP | acme.com/Production |
| gce-inst-02 | orders-prod-vm | GCP | acme.com/Production |
| gcs-bucket-01 | billing-prod-data | GCP | acme.com/Production/Billing |

### Example 6: Pin to a specific GCP folder by ID

**Goal**: Return only the assets under the `Production` folder whose ID is `folders/574839201122`.

**XQL code**:

```sql
config timeframe = 1d
| dataset = asset_inventory
| filter hierarchy_match(arraycreate("acme.com", "Production"), "folders/574839201122") = true
| fields asset_id, asset_name, xdm.asset.hierarchy.path, xdm.asset.hierarchy.id_path
| limit 3
```

**Explanation**: You combine the folder path prefix (`acme.com/Production`) with the folder's ID as `id_path`. Only assets whose path starts with `acme.com/Production` and whose `id_path` equals `folders/574839201122` are returned, pinning the match to the exact folder even if another folder shares the same name.

**Output**:

| ASSET\_ID | ASSET\_NAME | XDM.ASSET.HIERARCHY.PATH | XDM.ASSET.HIERARCHY.ID\_PATH |
| ------------- | -------------------- | ------------------------ | ---------------------------- |
| gce-inst-01 | payments-prod-vm | acme.com/Production | folders/574839201122 |
| gce-disk-01 | payments-prod-disk | acme.com/Production | folders/574839201122 |
| gcs-bucket-02 | payments-prod-bucket | acme.com/Production | folders/574839201122 |

### Example 7: Exclude a hierarchy node (negation)

**Goal**: Return all assets except those in the `Acme Corp/Sandbox` OU.

**XQL code**:

```sql
config timeframe = 1d
| dataset = asset_inventory
| filter hierarchy_match(arraycreate("Acme Corp", "Sandbox")) = false
| fields asset_id, cloud_provider, xdm.asset.hierarchy.path
| limit 3
```

**Explanation**: Comparing the result of `hierarchy_match()` to `false` inverts the match, so every asset that does not live under the `Acme Corp/Sandbox` container is returned. This is useful for excluding non-production or sandbox scopes from a query.

**Output**:

| ASSET\_ID | CLOUD\_PROVIDER | XDM.ASSET.HIERARCHY.PATH |
| ----------- | --------------- | -------------------------- |
| i-0a1b2c3d | AWS | Acme Corp/Production |
| vm-web-01 | AZURE | Tenant Root Group/Platform |
| gce-inst-01 | GCP | acme.com/Production |

## Related articles

* **Stages**: [`filter`](broken-reference), [`alter`](broken-reference), [`fields`](broken-reference)
* **Functions**: [`arraycreate()`](broken-reference), [`wildcard_match`](broken-reference), [`coalesce()`](broken-reference)
* **Datasets**: [`asset_inventory`](https://docs-cortex.paloaltonetworks.com/r/Cortex-XQL-Schema-Reference-Guide/Introduction)