Skip to main content

Sembra

Structural similarity scoring for JSON-compatible data

Italian: "sembrare" — to seem, to resemble


The Problem

Existing deep comparison libraries answer only binary questions:

Library Gives you
fast-deep-equal Equal or not?
lodash.isequal Equal or not?
deep-diff What changed?
deepdiff (Python) What changed?

None answer the most natural question:

How similar are these two structures?

When schemas evolve, keys get renamed, or data comes from different sources, binary equality is useless. You need a similarity score.

The Algorithm: Sembra Similarity

Sembra computes a continuous similarity score S(a, b) ∈ [0, 1] for any two JSON-compatible values using a novel multi-phase algorithm:

Phase 1: Type-Aware Primitive Matching

  • Strings: Jaro-Winkler distance (handles typos, minor variations)
  • Numbers: Relative difference scoring
  • Booleans: Exact match (configurable partial mode)
  • Null: Always exact

Phase 2: Optimal Array Alignment

Instead of index-by-index comparison, Sembra computes a similarity matrix between all pairs of elements and finds the optimal matching using a greedy assignment algorithm. This handles:

  • Reordered elements
  • Inserted/deleted elements
  • Partially matching elements

Phase 3: Value-Guided Key Rename Detection

This is the key novelty. When object keys differ between two structures, Sembra infers renames by comparing the values at those keys:

a = {"name": "Alice", "age": 30}
b = {"fullName": "Alice", "yearsOld": 30}
# Sembra detects: name → fullName, age → yearsOld
# Score: >0.85

No other library does this.

Phase 4: Recursive Composition

All phases compose recursively — nested arrays, nested objects, and mixed structures are handled uniformly.

Performance

Operation Complexity
Identical structures (early exit) O(n)
Similar structures O(n log n)
Dissimilar structures O(n × m)

n = number of nodes in the larger structure.

Quick Start

from sembra import sembra, sembra_report, SembraConfig

# Basic similarity
score = sembra({"a": 1, "b": 2}, {"a": 1, "b": 3})
print(score)  # ~0.89

# Key rename detection
score = sembra(
    {"userName": "Alice", "userAge": 30},
    {"name": "Alice", "age": 30}
)
print(score)  # >0.8

# Reordered arrays
score = sembra([1, 2, 3], [3, 1, 2])
print(score)  # 1.0 (all elements match)

# Detailed report
report = sembra_report({"a": 1}, {"a": 2})
print(report.score)
print(report.matches)
print(f"Computed in {report.duration_ns}ns")

# Configuration
config = SembraConfig(
    string_similarity=False,
    object_key_rename=False,
    number_threshold=0.9,
)
score = sembra({"a": "hello"}, {"a": "hallo"}, config)

Configuration Reference

Option Default Description
string_similarity True Enable fuzzy string matching
string_threshold 0.6 Minimum string similarity to count as match
number_similarity True Enable fuzzy number matching
number_threshold 0.8 Minimum number similarity to count as match
boolean_partial False Allow partial boolean matching
array_matching True Enable optimal array element matching
array_match_threshold 0.4 Minimum element similarity to match
object_key_rename True Enable value-guided key rename detection
object_rename_threshold 0.65 Minimum value similarity to infer rename
max_depth 16 Maximum recursion depth
max_array_size 200 Max array size for element-by-element matching
use_cache True Cache intermediate results
early_exit True Exit early for same-reference objects
key_weight_mode 'uniform' Key importance weighting

Use Cases

  • Test assertions with tolerance for structural variation
  • Schema migration — map old API responses to new schemas
  • Data deduplication — find structurally similar records
  • Configuration comparison — detect drifted configs
  • API monitoring — alert on structural drift
  • Merge conflict resolution — find best correspondence

Comparison with Existing Libraries

Feature Sembra deepdiff fast-deep-equal deep-diff
Continuous similarity score ✅ ❌ ❌ ❌
Key rename detection ✅ ❌ ❌ ❌
Array alignment ✅ ❌ ❌ ❌
Fuzzy strings ✅ ❌ ❌ ❌
Fuzzy numbers ✅ ❌ ❌ ❌
Binary equality ✅ ✅ ✅ ❌
Diff script ✅ ✅ ❌ ✅
Cross-type matching ✅ ❌ ❌ ❌

License

MIT — see LICENSE

Author

nhemlos

Metadata

Release files for sembra 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sembra 0.1.0
File Size Uploaded
sembra-0.1.0.tar.gz 75.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sembra 0.1.0
File Interpreter ABI Platform
sembra-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 83.4 kB

Release files / sembra-0.1.0.tar.gz

Download URL sembra-0.1.0.tar.gz
Size 75.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e591e20bee44b732deecab9d9a73557feb0afc5ff5bcacf5278a8b51b2cfbe02
BLAKE2b-256 checksum
How to use checksums
234089fbe31754c009e04f06b65e374b226f21d516208fb3d5bc1d102a741522
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Release files / sembra-0.1.0-py3-none-any.whl

Download URL sembra-0.1.0-py3-none-any.whl
Size 8.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4360d798dedeb8e8e454e55b6e38c7f859b6c7b0f728f424b925417cd8d04335
BLAKE2b-256 checksum
How to use checksums
78c6f1d86458712ace2c125583aac0a1b1937efa540925e636caaa8088884c3a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page