← All projects

Cross-supplier hotel matching

A service that recognises when different suppliers are selling the same hotel, so each hotel appears once and nothing goes on sale before it has been checked.

10,428

Saudi hotel listings checked

From the Juniper, TripMaker and IRIX production feeds

2.4%

needed a person to decide

251 listings; the rest were settled automatically

10

signals compared for every pair

Name, distance, city, phone, star rating, brand and more

The problem

Hala Saudi buys hotel rooms from several suppliers. Each supplier sends its own list of hotels, with its own spelling of the name, its own address format and its own map point. The same hotel can arrive three times, written three different ways.

If nobody matches them, an agent searching for a hotel sees duplicates, prices from different suppliers cannot be compared, and a hotel can go on sale before anyone has checked it. Matching by name alone is not safe either: two different hotels can share a name, and one hotel can go by several names.

What I did

  • Built one matching service that replaced three separate copies of the matching logic.
  • Designed the scoring: every possible pair is scored from 0 to 100 using ten signals, such as name similarity, distance between map points, city, phone number, star rating and brand.
  • Added hard rules that block a match whatever the score: a different country or city, too much distance, or conflicting phone numbers or brands.
  • Built a review queue for uncertain cases, with a claim step, two-person approval and hotel photographs side by side, so a reviewer can tell two buildings apart.
  • Made unsettled hotels wait outside the catalogue until a reviewer decides, instead of going on sale.
  • Stored the rules version on every decision, so any past result can be explained later.
  • Built the review screens in the Admin Hub.

How a listing is matched

Each step is in plain words. Open “Technical detail” for the engineering version.

  1. Find possible matches

    For each new supplier listing, look up hotels already in the catalogue that could be the same one: similar names close by, or the same supplier code.

    Technical detail

    Candidate retrieval in PostgreSQL using pg_trgm trigram similarity on the hotel name together with geographic distance. A very close location can outweigh a city mismatch at this stage.

  2. Score each candidate

    Compare ten signals and add up points to a score out of 100. Missing information earns no points but costs none either, because each supplier fills in different fields.

    Technical detail

    A weighted sum of ten signals. The weights are checked at start-up to total exactly 100, so a score always reads as a percentage. Thresholds are configured per supplier.

  3. Apply the hard rules

    Some differences rule a match out completely: a different country or city, too much distance, or a different phone number or brand. A reviewer cannot override them.

    Technical detail

    Vetoes run after scoring and fire only on a real contradiction, never on missing data, so a supplier with sparse records is not locked out.

  4. Decide

    A high score links the listing to the existing hotel automatically. A middle score goes to a person. A low score becomes a new hotel.

    Technical detail

    Separate link and review thresholds per supplier, plus an ambiguity check when two candidates score too close to call.

  5. Human review

    A reviewer claims the task, compares the two hotels with their photos and proposes a decision. A second person approves it before anything changes.

    Technical detail

    Claim plus two-step approval. Every decision is stored with the policy version that produced it, so it can be replayed against the same rules.

Results

  • Of 10,428 Saudi hotel listings from the Juniper, TripMaker and IRIX production feeds, 251 (2.4%) needed a person to decide. The service settled the rest on its own.
  • Hotels with an open question no longer go on sale. They wait until a reviewer decides.
  • Every match decision can be traced back to the exact rules that made it.

Timeline

  1. Jun 2026First version: mapping supplier hotels to one catalogue with fuzzy name matching.
  2. Aug 2026One matching service with a review queue, two-person approval, photographs and hard rules.
  3. Sep 2026Unsettled hotels held out of the catalogue; matching rules set per supplier.

What I learned

Name similarity on its own is not enough. Early name-only matching joined hotels that were not the same, which is why the service now requires a measured distance before it links two hotels.

A clear “I don’t know” beats a wrong answer. Sending a small share of cases to a person keeps the automatic decisions trustworthy.

Words on this page

Supplier
A company that sells hotel rooms wholesale to travel businesses, such as Juniper or TripMaker.
Listing
One supplier's record of a hotel. The same hotel can have one listing per supplier.
Catalogue
Hala Saudi's own list of hotels, where each hotel appears once.
Trigram similarity
A way to compare two names by the three-letter chunks they share, so small spelling differences still match.
Veto
A rule that blocks a match outright, whatever the score.

Built with

NestJSPostgreSQLpg_trgmPrismaNext.jsTanStack Query