dp:contextualization:cdf_entity_matching) automates the contextualization of entities, typically time series, to a configurable target view (for example, CogniteAsset, Tags, or Equipment) in Cognite Data Fusion (CDF). The pack deploys as a module for the Cognite Toolkit. A data workflow runs two functions in Cognite Functions:
- An aliases update function that writes normalized
aliaseson time series, assets, and files. - An entity matching function that runs in a submit stage and a collect stage to establish direct relationships in the data model.
dp:contextualization:cdf_entity_matching) inside the Contextualization deployment pack (dp:contextualization). You can add it on its own or alongside the other contextualization modules.Who it’s for
Target personas:- Data engineers — deploy, configure, and tune the matching pipeline.
- Solution architects — design the contextualization approach across source systems.
- You need to match time series (or another entity view) to assets automatically, without building a custom matching pipeline from scratch.
- Your project combines data from multiple sources (for example, SAP assets and OSIsoft/AVEVA PI time series), possibly in separate instance spaces, and requires relationship discovery across them.
- Source system tags are formatted differently from asset names, and you need normalized aliases so matching compares like-for-like tags.
- You need a combination of manual expert mappings, rule-based logic, and AI-powered matching in a single orchestrated workflow.
- You need incremental processing, where only new or updated entities are matched on each run.
- You want a scalable foundation proven for 10,000+ time series per batch in production environments.
- If your assets and time series are already contextualized and you only need to maintain relationships. This pack is optimized for initial and incremental matching, not purely for maintenance.
- If your project requires document or piping and instrumentation diagram (P&ID) annotation, use the P&ID Annotation deployment pack instead.
What’s included
Prerequisites
Verify all of the following before you start:- The Cognite Toolkit version 0.8 or later is installed. See Setting up.
-
A
cdf.tomlfile exists in your project root. If it’s missing, runcdf modules initand select Create toml file (required). -
The data plugin is enabled in
cdf.toml. You need it for thecdf data uploadstep after deployment: -
Authentication is configured and verified. Run
cdf auth initandcdf auth verifyusing a local.envfile. See Authentication and authorization. -
A data model with views that implement
CogniteAssetandCogniteTimeSeries(or the core data model views themselves) is deployed, and instances are already ingested. -
You have a service principal (app registration) in your IdP for the scheduled workflow to authenticate as. Have its client ID and client secret ready. These populate
IDP_CLIENT_IDandIDP_CLIENT_SECRETin your.envfile, mapped toworkflowClientIdandworkflowClientSecret. -
You have an IdP group for the processing access group, and you know its source ID, the group’s object ID in the IdP. This populates
GROUP_SOURCE_ID, mapped toentity_matching_processing_group_source_id. The workflow’s service principal must be a member of this group.
Install and deploy
You can add the Entity Matching module to an existing Cognite Toolkit project or start a new project from scratch.- Add to an existing project
- Start a new project
modules/contextualization/cdf_entity_matching/ and updates your config.<env>.yaml files. Before building, open config.dev.yaml and set at minimum:
project.- The schema and instance spaces.
- The target and entity view external IDs and search properties.
- The alias patterns.
- The credentials:
workflowClientId,workflowClientSecret, andentity_matching_processing_group_source_id.
Build deployment artifacts
build/ directory. If you need to change the project name or any variables marked <change_me>, edit config.<env>.yaml first — see Configure, build, and deploy modules.Dry-run the deployment
Deploy to CDF
Set up CI/CD (optional)
cdf.toml (see Prerequisites) before running cdf data upload.Verify the deployment
After deploying, confirm success with these checks:- The
cdf deploycommand finishes without errors and reports successful deployment of Functions, Workflows, Extraction Pipelines, RAW, the data set, the access group, and the data modeling resources. - The
cdf data uploadcommand finishes without errors, andcontextualization_manual_inputandcontextualization_rule_inputare visible in Integrate > Staging (RAW) underdb_asset_entity_matching. - In CDF, navigate to Integrate > Data Workflows and verify that the
wf_ctx_entity_matchingworkflow is listed. - Trigger the workflow with Run. The default schedule rarely fires, so start the first run manually. Confirm that the aliases update, submit, and collect tasks run in that order and finish without errors.
- Navigate to Build Solutions > Functions, open
fn_dm_context_aliases_updateandfn_dm_context_entity_matching, select View logs, and review the processed and updated counts and match scores. - Use CDF Search or Data Modeling to confirm that time series and assets have the expected
aliasesvalues. - Navigate to Integrate > Staging (RAW) and verify that
contextualization_goodandcontextualization_badare populated. - Confirm that direct relationships exist between matched entities and the target view (when
dmUpdateis enabled).
Configuration reference
Set module variables per environment inconfig.<env>.yaml before running cdf build. Required variables must be set for your project. Optional variables can keep their defaults. Where the default is — or a ${...} value read from .env, you must provide your own value before deploying.
Runtime parameters live in the extraction pipeline configs under extraction_pipelines/, and the functions read them on every run.
The settings are grouped by what they control:
- General settings (this section): project, spaces, workflow, credentials, and function input.
- Aliases update settings: the views, patterns, and parameters for
fn_dm_context_aliases_update. - Entity matching settings: the views, filters, scopes, inputs, and parameters for
fn_dm_context_entity_matching.
General variables
These variables apply to the whole module:Multiple instance spaces
Both functions read and write instances in these spaces. Each variable takes a single space or a list of spaces:- Manual mappings: the manual mapping RAW table has only
TsExternalIdandAssetExternalIdcolumns, so a manual mapping applies to every copy of that external ID. - Asset links: when an asset external ID exists in several of the spaces in
assetInstanceSpace, the space a link points to is arbitrary.
entities and assets. Use unique external IDs per space, or configure a single space, to avoid both cases.
When more than one time series space is configured, the space becomes part of the row key in the good and bad RAW tables so copies don’t overwrite each other. With a single space, the key is the external ID. If an instance’s space can’t be determined, the link is written to the first space in the list and a warning names the instance. That happens, for example, when a manual mapping names a target outside the configured filter.
Function input
The workflow passes these values in each function call’s input data. Both functions validate them before calling CDF. These are task inputs, notconfig.<env>.yaml variables.
Aliases update settings
These settings control howfn_dm_context_aliases_update derives normalized aliases from instance names. Entity matching uses those aliases when you set the search properties to aliases.
aliases and doesn’t write its own. Keep fileView enabled if you annotate files. When you change assetAliasPattern or fileAliasPattern, update entityNormalizationPatterns and fileNormalizationPatterns in File Annotation to match.Aliases update variables
Aliases update runtime parameters
Editextraction_pipelines/ctx_aliases_update.config.yaml to control which instances each run processes:
fileView section is optional. Remove it from the config to leave file metadata untouched.
Alias patterns
Aliases update uses one list of regex patterns per view to find the tag inside an instance’sname, so time series, assets, and files can follow different naming conventions. The alias written back is the pattern’s capture groups joined by -. Separators inside a captured group (_, ., :) are also rewritten to -. With the default patterns, the time series name VAL_23-KA-9101:X.Value gets the alias 23-KA-9101, which is what makes matching on aliases work across differently formatted names.
When several patterns match one name, the view’s AliasSelection setting decides what to keep: all writes one alias per matching pattern, and longest writes only the longest one. For example:
No alias extracted based on configured <view> regular expression for name: … for the first ten names, then a total. Many of these warnings usually point at the pattern, not the data. When nothing is extracted, aliases is written as null so a previous list is cleared.
By default, fileAliasPattern matches document numbers, so PH-25578-P-4110006-001.pdf yields PH-25578-P-4110006-001 and PH-25578-P-4110006. Keep fileAliasSelection: all for these patterns, since longest would drop the shorter number. Files also get their file name without its final extension as an alias, but only when a pattern matches. AliasSelection never discards that file name alias.
Follow these rules when you write your own patterns:
- Use character classes, not backslash escapes. Write
[0-9], not\d. The Cognite Toolkit substitutes variables as a regex replacement, and a backslash escape fails the build. - Accept
-as a separator between groups. Generated aliases join groups with-, and the function recognizes its own earlier output by feeding a stored alias back through the pattern. A pattern that can’t match-never recognizes its own aliases, soupdateAllleaves stale ones in place. Also accept_so aliases written by earlier runs that used underscores are still recognized.
Entity matching settings
These settings control which instancesfn_dm_context_entity_matching reads, which properties it matches on, and how it approves and writes matches.
Entity matching variables
Entity matching runtime parameters
Editextraction_pipelines/ctx_entity_matching.config.yaml to tune the matching run:
autoApprovalThreshold, clean up the relationships created by previous runs before re-running. Only matches created by this process are removed; manually created relationships are preserved.Manual mapping and rule inputs
The submit stage reads two RAW tables indb_asset_entity_matching. The upload_data/ directory contains seed rows for both tables. Replace them with your own mappings and rules before you run cdf data upload.
Manual mappings (contextualization_manual_input, uploaded from contextualization_manual_input.RawRows.csv) link a specific entity to a specific target:
contextualization_rule_input, uploaded from contextualization_rule_input.RawRows.ndjson) link entities to targets whose names share a key. Each row holds a pair of regular expressions:
VAL_23-KA-9101:X.Value and the asset 23-KA-9101 both capture 23, KA, and 9101, so they get the same key and the rule links them. Keep rules specific: a key that resolves to many targets gives one entity many links. Check the entity_rule_keys and asset_rule_keys columns in contextualization_good to see which keys produced a match.
\d are fine in the rule table, because the rows are uploaded as data. The alias patterns in config.<env>.yaml are different: those must use character classes. See Alias patterns.Search properties
targetViewSearchProperty and entityViewSearchProperty name the property whose value is passed to the matching model. The default is name. Set them to aliases when source system tags differ from display names, so matching compares the normalized tags that aliases update wrote.
List-valued properties are reduced differently on each side:
- Entities: only the longest usable entry is used, so one time series isn’t submitted as several match candidates.
["DB-9101", "23-DB-9101"]becomes23-DB-9101. Values of equal length keep the first. - Targets: every usable entry is kept, so alternate spellings on an asset remain matchable.
name. Empty entries in an otherwise populated list are dropped, so ["pi:1", ""] matches on pi:1 only.
Filtering instances
viewFilterProperty is the view property used to filter target and entity instances, together with targetViewFilterValues and entityViewFilterValues. The filter applies only when the corresponding values list is non-empty. Only entity matching uses it; aliases update doesn’t filter.
The default tags matches core data model views such as CogniteAsset. If your data model uses a different property, for example labels in the Capital Facilities Information Handover Specification (CFIHOS) oil and gas domain model, set it accordingly:
Scoped matching
primaryScopeProperty and secondaryScopeProperty are optional. Leave both empty (the default) to run one unscoped predict job against every target. Both property names must exist on the entity view and the target view.
When primaryScopeProperty is set, the submit stage groups entities by their primary and secondary values and starts one predict job per group that has targets. Rule-based matching runs on the same groups. Manual mappings stay global, and the matching model fitted for the first job is reused by the others.
site/unit model, use the test resources in the module’s testing/ directory. Don’t leave the copied files in data_modeling/ or transformations/ unless you intend to deploy them.
Architecture
The pack deploys two functions into a dedicated function space, orchestrated by thewf_ctx_entity_matching workflow and a scheduled trigger. Each function reads its runtime parameters from an extraction pipeline config. RAW holds the manual and rule inputs, the good and bad match results, and the incremental state and job queue. CDF files in ds_entity_matching hold the target cache and staged matches.
Data flow
The workflow runs aliases update first to normalize tags, then the submit and collect stages of the matching function. Manual mappings and rule-based matches always take priority over model matches for the same entity.Aliases update
fn_dm_context_aliases_update reads ep_ctx_aliases_update, pages through instances with only name and aliases, derives aliases with the view’s alias patterns, and writes each page back before reading the next. By default, only instances missing aliases are fetched. A failed read or write fails the function call, so matching doesn’t run on stale aliases.
Submit stage
The submit stage offn_dm_context_entity_matching:
- Reads the
ep_ctx_entity_matchingconfig and the manual and rule mapping tables. - Reads the target instances through the data modeling sync endpoint and caches them in a CDF file,
em_target_cache_<key>.json. Later runs merge only the sync changes into the same file instead of paging the whole view again. - Reads the entities not yet matched (or all entities when
runAllistrue), one page at a time with only the properties matching uses. - Applies manual mappings, which overwrite any existing mapping, then rule-based matching with the configured regex patterns.
- Starts the entity matching predict job for the remaining candidates without waiting for it, one job per scope when scoped matching is configured.
- Stages the manual and rule matches in a CDF file,
em_staged_matches_<jobId>.json, and adds the job to the queue incontextualization_state_store.
Collect stage
The collect stage polls queued predict jobs in parallel, with up to 10 workers, every 30 seconds, for at most 7 minutes per run. When a job finishes and time remains, the next queued job is started. Finished results are merged with the staged matches, split byautoApprovalThreshold into the good and bad tables, written to the data model when dmUpdate is true, and removed from the queue. Jobs still running are picked up by the next collect run.
The function stores a digest of each cache and staged-match file in the RAW state row and checks file contents against that digest. A principal that can overwrite files, but not that RAW table, can’t inject content.
Incremental processing and state
runAll: false (the shipped default), only entities updated since the last run are processed. Set runAll: true or clear the state table to reprocess everything.
Resilience
Every task fails its function call on error, so the workflow stops instead of matching on stale aliases or partial input. A failed read of the time series, the manual or rule mappings, or a staged-match file fails the run. A job whose staged matches can’t be read stays queued for the next collect run. Aliases update and collect retry up to 3 times. Submit isn’t retried, because a retry after a partial run could queue a second predict job for the same entities; the next workflow run picks those entities up again.Access
Thegp_entity_matching_processing group grants the workflow’s service principal these access control lists (ACLs):
rawAclread and write on thedb_asset_entity_matchingdatabase.dataModelsAclread anddataModelInstancesAclread and write.filesAclread and write scoped to theds_entity_matchingdata set, for the target cache and staged-match files, anddatasetsAclread to resolve the data set.entitymatchingAcl,functionsAcl,sessionsAcl,extractionConfigsAcl, andextractionRunsAclfor running the functions and the matching jobs.
Troubleshooting
Problems are grouped by where they show up. Check the function logs in Build Solutions > Functions first: both functions log the configuration they read and the counts they processed.Deployment and access problems
cdf deploy fails with Insufficient permissions
cdf deploy fails with Insufficient permissions
cdf data upload fails with data plugin not enabled
cdf data upload fails with data plugin not enabled
[plugins] data = true is missing from cdf.toml.Resolution: Add data = true under [plugins] in cdf.toml and retry the upload command.The workflow fails with an access error
The workflow fails with an access error
workflowClientId, workflowClientSecret, and entity_matching_processing_group_source_id in config.<env>.yaml point to the correct IdP application and group source ID. See Access management.Submit fails on the target cache or with a data set error
Submit fails on the target cache or with a data set error
filesAcl on ds_entity_matching, or dataSetExternalId names a data set that doesn’t exist.Resolution: Confirm that the data set exists and that the processing group has filesAcl read and write on it and datasetsAcl read. Alternatively, remove dataSetExternalId from the extraction pipeline config.The workflow never runs on its own
The workflow never runs on its own
workflowSchedule only fires on 29 February.Resolution: Set workflowSchedule to a cron expression, for example '0 2 * * *', and redeploy.Alias problems
cdf build fails on an alias pattern
cdf build fails on an alias pattern
\d.Resolution: Use character classes such as [0-9] instead. See Alias patterns.Many No alias extracted warnings in the logs
Many No alias extracted warnings in the logs
timeseriesAliasPattern, assetAliasPattern, or fileAliasPattern to match your names.updateAll leaves stale aliases in place
updateAll leaves stale aliases in place
- as a separator, so the function can’t recognize its own earlier aliases.Resolution: Add - (and _) to the separators the pattern accepts.Matching problems
No matches created after the workflow run
No matches created after the workflow run
- Predict jobs are still queued. Run the workflow again. The collect stage picks up jobs that were still running when the previous run ended.
- Input tables are missing. Verify that
cdf data uploadpopulatedcontextualization_manual_inputandcontextualization_rule_input. - Search properties don’t exist on the views. Confirm that
targetViewSearchPropertyandentityViewSearchPropertymatch real property names. See Search properties. - The configuration doesn’t match your data. Check that filter values, scope properties, views, spaces, and versions in the extraction pipeline config match your data in CDF. Clear
targetViewFilterValuesandentityViewFilterValuesto remove the filter.
Low match rate despite correct configuration
Low match rate despite correct configuration
name instead of aliases.Resolution: Check the fn_dm_context_aliases_update logs, and set the search properties to aliases if your tags differ from display names.Property does not exist in view (400 error)
Property does not exist in view (400 error)
viewFilterProperty names a property the views don’t have. The error appears only once targetViewFilterValues or entityViewFilterValues is non-empty, so a wrong name can go unnoticed until you start filtering.Resolution: Set viewFilterProperty to the property your views use, for example tags for core data model views or labels for CFIHOS. See Filtering instances.Warning that external IDs exist in more than one instance space
Warning that external IDs exist in more than one instance space
assets, confirm that links point to the expected space. Manual mappings apply to every copy of an external ID. See Multiple instance spaces.Matches are written to RAW but not to the data model
Matches are written to RAW but not to the data model
dmUpdate is set to false.Resolution: Set dmUpdate: true in extraction_pipelines/ctx_entity_matching.config.yaml and re-run.Duplicate or stale relationships after a threshold change
Duplicate or stale relationships after a threshold change
autoApprovalThreshold changed without cleaning up prior matches.Resolution: Remove relationships created by previous runs, or set removeOldLinks: true, before re-running. Manually created relationships are preserved.The workflow processes all entities on every run
The workflow processes all entities on every run
runAll is true, or the state table was cleared.Resolution: Set runAll: false for incremental runs. Confirm that contextualization_state_store exists and is being updated.Further reading
- Deployment packs — the other packs in the library, including the Contextualization pack.
- Foundation Demo — installs this module preconfigured for the Quickstart data model.
- P&ID Annotation — contextualize documents and engineering diagrams.
- Authentication and authorization — set up the credentials the workflow uses.