From bbe5a6660d02e3581f53ea015d2922f9e8f14a16 Mon Sep 17 00:00:00 2001 From: Jonathan Payne Date: Mon, 26 Oct 2026 10:58:47 -0400 Subject: [PATCH 1/5] OpenConceptLab/ocl_issues#2817 | Write the Matching Algorithms page Replaces the Mapper's Matching Algorithms stub with the full page: what OCL Search, OCL Semantic, Bridge terminology search, ScispaCy LOINC search and a custom algorithm each do and when to pick them; which combinations are allowed; how candidates from several algorithms are merged and given one unified score by the reranker; how the Recommended, Available and Low Ranked thresholds group candidates and drive AutoMatch; and where the OCL AI Assistant fits. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GrxkQb6LXc868Qyp4BfEuZ --- docs/source/oclmap/matching-algorithms.md | 124 ++++++++++++++++++++-- 1 file changed, 114 insertions(+), 10 deletions(-) diff --git a/docs/source/oclmap/matching-algorithms.md b/docs/source/oclmap/matching-algorithms.md index 47ab254..17440b5 100644 --- a/docs/source/oclmap/matching-algorithms.md +++ b/docs/source/oclmap/matching-algorithms.md @@ -1,21 +1,125 @@ # Matching Algorithms -*This page is a stub. It introduces the matching algorithms in the OCL Mapper; a full guide is on the way.* +A matching algorithm finds candidate concepts in your target repository for each row of your input file. You choose one or more in the project configuration, under **Matching Algorithm**. Which algorithms you can select depends on your target repository, your account and how the Mapper you use is set up. -A matching algorithm finds candidate concepts in your target repository for each row of your input file. You choose one or more in the project configuration, under **Matching Algorithm**. Which algorithms you can select depends on your target repository and your account. +For each row, the Mapper: + +1. **Retrieves candidates.** Each selected algorithm searches for concepts that match the row. +2. **Merges them.** A concept found by more than one algorithm becomes one candidate. +3. **Scores them.** Every candidate gets a unified score from 0 to 100, whichever algorithm found it. +4. **Groups them.** Your score thresholds sort the candidates into Recommended, Available and Low Ranked. AutoMatch proposes a row's best candidate as its match when that candidate is Recommended. +5. **Recommends a match, if you ask.** The OCL AI Assistant reviews the candidates and recommends one, with its reasons. ## The algorithms -- **OCL Search Algorithm** — Token and keyword search using Elasticsearch. Works best when your input uses the same wording as the target terminology. -- **OCL Semantic Algorithm** — Vector-based search that matches on meaning, not just keywords, so it can find a concept worded differently from your input. Available when the target repository has semantic search enabled. -- **Bridge terminology search** — Searches the CIEL interface terminology and follows its mappings into your target repository, finding candidates the direct search can miss. Available for compatible target repositories. -- **ScispaCy LOINC search** — Uses scispaCy, a biomedical language-processing library, to match laboratory terms to LOINC. Returns LOINC codes only. -- **Custom Match Algorithm** — Calls a matching service you run, at an API URL you provide. +- **OCL Search Algorithm**: keyword search, plus codes and mappings. +- **OCL Semantic Algorithm**: search by meaning. +- **Bridge terminology search**: searches CIEL and follows its mappings into your target repository. +- **ScispaCy LOINC search**: suggests LOINC codes for laboratory test names. +- **Custom Match Algorithm**: calls a matching service you run. + +### OCL Search Algorithm + +OCL Search runs a keyword search of your target repository in Elasticsearch. It uses the input columns you assign in **Field Configuration**: + +- **Name** and **Synonyms**: keyword search of each concept's names and synonyms that tolerates small spelling differences. +- **ID**: exact match on the concept ID. +- **Mapping: Code** and **Mapping: List**: concepts that share a mapping with the row, for example to the same LOINC code. +- **Description**, **Property: Class**, **Property: Datatype** and other properties: string matching. + +It works with any target repository. Pick it when your input uses the same wording as the target terminology, when you match on codes or mappings, or when the target repository doesn't support semantic search. + +### OCL Semantic Algorithm + +OCL Semantic searches by meaning instead of by keywords. OCL stores a vector for each name and synonym in a repository that has semantic search, made with the `all-MiniLM-L6-v2` sentence-embedding model. The algorithm compares the row's **Name** and **Synonyms** with those vectors, so it can find a concept whose name uses different words from your input. Exact matches are boosted: a concept whose name is the row's name, or whose synonyms include one of the row's synonyms. The **ID** and mapping columns count as they do for OCL Search. + +It needs a target repository version with semantic search turned on: one whose `match_algorithms` setting includes `llm`. Only staff accounts can change that setting. If your target repository version doesn't have it, you can't select OCL Semantic, and switching a project to such a version removes OCL Semantic from it. + +Pick it when your terms are worded differently from the target terminology, as local and free-text terms often are. It takes longer per row than OCL Search, so AutoMatch sends it 10 rows per request by default, against 50 for OCL Search. + +### Bridge terminology search + +Bridge terminology search uses CIEL, an interface terminology with mappings to many reference terminologies, as a bridge. It runs a semantic search of CIEL, limited to CIEL concepts that have mappings into your target repository, and follows those mappings: the concepts they point to in your target repository become candidates. It can find target concepts that a direct search of the target repository misses. + +In the candidate list, a candidate found this way shows the CIEL concept it came through and the map type of that mapping. The CIEL concepts themselves are never proposed as matches. They appear when you group candidates by algorithm, and the OCL AI Assistant gets them as context. + +Pick it when CIEL has mappings into your target repository. It finds candidates only through those mappings, so it isn't available for every target repository. + +### ScispaCy LOINC search + +ScispaCy LOINC search sends the row's **Name** to an OCL matching service built on scispaCy, an open-source library for processing biomedical text, and gets back LOINC codes with their long common names. It uses no other column, and skips rows without a name. + +Its results are LOINC codes, so they become candidates in your target repository only when that repository is LOINC, with the canonical URL `http://loinc.org`. Pick it alongside OCL Search or OCL Semantic when you map laboratory test names to LOINC. + +The service can take a few minutes to start. Meanwhile the Mapper says it's warming up and tries again every two minutes, for up to ten minutes. + +### Custom Match Algorithm + +A custom algorithm calls a matching service you run. You configure: + +- **API URL**: where the Mapper sends match requests. When you enter it, the Mapper sends a `GET` request to it and fills in **ID**, **Name** and **Description** from the `id`, `name` and `description` in the response. If the service answers 401 or 403, the Mapper asks for a token. +- **API Token**, if your service needs one. The Mapper sends it in an `Authorization: Token ` header. It never sends your OCL credentials to a custom algorithm. +- **Canonical URL**, required: the canonical URL of the code system whose codes your service returns, such as `http://loinc.org`. Its results count as concepts in your target repository only when this matches the target repository's canonical URL. + +For each batch of rows, the Mapper sends your service a `POST` request, the same request it sends to OCL's [`$match` operation](../oclapi/apireference/match.md), and expects a response in the same shape: one entry per row, with the `row` as it was sent, `__index` included, and a `results` list of concepts, each with an `id` (its code) and a `display_name`. The reranker scores them like any other candidates, with one exception. When the custom algorithm is a project's only algorithm, AutoMatch takes each result's `search_meta.search_normalized_score`, if your service returns one, as its unified score, so return that score on the 0 to 100 scale. + +### Batch size and concurrent requests + +Each selected algorithm has a **Batch Size**, the number of rows AutoMatch sends it in one request, and a **Concurrent Requests** setting, the number of requests it keeps open at once. Lower the batch size for a slow service whose requests time out. See "Batching & Concurrency" in the [`$match` reference](../oclapi/apireference/match.md). ## One algorithm or several -**One algorithm** is the simplest place to start: every candidate comes from a single method, so the scores are easy to compare. Use OCL Semantic Algorithm if your target repository supports it, and OCL Search Algorithm if it doesn't. +**One algorithm** is the simplest place to start: every candidate comes from a single method. Use OCL Semantic Algorithm if your target repository supports it, and OCL Search Algorithm if it doesn't. + +**Several algorithms** widen the net. You can select up to five. Each one runs on every row, and their candidates are merged into one list per row. Add a second algorithm when one method alone misses matches, for example OCL Semantic Algorithm plus Bridge terminology search, or OCL Semantic Algorithm plus ScispaCy LOINC search for laboratory tests mapped to LOINC. + +Two rules limit the combinations: + +- **OCL Search and OCL Semantic exclude each other.** Once you select one, the other can't be selected. +- **OCL Semantic needs semantic search on the target repository version**, as described above. + +### How candidates are merged + +OCL Search and OCL Semantic each return up to 15 candidates per row, and **Fetch More** in the candidate list asks the algorithms for the next ones. The Mapper identifies every candidate by the canonical URL of its code system and its code. A concept that several algorithms found is therefore one candidate, labeled with every algorithm that found it. + +### How candidates are scored + +Each algorithm scores its candidates in its own way, so those scores can't be compared with each other. The Mapper gives every candidate a **unified score** from 0 to 100 instead. It comes from OCL's reranker, a cross-encoder model (by default `BAAI/bge-reranker-v2-m3`) that reads the row's **Name** next to the candidate's name and up to five of its synonyms, the five closest to the row's name in spelling. The candidate scores as its best-matching name. + +- When a project has one algorithm, and it's OCL Search or OCL Semantic, the reranker runs in the same request and the candidates arrive scored. +- Otherwise, with several algorithms or a bridge, ScispaCy or custom algorithm, the Mapper sends the row's merged candidates to OCL's `$rerank` endpoint once every algorithm has answered for the row. Until then, the candidates wait under **Unranked Candidates**. + +The unified score measures how well the names match. Codes, mappings and the other columns help the algorithms find candidates, but they don't change the score, so assign the column that holds your terms' names to **Name**. A row without a name gets no unified score, and its candidates stay unranked. The exception is a project whose only algorithm is OCL Search or OCL Semantic: there, such a row's candidates get the search's own score relative to its best candidate, which scores 100. + +The candidate list sorts by **Unified Score**. To see each algorithm's own score, sort by **Raw Algorithm Score**; the list then groups the candidates by algorithm, since those scores aren't comparable across algorithms. + +## Score thresholds + +Under **Score Configuration** in the project configuration, a slider sets two thresholds on the unified score, **Recommended** (99 by default) and **Available** (70 by default). They sort the candidates into three groups: + +- **Recommended**: a score at or above the Recommended threshold. +- **Available**: a score at or above the Available threshold, but below the Recommended threshold. +- **Low Ranked**: a score below the Available threshold. The configuration panel calls this group **Not Recommended**. + +The thresholds apply in three places: + +- **The candidate list.** Grouped by **Match Quality**, the default, a row's candidates appear under **Recommended Candidates**, **Available Candidates** and **Low Ranked Candidates**, and the low-ranked group starts collapsed. Only concepts in your target repository are grouped this way. +- **AutoMatch.** When a row's best candidate scores at or above the Recommended threshold, AutoMatch proposes it as the row's match, and the row becomes **Proposed**, ready for your review. Rows that AutoMatch runs on without such a candidate are left **Unmapped**. +- **The row list.** Each row has a match quality: the group of its proposed match or, where no match is proposed yet, of its best candidate. The row list counts the rows in each group, and you can show only the rows in one group. + +Changing the thresholds regroups candidates and rows at once, but it doesn't change matches already proposed: AutoMatch uses the new Recommended threshold the next time it runs. A higher Recommended threshold means fewer proposed matches that are more likely to be right; a lower one proposes more, and leaves more for you to check. + +## Where the OCL AI Assistant fits + +The OCL AI Assistant doesn't search for candidates. It works on the candidates the algorithms found: it weighs a row's candidates against the row's fields and your project's **Context**, then recommends one of them as the match and others as alternates, or none if nothing fits, and explains why. It chooses only among candidates in your target repository. The CIEL concepts that Bridge terminology search went through are given to it as context. + +You can run it: + +- on one row, from the candidate list, or +- in AutoMatch, by selecting **Recommend matches with the OCL AI Assistant**. It then runs after candidates are retrieved and scored, and skips rows it has already analyzed with the same candidates. Without **Retrieve candidates**, it analyzes only rows that already have candidates. + +Its analysis appears in the candidate list with its assessment, its primary candidate, the alternates and its reasoning, and you can group the candidates by **AI Analysis**. Each analysis stays with the row, so you can page back to earlier ones. In the row list, an icon next to a row's match shows whether the OCL AI Assistant recommended that match, suggested it as an alternate, or neither. -**Several algorithms** widen the net. Each one runs on every row, and their candidates are merged into one list per row; a concept found by more than one algorithm appears once. Add a second algorithm when one method alone misses matches — for example, OCL Semantic Algorithm plus Bridge terminology search. +The OCL AI Assistant doesn't change which match AutoMatch proposes: that still follows the Recommended threshold. The assistant's recommendation sits beside it for you to accept or reject. In **Field Configuration**, **Send to OCL AI Assistant** chooses which input columns it receives, and the project's **Input Language** decides which languages' concept names it gets. -OCL Search Algorithm and OCL Semantic Algorithm can't be selected together; choose one of them. +The OCL AI Assistant is an OCL Online service. The Mapper shows its controls when the Mapper is connected to that service and your account can use it. From 9e3a29991410ce9ac0600ce9e1e34cfbb14d9dd5 Mon Sep 17 00:00:00 2001 From: Jonathan Payne Date: Mon, 26 Oct 2026 11:11:34 -0400 Subject: [PATCH 2/5] OpenConceptLab/ocl_issues#2817 | Matching Algorithms: fixes from Codex pass 1 The ID column is a word-by-word text search of concept IDs, not an exact match, here and in the $match reference's two descriptions of `id`. Batch Size and Concurrent Requests apply only to OCL Search, OCL Semantic and custom algorithms; Bridge terminology search and ScispaCy LOINC search match one row at a time. Says that a name-less row's best candidate is always proposed with a single OCL algorithm, and states the AI Assistant's inputs as the Mapper sends them. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GrxkQb6LXc868Qyp4BfEuZ --- docs/source/oclapi/apireference/match.md | 4 ++-- docs/source/oclmap/matching-algorithms.md | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/oclapi/apireference/match.md b/docs/source/oclapi/apireference/match.md index c8d2997..d9ddd27 100644 --- a/docs/source/oclapi/apireference/match.md +++ b/docs/source/oclapi/apireference/match.md @@ -21,7 +21,7 @@ For every request, the API automatically adds a zero-based `__index` field to ea The API processes rows in batches. The client interface allows you to set the batch size, which is useful for APIs with longer computation times—using a lower batch size helps avoid timeouts. By default, the UI sends two concurrent batch requests at a time. For example, with 1000 rows and a batch size of 50, two batches (each with 50 rows) are sent concurrently; as soon as one finishes, the next batch is sent, maintaining exactly two in-flight requests. ### $match Algorithm Fields -- `id` - Exact match on `concept.id` in the target repository +- `id` - Search on `concept.id` in the target repository, word by word as in a text search: `ABC-123` can also match `DEF-123` - `name` - Keyword or semantic search on concept primary display name - `synonyms` - Keyword or semantic search on all concept names and synonyms - `description` - String search on all concept descriptions @@ -64,7 +64,7 @@ POST /concepts/$match/ | `target_repo_url` | 0..1 | string | Repository URL to match against. Uses `$resolve` to identify the specific repo version. Either `target_repo_url` or `target_repo` must be provided. **Example:** `/orgs/CIEL/sources/CIEL/` | | `target_repo` | 0..1 | object | Alternative to `target_repo_url`. Object with `owner`, `source`, `source_version`, and `owner_type` fields. Either `target_repo_url` or `target_repo` must be provided. | | `rows` | 1..\* | list | List of concept-like key-value pairs; each row may have different fields. Only fields that are recognized by the matching algorithm are used, all other fields are ignored. **Example:** `[{"s_n":"1","name":"malaria"},{"s_n":"2","name":"blood type"}]` | -| `rows.id` | 0..1 | string | Exact match against a concept ID. *(May be removed in future versions.)* **Example Input Data:** `12`, `57`, `A01.1` | +| `rows.id` | 0..1 | string | Search on concept IDs, word by word as in a text search, so `ABC-123` can also match `DEF-123`. *(May be removed in future versions.)* **Example Input Data:** `12`, `57`, `A01.1` | | `rows.name` | 0..1 | string | Semantic or fuzzy search on primary display name. **Example Input Data:** `Anemia due to blood loss` | | `rows.synonyms` | 0..1 | string or list | Semantic or fuzzy search across all names/synonyms. Accepts a single string or a list of strings. **Example Input Data:** `"Anemia, blood loss"` or `["Anemia, blood loss", "Anémie secondaire à une hémorragie"]` | | `rows.description` | 0..1 | string | Text search on concept descriptions. **Example Input Data:** `"Anemia due to bleeding or a hemorrhagic process"` | diff --git a/docs/source/oclmap/matching-algorithms.md b/docs/source/oclmap/matching-algorithms.md index 17440b5..96faf2f 100644 --- a/docs/source/oclmap/matching-algorithms.md +++ b/docs/source/oclmap/matching-algorithms.md @@ -23,7 +23,7 @@ For each row, the Mapper: OCL Search runs a keyword search of your target repository in Elasticsearch. It uses the input columns you assign in **Field Configuration**: - **Name** and **Synonyms**: keyword search of each concept's names and synonyms that tolerates small spelling differences. -- **ID**: exact match on the concept ID. +- **ID**: search of concept IDs, word by word as in a text search, so a row with `ABC-123` can also find a concept whose ID is `DEF-123`, not only the exact ID. - **Mapping: Code** and **Mapping: List**: concepts that share a mapping with the row, for example to the same LOINC code. - **Description**, **Property: Class**, **Property: Datatype** and other properties: string matching. @@ -65,7 +65,7 @@ For each batch of rows, the Mapper sends your service a `POST` request, the same ### Batch size and concurrent requests -Each selected algorithm has a **Batch Size**, the number of rows AutoMatch sends it in one request, and a **Concurrent Requests** setting, the number of requests it keeps open at once. Lower the batch size for a slow service whose requests time out. See "Batching & Concurrency" in the [`$match` reference](../oclapi/apireference/match.md). +AutoMatch sends rows to OCL Search, OCL Semantic and custom algorithms in batches. **Batch Size** is the number of rows in one request, and **Concurrent Requests** the number of requests it keeps open at once. Lower the batch size for a slow service whose requests time out. See "Batching & Concurrency" in the [`$match` reference](../oclapi/apireference/match.md). Bridge terminology search and ScispaCy LOINC search match one row at a time, whatever these settings say. ## One algorithm or several @@ -89,7 +89,7 @@ Each algorithm scores its candidates in its own way, so those scores can't be co - When a project has one algorithm, and it's OCL Search or OCL Semantic, the reranker runs in the same request and the candidates arrive scored. - Otherwise, with several algorithms or a bridge, ScispaCy or custom algorithm, the Mapper sends the row's merged candidates to OCL's `$rerank` endpoint once every algorithm has answered for the row. Until then, the candidates wait under **Unranked Candidates**. -The unified score measures how well the names match. Codes, mappings and the other columns help the algorithms find candidates, but they don't change the score, so assign the column that holds your terms' names to **Name**. A row without a name gets no unified score, and its candidates stay unranked. The exception is a project whose only algorithm is OCL Search or OCL Semantic: there, such a row's candidates get the search's own score relative to its best candidate, which scores 100. +The unified score measures how well the names match. Codes, mappings and the other columns help the algorithms find candidates, but they don't change the score, so assign the column that holds your terms' names to **Name**. A row without a name gets no unified score, and its candidates stay unranked. The exception is a project whose only algorithm is OCL Search or OCL Semantic: there, such a row's candidates get the search's own score relative to its best candidate, which scores 100, so AutoMatch always proposes it. The candidate list sorts by **Unified Score**. To see each algorithm's own score, sort by **Raw Algorithm Score**; the list then groups the candidates by algorithm, since those scores aren't comparable across algorithms. @@ -111,7 +111,7 @@ Changing the thresholds regroups candidates and rows at once, but it doesn't cha ## Where the OCL AI Assistant fits -The OCL AI Assistant doesn't search for candidates. It works on the candidates the algorithms found: it weighs a row's candidates against the row's fields and your project's **Context**, then recommends one of them as the match and others as alternates, or none if nothing fits, and explains why. It chooses only among candidates in your target repository. The CIEL concepts that Bridge terminology search went through are given to it as context. +The OCL AI Assistant doesn't search for candidates. It works on the candidates the algorithms found: it weighs a row's candidates against the row's fields and your project's **Context**, then recommends one of them as the match and others as alternates, or none if nothing fits, and explains why. The Mapper gives it the row's candidates in your target repository to choose from, and the CIEL concepts that Bridge terminology search went through as context only. You can run it: From cada2203d85ae9da98a7d9ba252b66d325fddbee Mon Sep 17 00:00:00 2001 From: Jonathan Payne Date: Mon, 26 Oct 2026 11:27:51 -0400 Subject: [PATCH 3/5] closes OpenConceptLab/ocl_issues#2817 | Matching Algorithms: simplification review cuts Folds the two combination rules into one sentence, and drops repeated statements: where the CIEL concepts go (the AI Assistant section keeps it), how several algorithms run and merge (the merge section keeps it), the ScispaCy pairing example (the ScispaCy section keeps it), and the bridge's reason for not being available everywhere. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GrxkQb6LXc868Qyp4BfEuZ --- docs/source/oclmap/matching-algorithms.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/source/oclmap/matching-algorithms.md b/docs/source/oclmap/matching-algorithms.md index 96faf2f..5c8dc07 100644 --- a/docs/source/oclmap/matching-algorithms.md +++ b/docs/source/oclmap/matching-algorithms.md @@ -41,9 +41,9 @@ Pick it when your terms are worded differently from the target terminology, as l Bridge terminology search uses CIEL, an interface terminology with mappings to many reference terminologies, as a bridge. It runs a semantic search of CIEL, limited to CIEL concepts that have mappings into your target repository, and follows those mappings: the concepts they point to in your target repository become candidates. It can find target concepts that a direct search of the target repository misses. -In the candidate list, a candidate found this way shows the CIEL concept it came through and the map type of that mapping. The CIEL concepts themselves are never proposed as matches. They appear when you group candidates by algorithm, and the OCL AI Assistant gets them as context. +In the candidate list, a candidate found this way shows the CIEL concept it came through and the map type of that mapping. The CIEL concepts themselves are never proposed as matches. They appear when you group candidates by algorithm. -Pick it when CIEL has mappings into your target repository. It finds candidates only through those mappings, so it isn't available for every target repository. +Pick it when CIEL has mappings into your target repository; it isn't available for every target repository. ### ScispaCy LOINC search @@ -71,12 +71,9 @@ AutoMatch sends rows to OCL Search, OCL Semantic and custom algorithms in batche **One algorithm** is the simplest place to start: every candidate comes from a single method. Use OCL Semantic Algorithm if your target repository supports it, and OCL Search Algorithm if it doesn't. -**Several algorithms** widen the net. You can select up to five. Each one runs on every row, and their candidates are merged into one list per row. Add a second algorithm when one method alone misses matches, for example OCL Semantic Algorithm plus Bridge terminology search, or OCL Semantic Algorithm plus ScispaCy LOINC search for laboratory tests mapped to LOINC. +**Several algorithms** widen the net. You can select up to five. Add a second algorithm when one method alone misses matches, for example OCL Semantic Algorithm plus Bridge terminology search. -Two rules limit the combinations: - -- **OCL Search and OCL Semantic exclude each other.** Once you select one, the other can't be selected. -- **OCL Semantic needs semantic search on the target repository version**, as described above. +**OCL Search and OCL Semantic can't be selected together**, and OCL Semantic needs a target repository version with semantic search. ### How candidates are merged From 16099c162f8d08421230c7e575f3f2e60ac54394 Mon Sep 17 00:00:00 2001 From: Jonathan Payne Date: Mon, 26 Oct 2026 16:46:53 -0400 Subject: [PATCH 4/5] OpenConceptLab/ocl_issues#2817 | Matching Algorithms: open Mapper first, OCL Online last The page now leads with what the open-source OCL Mapper and OCL API do: OCL Search, OCL Semantic and Custom Match Algorithm, merging, the unified score and the score thresholds. Bridge terminology search, ScispaCy LOINC search and the OCL AI Assistant move to a closing section, Available on OCL Online, which says they run on services OCL hosts and that the account decides which can be used. The intro links the $match reference as the specification of the request and response. Model names are given as the OCL API's defaults. The $match reference describes access neutrally (permission to use the Mapper; per-user rate limits answered with 429) and is brought in line with oclapi2: the bridge algorithm is reported as ocl-bridge and runs whenever filter.target_repo isn't the repository searched, numCandidates defaults to 500, and the reranker applies to any request with a row name. Custom Match Algorithm is documented as part of the open Mapper; OpenConceptLab/ocl_issues#2966 makes every build offer it. Co-Authored-By: Claude Opus 5.5 --- docs/source/oclapi/apireference/match.md | 12 ++--- docs/source/oclmap/matching-algorithms.md | 64 +++++++++++++---------- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/docs/source/oclapi/apireference/match.md b/docs/source/oclapi/apireference/match.md index d9ddd27..84459d3 100644 --- a/docs/source/oclapi/apireference/match.md +++ b/docs/source/oclapi/apireference/match.md @@ -9,8 +9,8 @@ The `$match` endpoint allows you to find similar or matching concepts across dif ### Authentication & Access - **Authentication required.** The user must be signed in. -- The user must be **mapper-approved** and not on the mapper waitlist. Returns `403 Forbidden` otherwise. -- Plan-based throttling is applied per user. +- The user must have permission to use the Mapper. Returns `403 Forbidden` otherwise. +- The server may limit how often each user can call `$match`. Returns `429 Too Many Requests` beyond that limit. ### Row Indexing @@ -52,10 +52,10 @@ POST /concepts/$match/ | `includeRetired` | Boolean | No | `false` | Match against retired concepts as well | | `bestMatch` | Boolean | No | `false` | Forces a minimum search score threshold to be applied, filtering out low-quality matches | | `semantic` | Boolean | No | `false` | Use semantic (LM-based) matching algorithm. The target repository must have the semantic match algorithm enabled. | -| `numCandidates` | Integer | No | `3000` | Only needed when semantic=true. Number of approximate nearest neighbor candidates. Range: 1 to 3000. For more information: https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html#tune-approximate-knn-for-speed-accuracy | +| `numCandidates` | Integer | No | `500` | Only needed when semantic=true. Number of approximate nearest neighbor candidates. Range: 1 to 3000. For more information: https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html#tune-approximate-knn-for-speed-accuracy | | `kNearest` | Integer | No | `100` | Only needed when semantic=true. Number of nearest neighbors to return from vector search. Range: 1 to 100. | | `encoder_model` | String | No | (none) | Custom encoder model name for semantic vector search | -| `reranker` | Boolean | No | `false` | Enable cross-encoder reranking of results. Only applicable when semantic=true. | +| `reranker` | Boolean | No | `false` | Rerank each row's results with a cross-encoder model, against the row's `name`. Rows without a `name` aren't reranked. | ### Request Body Schema @@ -112,7 +112,7 @@ POST /concepts/$match/ | results.search_meta.search_normalized_score | 1 | decimal | Normalized score on a 0-100 scale | | results.search_meta.search_rerank_score | 0..1 | decimal | Cross-encoder rerank score (only present when `reranker=true`) | | results.search_meta.match_type | 1 | string | Match confidence: `very_high`, `high`, `medium`, or `low` (see below) | -| results.search_meta.algorithm | 1 | string | Algorithm used: `ocl-search`, `ocl-semantic`, or `ocl-ciel-bridge` | +| results.search_meta.algorithm | 1 | string | Algorithm used: `ocl-search`, `ocl-semantic`, or `ocl-bridge` | | results.search_meta.search_highlight | 0..1 | map | Highlighted matching fields (e.g. `name`, `synonyms`) | | results.search_meta.search_confidence | 0..1 | string | Confidence value (may be null) | | results.source | 0..1 | string | Source mnemonic | @@ -153,7 +153,7 @@ When `bestMatch=true`, results with `low` match type are excluded. ### Notes - **`search_meta` is always included** in `$match` responses. There is no need to pass `includeSearchMeta=true`. -- **CIEL bridge algorithm:** When the target repo is CIEL and a `filter.target_repo` points to a non-CIEL repo, the `ocl-ciel-bridge` algorithm is used. +- **Bridge algorithm:** With `semantic=true` and a `filter.target_repo` other than the repository being searched, `$match` searches that repository's concepts that have mappings into `filter.target_repo`, and reports the algorithm as `ocl-bridge`. The OCL Mapper's Bridge terminology search uses it to search CIEL. - **Pagination** via `offset`/`limit` or `page`/`limit` applies to each row's result set independently. ### Example Response diff --git a/docs/source/oclmap/matching-algorithms.md b/docs/source/oclmap/matching-algorithms.md index 5c8dc07..0d7d340 100644 --- a/docs/source/oclmap/matching-algorithms.md +++ b/docs/source/oclmap/matching-algorithms.md @@ -1,6 +1,6 @@ # Matching Algorithms -A matching algorithm finds candidate concepts in your target repository for each row of your input file. You choose one or more in the project configuration, under **Matching Algorithm**. Which algorithms you can select depends on your target repository, your account and how the Mapper you use is set up. +A matching algorithm finds candidate concepts in your target repository for each row of your input file. You choose one or more in the project configuration, under **Matching Algorithm**. Which algorithms you can select depends on your target repository and on how the Mapper you use is set up. For each row, the Mapper: @@ -8,16 +8,20 @@ For each row, the Mapper: 2. **Merges them.** A concept found by more than one algorithm becomes one candidate. 3. **Scores them.** Every candidate gets a unified score from 0 to 100, whichever algorithm found it. 4. **Groups them.** Your score thresholds sort the candidates into Recommended, Available and Low Ranked. AutoMatch proposes a row's best candidate as its match when that candidate is Recommended. -5. **Recommends a match, if you ask.** The OCL AI Assistant reviews the candidates and recommends one, with its reasons. +5. **Recommends a match, if you ask.** On OCL Online, the OCL AI Assistant reviews the candidates and recommends one, with its reasons. + +Everything on this page is part of the open-source OCL Mapper and OCL API, except what the last section, [Available on OCL Online](#available-on-ocl-online), describes. The OCL algorithms run through the OCL API's `$match` operation, and a custom algorithm answers the same request. The [`$match` reference](../oclapi/apireference/match.md) specifies that request and its response. ## The algorithms +The OCL Mapper offers three algorithms: + - **OCL Search Algorithm**: keyword search, plus codes and mappings. - **OCL Semantic Algorithm**: search by meaning. -- **Bridge terminology search**: searches CIEL and follows its mappings into your target repository. -- **ScispaCy LOINC search**: suggests LOINC codes for laboratory test names. - **Custom Match Algorithm**: calls a matching service you run. +OCL Online adds two more, Bridge terminology search and ScispaCy LOINC search. + ### OCL Search Algorithm OCL Search runs a keyword search of your target repository in Elasticsearch. It uses the input columns you assign in **Field Configuration**: @@ -31,28 +35,12 @@ It works with any target repository. Pick it when your input uses the same wordi ### OCL Semantic Algorithm -OCL Semantic searches by meaning instead of by keywords. OCL stores a vector for each name and synonym in a repository that has semantic search, made with the `all-MiniLM-L6-v2` sentence-embedding model. The algorithm compares the row's **Name** and **Synonyms** with those vectors, so it can find a concept whose name uses different words from your input. Exact matches are boosted: a concept whose name is the row's name, or whose synonyms include one of the row's synonyms. The **ID** and mapping columns count as they do for OCL Search. +OCL Semantic searches by meaning instead of by keywords. The OCL API stores a vector for each name and synonym in a repository that has semantic search, made with a sentence-embedding model (by default `all-MiniLM-L6-v2`). The algorithm compares the row's **Name** and **Synonyms** with those vectors, so it can find a concept whose name uses different words from your input. Exact matches are boosted: a concept whose name is the row's name, or whose synonyms include one of the row's synonyms. The **ID** and mapping columns count as they do for OCL Search. It needs a target repository version with semantic search turned on: one whose `match_algorithms` setting includes `llm`. Only staff accounts can change that setting. If your target repository version doesn't have it, you can't select OCL Semantic, and switching a project to such a version removes OCL Semantic from it. Pick it when your terms are worded differently from the target terminology, as local and free-text terms often are. It takes longer per row than OCL Search, so AutoMatch sends it 10 rows per request by default, against 50 for OCL Search. -### Bridge terminology search - -Bridge terminology search uses CIEL, an interface terminology with mappings to many reference terminologies, as a bridge. It runs a semantic search of CIEL, limited to CIEL concepts that have mappings into your target repository, and follows those mappings: the concepts they point to in your target repository become candidates. It can find target concepts that a direct search of the target repository misses. - -In the candidate list, a candidate found this way shows the CIEL concept it came through and the map type of that mapping. The CIEL concepts themselves are never proposed as matches. They appear when you group candidates by algorithm. - -Pick it when CIEL has mappings into your target repository; it isn't available for every target repository. - -### ScispaCy LOINC search - -ScispaCy LOINC search sends the row's **Name** to an OCL matching service built on scispaCy, an open-source library for processing biomedical text, and gets back LOINC codes with their long common names. It uses no other column, and skips rows without a name. - -Its results are LOINC codes, so they become candidates in your target repository only when that repository is LOINC, with the canonical URL `http://loinc.org`. Pick it alongside OCL Search or OCL Semantic when you map laboratory test names to LOINC. - -The service can take a few minutes to start. Meanwhile the Mapper says it's warming up and tries again every two minutes, for up to ten minutes. - ### Custom Match Algorithm A custom algorithm calls a matching service you run. You configure: @@ -61,17 +49,17 @@ A custom algorithm calls a matching service you run. You configure: - **API Token**, if your service needs one. The Mapper sends it in an `Authorization: Token ` header. It never sends your OCL credentials to a custom algorithm. - **Canonical URL**, required: the canonical URL of the code system whose codes your service returns, such as `http://loinc.org`. Its results count as concepts in your target repository only when this matches the target repository's canonical URL. -For each batch of rows, the Mapper sends your service a `POST` request, the same request it sends to OCL's [`$match` operation](../oclapi/apireference/match.md), and expects a response in the same shape: one entry per row, with the `row` as it was sent, `__index` included, and a `results` list of concepts, each with an `id` (its code) and a `display_name`. The reranker scores them like any other candidates, with one exception. When the custom algorithm is a project's only algorithm, AutoMatch takes each result's `search_meta.search_normalized_score`, if your service returns one, as its unified score, so return that score on the 0 to 100 scale. +For each batch of rows, the Mapper sends your service a `POST` request, the same request it sends to the OCL API's [`$match` operation](../oclapi/apireference/match.md), and expects a response in the same shape: one entry per row, with the `row` as it was sent, `__index` included, and a `results` list of concepts, each with an `id` (its code) and a `display_name`. The reranker scores them like any other candidates, with one exception. When the custom algorithm is a project's only algorithm, AutoMatch takes each result's `search_meta.search_normalized_score`, if your service returns one, as its unified score, so return that score on the 0 to 100 scale. ### Batch size and concurrent requests -AutoMatch sends rows to OCL Search, OCL Semantic and custom algorithms in batches. **Batch Size** is the number of rows in one request, and **Concurrent Requests** the number of requests it keeps open at once. Lower the batch size for a slow service whose requests time out. See "Batching & Concurrency" in the [`$match` reference](../oclapi/apireference/match.md). Bridge terminology search and ScispaCy LOINC search match one row at a time, whatever these settings say. +AutoMatch sends rows to these algorithms in batches. **Batch Size** is the number of rows in one request, and **Concurrent Requests** the number of requests it keeps open at once. Lower the batch size for a slow service whose requests time out. See "Batching & Concurrency" in the [`$match` reference](../oclapi/apireference/match.md). ## One algorithm or several **One algorithm** is the simplest place to start: every candidate comes from a single method. Use OCL Semantic Algorithm if your target repository supports it, and OCL Search Algorithm if it doesn't. -**Several algorithms** widen the net. You can select up to five. Add a second algorithm when one method alone misses matches, for example OCL Semantic Algorithm plus Bridge terminology search. +**Several algorithms** widen the net. You can select up to five. Add a second algorithm when one method alone misses matches, for example a custom algorithm built for your terminology alongside OCL Semantic Algorithm. **OCL Search and OCL Semantic can't be selected together**, and OCL Semantic needs a target repository version with semantic search. @@ -81,10 +69,10 @@ OCL Search and OCL Semantic each return up to 15 candidates per row, and **Fetch ### How candidates are scored -Each algorithm scores its candidates in its own way, so those scores can't be compared with each other. The Mapper gives every candidate a **unified score** from 0 to 100 instead. It comes from OCL's reranker, a cross-encoder model (by default `BAAI/bge-reranker-v2-m3`) that reads the row's **Name** next to the candidate's name and up to five of its synonyms, the five closest to the row's name in spelling. The candidate scores as its best-matching name. +Each algorithm scores its candidates in its own way, so those scores can't be compared with each other. The Mapper gives every candidate a **unified score** from 0 to 100 instead. It comes from the OCL API's reranker, a cross-encoder model (by default `BAAI/bge-reranker-v2-m3`) that reads the row's **Name** next to the candidate's name and up to five of its synonyms, the five closest to the row's name in spelling. The candidate scores as its best-matching name. - When a project has one algorithm, and it's OCL Search or OCL Semantic, the reranker runs in the same request and the candidates arrive scored. -- Otherwise, with several algorithms or a bridge, ScispaCy or custom algorithm, the Mapper sends the row's merged candidates to OCL's `$rerank` endpoint once every algorithm has answered for the row. Until then, the candidates wait under **Unranked Candidates**. +- Otherwise, with several algorithms, a custom algorithm or one of OCL Online's, the Mapper sends the row's merged candidates to the OCL API's `$rerank` endpoint once every algorithm has answered for the row. Until then, the candidates wait under **Unranked Candidates**. The unified score measures how well the names match. Codes, mappings and the other columns help the algorithms find candidates, but they don't change the score, so assign the column that holds your terms' names to **Name**. A row without a name gets no unified score, and its candidates stay unranked. The exception is a project whose only algorithm is OCL Search or OCL Semantic: there, such a row's candidates get the search's own score relative to its best candidate, which scores 100, so AutoMatch always proposes it. @@ -106,7 +94,27 @@ The thresholds apply in three places: Changing the thresholds regroups candidates and rows at once, but it doesn't change matches already proposed: AutoMatch uses the new Recommended threshold the next time it runs. A higher Recommended threshold means fewer proposed matches that are more likely to be right; a lower one proposes more, and leaves more for you to check. -## Where the OCL AI Assistant fits +## Available on OCL Online + +[OCL Online](https://openconceptlab.org/) is where the OCL tools run for the global community, hosted by OCL. Its Mapper adds two algorithms and the OCL AI Assistant, which run on services that OCL hosts, so a Mapper you install yourself doesn't offer them. Your OCL Online account decides which of them you can use, and it can also limit the batch size and concurrent requests you can set and how much matching you can run. + +### Bridge terminology search + +Bridge terminology search uses CIEL, an interface terminology with mappings to many reference terminologies, as a bridge. It runs a semantic search of CIEL, limited to CIEL concepts that have mappings into your target repository, and follows those mappings: the concepts they point to in your target repository become candidates. It can find target concepts that a direct search of the target repository misses. + +In the candidate list, a candidate found this way shows the CIEL concept it came through and the map type of that mapping. The CIEL concepts themselves are never proposed as matches. They appear when you group candidates by algorithm. + +Pick it when CIEL has mappings into your target repository, for example alongside OCL Semantic Algorithm; it isn't available for every target repository. It matches one row at a time, so Batch Size and Concurrent Requests don't apply to it. + +### ScispaCy LOINC search + +ScispaCy LOINC search sends the row's **Name** to a matching service that OCL hosts, built on scispaCy, an open-source library for processing biomedical text, and gets back LOINC codes with their long common names. It uses no other column, and skips rows without a name. + +Its results are LOINC codes, so they become candidates in your target repository only when that repository is LOINC, with the canonical URL `http://loinc.org`. Pick it alongside OCL Search or OCL Semantic when you map laboratory test names to LOINC. It matches one row at a time, so Batch Size and Concurrent Requests don't apply to it. + +The service can take a few minutes to start. Meanwhile the Mapper says it's warming up and tries again every two minutes, for up to ten minutes. + +### Where the OCL AI Assistant fits The OCL AI Assistant doesn't search for candidates. It works on the candidates the algorithms found: it weighs a row's candidates against the row's fields and your project's **Context**, then recommends one of them as the match and others as alternates, or none if nothing fits, and explains why. The Mapper gives it the row's candidates in your target repository to choose from, and the CIEL concepts that Bridge terminology search went through as context only. @@ -118,5 +126,3 @@ You can run it: Its analysis appears in the candidate list with its assessment, its primary candidate, the alternates and its reasoning, and you can group the candidates by **AI Analysis**. Each analysis stays with the row, so you can page back to earlier ones. In the row list, an icon next to a row's match shows whether the OCL AI Assistant recommended that match, suggested it as an alternate, or neither. The OCL AI Assistant doesn't change which match AutoMatch proposes: that still follows the Recommended threshold. The assistant's recommendation sits beside it for you to accept or reject. In **Field Configuration**, **Send to OCL AI Assistant** chooses which input columns it receives, and the project's **Input Language** decides which languages' concept names it gets. - -The OCL AI Assistant is an OCL Online service. The Mapper shows its controls when the Mapper is connected to that service and your account can use it. From d52e4433c71ac4f36130ee60080071ee1bf23aa7 Mon Sep 17 00:00:00 2001 From: Jonathan Payne Date: Mon, 26 Oct 2026 16:55:07 -0400 Subject: [PATCH 5/5] OpenConceptLab/ocl_issues#2817 | Matching Algorithms: OCL Online section names only what an account decides Co-Authored-By: Claude Opus 5.5 --- docs/source/oclmap/matching-algorithms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/oclmap/matching-algorithms.md b/docs/source/oclmap/matching-algorithms.md index 0d7d340..7b431c5 100644 --- a/docs/source/oclmap/matching-algorithms.md +++ b/docs/source/oclmap/matching-algorithms.md @@ -96,7 +96,7 @@ Changing the thresholds regroups candidates and rows at once, but it doesn't cha ## Available on OCL Online -[OCL Online](https://openconceptlab.org/) is where the OCL tools run for the global community, hosted by OCL. Its Mapper adds two algorithms and the OCL AI Assistant, which run on services that OCL hosts, so a Mapper you install yourself doesn't offer them. Your OCL Online account decides which of them you can use, and it can also limit the batch size and concurrent requests you can set and how much matching you can run. +[OCL Online](https://openconceptlab.org/) is where the OCL tools run for the global community, hosted by OCL. Its Mapper adds two algorithms and the OCL AI Assistant, which run on services that OCL hosts, so a Mapper you install yourself doesn't offer them. Your OCL Online account decides which of them you can use. ### Bridge terminology search