Calculate String Similarity
data.calculate_similarity
Overview
You send two strings and name exactly one metric, and we return a score from 0 to 1 rounded to four decimals, the raw edit distance where the metric has one, the set arithmetic where it works on sets, and the lengths after normalisation so a surprising score is explainable. Seven metrics are offered and each is defined in the documentation: LEVENSHTEIN and DAMERAU_LEVENSHTEIN over code points, JARO and JARO_WINKLER with Winkler's published 0.7 prefix threshold, and JACCARD_TOKEN, JACCARD_SHINGLE and DICE_SHINGLE over token and word-shingle sets. There is no default metric, because a similarity score that does not say which metric produced it is not an answer. The cost budget is chosen by the metric, so a linear metric is never refused at a quadratic price, and a pair too expensive to compare is refused before the first cell rather than sampled.
One platform should have one Levenshtein and one Jaro-Winkler, so two skills scoring the same pair never disagree about the number.
Reliability
The same pair, metric and normalisation always give the same score, on any machine and under any locale, time zone or default charset. Scores round half-up to four decimals, and JARO_WINKLER applies its prefix boost only above a Jaro of 0.7, which is Winkler's published rule and is deliberately not what data.detect_duplicates does — that skill boosts unconditionally, so the two report different numbers for the same pair and both are intended. DAMERAU_LEVENSHTEIN is the restricted variant, where no substring is edited twice, so comparing CA against ABC gives 3 rather than the 2 the unrestricted definition gives. Missing, empty, non-string or over-65536-code-point operands are structural TOOL_INPUT_INVALID refusals. Seven domain refusals are not retryable unchanged: SIMILARITY_INPUT_INVALID when normalization is not an object — send an object and call again; SIMILARITY_METHOD_REQUIRED when no metric was named at all, which we never guess for you — pick one from the seven and resend; SIMILARITY_METHOD_UNSUPPORTED when the metric named is outside the seven we publish, so check the spelling against the list; SIMILARITY_OPTION_UNSUPPORTED when a normalisation key, a Unicode form or a token pattern is unknown, or a set-only option was sent with an edit metric — drop the option or switch the metric; SIMILARITY_SHINGLE_SIZE_INVALID when shingleSize is outside 2 to 8 inclusive, so move it back inside the range; SIMILARITY_EMPTY_AFTER_NORMALIZATION when your normalisation left both strings empty, where a score of 1 would claim two piles of punctuation are the same text — turn an option off and call again; SIMILARITY_WORK_REFUSED when the pair projects past the 25000000-unit ceiling, reported with both the projection and the budget so you can shorten the operand by the right amount or move to a set metric, which costs far less.
Context footprint
Returns one score plus lengths, set counts and the admission numbers — never an echo of either string. A successful call costs 2 execution credits.
When to use it
When you have exactly two strings and want a defensible number for how close they are.
When you have a table and want duplicate clusters rather than a single pairwise score.
Scope
Non-goals
- Does not cluster records — data.detect_duplicates does that
- Does not choose a metric for you
- Does not decide whether a score means the same thing
- Does not compare more than one pair per call
Properties
Capabilities
Cost & billing
Flat rate per invocation
File handling
How we handle your data
What this means
This skill may receive sensitive content, but it does not target sensitive data and returns only a structured non-sensitive result.
Squillify guarantees
- Runs inside Squillify
- This skill runs inside Squillify.
- Payloads are not sent to an external service by this skill.
- Squillify does not permanently store submitted payloads.
- Telemetry records metadata only, not submitted content.
- Submitted payloads are not used for training.
- Submitted payloads are not reviewed by humans.
- This skill does not target sensitive data.
- The response does not contain submitted content.
Your responsibility
Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
| a | string | Yes | First string to compare, 1 through 65536 code points. |
| b | string | Yes | Second string to compare, 1 through 65536 code points. |
| method | string | Yes | Named similarity metric; there is no default. |
| normalization | object | No | Closed optional normalization switches applied to both strings before scoring; omit the object to compare the strings exactly as sent. |
| tokenPattern | string | No | Token splitter for set metrics; omit it for UNICODE_WORD, and never send it with an edit or Jaro metric. |
| shingleSize | integer | No | Tokens per shingle for JACCARD_SHINGLE and DICE_SHINGLE; omit it for 5, and never send it with any other metric. |
Output schema
| Field | Type | Required | Description |
|---|---|---|---|
| score | number | Yes | Similarity from 0 through 1, rounded half-up to four decimals. |
| method | string | Yes | Metric that produced the score. |
| distance | integer | No | Raw edit distance for LEVENSHTEIN and DAMERAU_LEVENSHTEIN; omitted otherwise. |
| lengths | object | Yes | Closed operand lengths in code points after normalization, with left and right counts. |
| sets | object | No | Closed set arithmetic for token and shingle metrics; omitted for edit and Jaro metrics. |
| normalization | object | Yes | Closed normalization settings actually applied, with defaults filled in. |
| work | object | Yes | Closed admission decision with projected cost and budget in metric units. |
API contract
POST /v1/executecurl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"data.calculate_similarity","input":{"a":"Jonathon","b":"Jonathan","method":"LEVENSHTEIN"}}'import { Squillify } from "@squillify/sdk";
const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });
const { output } = await sq.execute("data.calculate_similarity", {"method":"LEVENSHTEIN","a":"Jonathon","b":"Jonathan"});Errors
| Code | HTTP | Retryable | Description |
|---|---|---|---|
| VALIDATION_ERROR | 400 | No | The request payload failed schema validation. |
| UNAUTHORIZED | 401 | No | Missing or invalid API key. |
| SKILL_NOT_ACCESSIBLE | 403 | No | The API key is not granted access to this skill. |
| SKILL_NOT_AVAILABLE_FOR_PLAN | 403 | No | This skill is not included in your current plan. |
| PLAN_ELIGIBILITY_UNAVAILABLE | 503 | Yes | Plan eligibility could not be decided. Retry after backoff. |
| SKILL_NOT_FOUND | 404 | No | The requested skill or version does not exist. |
| TENANT_RATE_LIMITED | 429 | Yes | Request rate limit exceeded. Retry after backoff. |
| QUOTA_EXCEEDED | 429 | Yes | Plan quota exhausted. Retryable once the quota period resets. |
| EXECUTION_TIMEOUT | 504 | Yes | Execution exceeded the allowed time budget. |
| SIMILARITY_INPUT_INVALID | 400 | No | The request payload failed this skill's input validation. |
| SIMILARITY_METHOD_REQUIRED | 400 | No | The request payload failed this skill's input validation. |
| SIMILARITY_METHOD_UNSUPPORTED | 400 | No | The skill does not support the requested variant. |
| SIMILARITY_OPTION_UNSUPPORTED | 400 | No | The skill does not support the requested variant. |
| SIMILARITY_SHINGLE_SIZE_INVALID | 400 | No | The request payload failed this skill's input validation. |
| SIMILARITY_EMPTY_AFTER_NORMALIZATION | 412 | No | The input is valid but cannot be processed as-is. |
| SIMILARITY_WORK_REFUSED | 429 | No | A size, quota, rate, or time limit was exceeded. |
Other limits
| Limit | Value |
|---|---|
| Recommended inline bytes | 32 KiB |
Limitations
- Does not cluster records — data.detect_duplicates does that
- Does not choose a metric for you
- Does not decide whether a score means the same thing
- Does not compare more than one pair per call
- Deduplicating a whole table pair by pair
- Treating a score as a probability that two records are the same
How to call
POST /v1/execute (requires authentication)
{
"skillKey": "data.calculate_similarity",
"input": {
"method": "LEVENSHTEIN",
"a": "Jonathon",
"b": "Jonathan"
}
}Examples
Two spellings of a surname
{
"method": "LEVENSHTEIN",
"a": "Jonathon",
"b": "Jonathan"
}{
"score": 0.875,
"distance": 1,
"method": "LEVENSHTEIN",
"normalization": {
"stripPunctuation": false,
"caseFold": false,
"unicodeForm": "NONE",
"collapseWhitespace": false
},
"work": {
"projected": 64,
"budget": 25000000
},
"lengths": {
"b": 8,
"a": 8
}
}Two product titles compared as word sets
{
"method": "JACCARD_TOKEN",
"a": "red cotton shirt",
"b": "cotton shirt red"
}{
"score": 1,
"sets": {
"union": 3,
"intersection": 3,
"aSize": 3,
"bSize": 3
},
"method": "JACCARD_TOKEN",
"normalization": {
"tokenPattern": "UNICODE_WORD",
"unicodeForm": "NONE",
"collapseWhitespace": false,
"caseFold": false,
"stripPunctuation": false
},
"work": {
"projected": 6,
"budget": 25000000
},
"lengths": {
"b": 16,
"a": 16
}
}Recommended use cases
- Comparing two candidate spellings of one name
- Scoring a proposed match before a human confirms it
- Measuring how far a rewritten text moved from the original
Avoid for
- Deduplicating a whole table pair by pair
- Treating a score as a probability that two records are the same
Related skills
Composable with
Safety & privacy
- Runs without calling any external service.
- Your payloads are never stored permanently.
- Telemetry captures metadata only — never your payload contents.
- We never train models on your payloads.
- No human reviews your payloads.