Job Offer Matching (JOM)¶
API version
Main API: 4.50.36
JOM compares a user with an opportunity in both directions. The direction changes the entity whose score set is persisted, but candidate eligibility, rules and scores use the same business definitions.
entity and tenant context
-> active candidates and hard filters
-> JOM rules and pool ranking
-> bounded final pool
-> skill score + motivation score (concurrent)
-> dislike penalties
-> persistence and optional publication
1. Context and candidate source¶
The processing service resolves the tenant configuration, AI configuration and
active backend. It loads one standardized user or opportunity and rejects an
unknown entity. MongoDB reads tenant collections; PostgreSQL reads the live user
and opportunity projections through PostgresMatchingRepository.
Only active targets enter the candidate source. A missing pool is meaningful: existing scores for the processed entity are deleted so stale recommendations are not retained.
2. Hard filters¶
Hard filters remove candidates before any rule or score is calculated. The
configured set is independent for hard_filters.jom.user and
hard_filters.jom.opportunity.
| Filter | Implemented behavior |
|---|---|
| Dislike | When dislike handling and delete_from_pool are active, an opportunity explicitly disliked by the user is excluded in either direction. |
job_classification |
If the source has a known classification and the configuration defines allowed target levels, the target classification must be in that list. |
technical_classification |
Uses the same directional compatibility mapping as job_classification, comparing technicalClassification from the configured Smart Editor fields. Supported by MongoDB and PostgreSQL. |
access_group |
When the source has access groups, the candidate must share at least one. An empty source group adds no MongoDB filter. PostgreSQL opportunities deliberately ignore it because their relational projection has no opportunity access-group contract. |
contract_type |
When the source contract has a configured compatibility list, the candidate contract must be in it. |
exclude_externals |
On the opportunity-to-users side, removes users explicitly marked external. |
location |
A candidate with no location remains eligible; otherwise its location must equal the source location when the source has one. |
MongoDB compiles these rules into one $and query. PostgreSQL compiles the
supported equivalents into SQL predicates while preserving tenant and active
status criteria.
Technical and job classifications are independent. La Poste JOM can compare
user and offer technical classifications while JPM/Galaxy continues to compare
user and job classifications. Mappings remain explicit and direction-specific;
the engine does not generate a uniform "+2" rule or invert the opposite mapping.
A missing, empty or "-1" source classification, or an absent/empty compatibility
list, adds no restriction. When a nonempty list applies, a target without an
allowed classification is excluded. Unknown source labels have no restriction
unless explicitly mapped. There is no fallback to attached-job classification.
3. JOM rules and pool score¶
Rules do not normally remove a candidate. They add evidence fields and points
to poolScore, which ranks the hard-filtered candidates. The rule set is
direction-specific under rules.user and rules.opportunity.
| Rule | Result and contribution |
|---|---|
generic_field_comparisons |
Compares each configured field, case-insensitively for strings. A non-empty equality adds one point; an optional value allow-list further restricts success. |
job_title_in_love_list |
Checks whether the opportunity title equals the title of a user bookmark or interest. Matching the configured success_value adds one point. |
love_list_shares_department |
Finds bookmarked/interested opportunities and compares their deepest available department with the candidate opportunity. Matching the configured boolean adds one point. |
compare_departments |
Adds one point for every department level whose key and value match. |
authorizations |
Keeps only user authorizations whose obtained/expiration dates contain the current UTC time, then adds the number also required by the opportunity. |
ways_of_work |
Remote is compatible with remote/hybrid; hybrid with hybrid/remote; onsite/hybrid combinations require equal locations. Matching success_value adds one point. |
number_of_matching_skills |
Counts opportunity skills matching a user skill by ID or fuzzy title above the configured threshold. Skill types with zero configured weight are ignored. Meeting success_value adds one point; the count is retained as nrMatchingSkills. |
primary_skills |
Adds one point when at least one opportunity primary skill title exists in the user's skills. |
Unknown configured rule names fail explicitly. If no matching-skill rule is
configured, nrMatchingSkills is recorded as -1 to preserve sorting shape.
4. Pool ordering and limits¶
User-side candidates are sorted by poolScore, then
nrMatchingSkills, then newest opportunity timestamp. Opportunity-side
candidates are sorted by poolScore and nrMatchingSkills. Each side is cut
to its configured maximum.
On the user side, the canonical
exclude_opportunity_with_zero_valid_rules_user=false default keeps candidates
whose rules produce a zero poolScore, so they can still reach skill and
motivation scoring. Setting it explicitly to true prevents such a candidate
from occupying the normal pool. Configured additional quotas can add
business-priority, interest-section or career-plan opportunities even when the
normal pool is full. The code can compute a volunteering marker, but the final
pool selector currently consumes only business priority, interest section and
extra information quotas.
The rule-ranked pool is written to the Datalake processing trace before scoring.
5. Skill score¶
JOM and JPM share the same directional skill-coverage algorithm. For JOM, the opportunity skills are the required skills and the user skills are the acquired skills, regardless of processing direction.
For every required skill i:
- cosine similarities to all acquired skills are obtained from the active MongoDB/PostgreSQL vector repository;
- a shared non-empty skill ID makes that required skill pass the semantic
threshold, otherwise its best cosine must be at least
skill_scores.threshold + embedding.threshold_delta; - the level factor is
1when the required level is missing (None,0or999),0when the acquired level is missing (Noneor999), otherwisemin(acquired_level / required_level, 1); the direction-specificmissing_target_skill_level_as_acquiredflag can treat a missing acquired level as1; - the factor is multiplied by the configured required-skill type weight.
The result is:
Skill groups with a weight less than or equal to zero are excluded from both
the numerator and denominator. Unknown types use weight 0.5. When
score_booster is enabled, the weighted average x is transformed to
sqrt(1 - (1 - x)^2).
6. Motivation score¶
Skill motivation and social motivation are independently configurable and are calculated concurrently with the main skill score.
Skill motivation¶
Inferred skills are excluded. For every semantically matching user skill, its
declared motivation value is summed; the sum is divided by the number of
opportunity skills. Candidates are ranked by this value, using timestamp as a
tie-breaker.
Social motivation¶
The opportunity embedding is compared with the user's interested and
bookmarked opportunity embeddings. The implemented raw value uses the maximum
bookmark similarity or the maximum interest similarity multiplied by 1.2
and capped at 1; compatible ways of working add 0.2, with a final cap of
1. The current implementation uses a maximum only when the corresponding
similarity list contains more than one item; a zero or one-item list contributes
zero for that source. Candidates are then ranked by this raw value.
Rank aggregation¶
When both components are active for a pool of size N, the unnormalized value
is 2N - (social_rank + skill_rank). With one component it is
N - component_rank. Min-max normalization maps the result to the pool range
and caps ordinary results at 0.99; a zero range produces 0. On the user
side, an explicitly bookmarked opportunity or an opportunity selected through
the interest-section additional pool is forced to 1.
7. Dislike adjustment¶
Direct dislikes are normally already absent because the hard filter removes
them. If delete_from_pool=false, their skill and motivation scores are
multiplied by the configured direct-dislike factors instead. Any candidate
whose opportunity embedding is similar to a disliked opportunity above
dislikes.<side>.threshold + threshold_delta receives the configured
similar factors.
8. Final and overall scores¶
Each retained pair stores skillScore, motivationScore, poolScore,
nrMatchingSkills, additional-pool flags and a timezone-aware scoreDate.
The external overall score is calculated as:
overallScore = skillScore * overall_weight_scores.skill_score
+ motivationScore * overall_weight_scores.motivation_score
The canonical template uses 0.8 for skills and 0.2 for motivation. Public
score responses round skill, motivation and overall values to three decimals.
9. Persistence and publication¶
MongoDB stores user-side and opportunity-side score documents in their
configured JOM collections (with separate PwC names) and can publish formatted
updates through RabbitMQ. PostgreSQL stores the two directions in
aihub_user_opportunity_matching and aihub_opportunity_user_matching.
Upserts are deduplicated by entity pair, and scores no longer present in the new
pool are deleted for the processed entity.
See Matching endpoints for ways to execute, inspect and export this algorithm.
The generated main HTTP reference is the authoritative source for parameters, schemas, responses and examples.