Skip to content

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:

  1. cosine similarities to all acquired skills are obtained from the active MongoDB/PostgreSQL vector repository;
  2. 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;
  3. the level factor is 1 when the required level is missing (None, 0 or 999), 0 when the acquired level is missing (None or 999), otherwise min(acquired_level / required_level, 1); the direction-specific missing_target_skill_level_as_acquired flag can treat a missing acquired level as 1;
  4. the factor is multiplied by the configured required-skill type weight.

The result is:

skillScore = sum(level_factor_i * type_weight_i)
             / sum(type_weight_i for every required skill)

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.