Omega Object Matching Grammar (OmegaOMG): DSL and engine for high-performance object/entity matching.
Project description
OmegaOMG: Omega Object Matching Grammar
OmegaOMG is a domain-specific language (DSL) and runtime engine for defining and evaluating high‑performance object / entity matching rules against large byte-based inputs (“haystacks”). It leverages pre‑anchored longest, non‑overlapping pattern matches (via the OmegaMatch library), an optimized AST evaluation engine, and a modular entity resolution pipeline to produce clean, canonicalized, and enriched match streams.
Key Features
- Expressive DSL (version
1.0):version 1.0header (mandatory)import "file.txt" as alias [with flags...]- Pattern atoms: literals, escapes (
\d \s \wetc.), anchors^ $, dot., character classes[...], list matches[[alias]], optional filters[[alias:startsWith("A")]], named captures(?P<name> ...). - Operators: concatenation, alternation
|, grouping(...). - Quantifiers: bounded
{m},{m,n}, and?(no unbounded*/+– enforced at runtime). - Every rule must include at least one
ListMatchanchor (validated). - Dotted rule names (e.g.
person.surname) supported for parent/child entity models.
- Import flags:
ignore-case,ignore-punctuation,elide-whitespace,word-boundary,word-prefix,word-suffix,line-start,line-end(forwarded toomega_match). - Pre‑anchored matching: Delegates raw token list detection to
omega_matchwithlongest_only&no_overlapguarantees per alias. - Optimized AST evaluation:
- Offset‑indexed & binary searched ListMatch anchors
- Greedy quantified ListMatch chaining
- Caching for pattern parts, prefix length, listmatch presence, unbounded checks
- Adaptive sampling of potential start offsets to dramatically reduce scan points
- Entity Resolution Pipeline (see
RESOLUTION.md): Implements Steps 1‑6- Validation & normalization
- Overlap resolution with deterministic tie‑breaking
- Tokenization + optional token filtering
- Horizontal canonicalization (parent deduplication)
- Vertical child resolution (child → parent referencing)
- Metadata enrichment (sentence / paragraph boundaries)
- Resolver configuration:
resolver default uses exact ...sets a default for rules- Per‑rule:
rule = ... uses resolver fuzzy(threshold="0.9") with ignore-case, optional-tokens("file.txt") - Parent rules without children skip resolution for speed; parents with children receive an automatic lightweight
boundary-onlyresolver if not explicitly configured.
- Resolver methods: Grammar accepts arbitrary resolver method identifiers; built-ins implemented are
exactandfuzzy(threshold=...). For parent canonicalization, unknown methods fall back toexact. For child resolution, useexactorfuzzyto guarantee matching; unknown methods may result in children being discarded. An internalboundary-onlymode is used automatically for certain parent rules. - Highlighter utility: Renders enriched matches to interactive HTML (
highlighter.py) with rule toggles and keyboard navigation (n/p). - VS Code language integration: See OMG Language Support for syntax highlighting & IntelliSense.
- Lean dependencies: Runtime requires only
larkandomega_match.
For algorithmic details and performance rationale see:
RESOLUTION.md
Installation
Requires: Python 3.9+ (uses builtin generics like tuple[str, ...]).
-
Clone this repository:
git clone https://github.com/scholarsmate/omega-omg.git cd omega-omg
-
Create and activate a Python virtual environment:
a. Windows:
python3.exe -m venv .venv .\.venv\Scripts\Activate.ps1
b. *nix and macOS:
python3 -m venv .venv source ./.venv/bin/activate
-
Install runtime dependencies (and optionally dev tooling):
pip install -r requirements.txt # For contributors / tests / linting pip install -r requirements-dev.txt
-
(Optional) Run tests to verify environment:
pytest -q
Usage
1. Define a DSL file
Create a .omg file with rules, e.g., demo/demo.omg:
version 1.0
# Import match lists
import "name_prefix.txt" as prefix with word-boundary, ignore-case
import "names.txt" as given_name with word-boundary
import "surnames.txt" as surname with word-boundary
import "name_suffix.txt" as suffix with word-boundary
import "0000-9999.txt" as 4_digits with word-boundary
import "tlds.txt" as tld with word-boundary, ignore-case
# Configure the default resolver
resolver default uses exact with ignore-case, ignore-punctuation
# Top-level rule for matching a person's name
person = ( [[prefix]] \s{1,4} )? \
[[given_name]] ( \s{1,4} [[given_name]] )? ( \s{1,4} \w | \s{1,4} \w "." )? \
\s{1,4} [[surname]] \
(\s{0,4} "," \s{1,4} [[suffix]])? \
uses default resolver with optional-tokens("person-opt_tokens.txt")
# Dotted-rule references resolve to top-level person matches
person.prefix_surname = [[prefix]] \s{1,4} [[surname]] (\s{0,4} "," \s{1,4} [[suffix]])? \
uses default resolver with optional-tokens("person-opt_tokens.txt")
person.surname = [[surname]] (\s{0,4} "," \s{1,4} [[suffix]])? \
uses default resolver with optional-tokens("person-opt_tokens.txt")
# Rule for matching a phone number
phone = "(" \s{0,2} \d{3} \s{0,2} ")" \s{0,2} \d{3} "-" \s{0,2} [[4_digits]]
# Rule for matching email addresses with bounded quantifiers
# Pattern: username@domain.tld
# Username: 1-64 chars (alphanumeric, dots, hyphens, underscores)
# Domain: 1-253 chars total, each label 1-63 chars
email = [A-Za-z0-9._-]{1,64} "@" [A-Za-z0-9-]{1,63} ("." [A-Za-z0-9-]{1,63}){0,10} "." [[tld]]
2. Parse and evaluate in Python
from dsl.omg_parser import parse_file
from dsl.omg_evaluator import RuleEvaluator
# Load DSL and input haystack
ast = parse_file("demo/demo.omg")
with open("demo/CIA_Briefings_of_Presidential_Candidates_1952-1992.txt", "rb") as f:
haystack = f.read()
# Evaluate a specific rule
engine = RuleEvaluator(ast_root=ast, haystack=haystack)
matches = engine.evaluate_rule(ast.rules["person"])
for m in matches:
print(m.offset, m.match.decode())
3. Command-Line Tool
A command-line interface is provided by omg.py.
python omg.py --help
Common flags:
| Flag | Purpose |
|---|---|
--show-stats |
Emit resolution statistics (input vs output, stage timings) |
--show-timing |
Show breakdown of file load, parse, evaluation, resolution |
--no-resolve |
Skip entity resolution; emit raw rule matches |
--pretty-print |
Emit a single JSON array instead of line-delimited JSON objects |
--log-level LEVEL |
Adjust logging (default WARNING) |
-o file.json |
Write JSON output to file (UTF‑8, LF) |
--version |
Show component & DSL versions |
Version output example:
Version information:
omega_match: <x.y.z>
omg: 0.2.0
DSL: 1.0
Demo: End-to-End Object Matching and Highlighting
The following demonstrates how to use the CLI tools to extract and visualize matches from a text file using a demo OMG rule set:
-
Run the matcher and output results to JSON (line‑delimited):
python omg.py --show-stats --show-timing --output matches.json .\demo\demo.omg .\demo\CIA_Briefings_of_Presidential_Candidates_1952-1992.txt
This command will print timing and statistics to the terminal and write all matches to
matches.jsonin UTF-8 with LF line endings. -
Render the matches as highlighted HTML:
python highlighter.py .\demo\CIA_Briefings_of_Presidential_Candidates_1952-1992.txt matches.json CIA_demo.html
This will generate an HTML file (
CIA_demo.html) with all matched objects highlighted for easy review.
You can open the resulting HTML file in a browser to visually inspect the extracted matches.
Project Structure
omg.py # CLI driver (evaluate + optional resolution + JSON output)
highlighter.py # Convert line-delimited match JSON to interactive HTML
dsl/
omg_grammar.lark # Lark grammar definition for DSL v1.0
omg_parser.py # Parser + resolver clause extraction + version enforcement
omg_ast.py # Immutable AST node dataclasses
omg_transformer.py # Grammar → AST transformer
omg_evaluator.py # Optimized rule evaluation engine
omg_resolver.py # Resolver façade (imports components below)
resolver/ # Entity resolution submodules (overlap, horizontal, vertical, tokenizer, metadata)
demo/ # Example DSL + pattern lists + sample text
tests/ # Comprehensive pytest suite
RESOLUTION.md # Detailed entity resolution algorithm spec
DSL Constraints & Gotchas
- All rules must include at least one
[[alias]](ListMatch). Pure literal / regex‑like rules are rejected. - Unbounded quantifiers (
*,+) are disallowed; use{0,n}/{1,n}equivalents. - Quantified
ListMatchchains are greedily extended with adjacency (no gaps) and optional line boundary enforcement. - Dotted (child) rules without an explicit resolver inherit the default; parents with children but no explicit resolver receive a lightweight
boundary-onlyconfig to add structural metadata. - Import paths in a DSL file are resolved relative to that DSL file when relative.
Entity Resolution Summary
After raw AST evaluation, resolution (unless --no-resolve) applies:
- Overlap removal (length > earlier offset > shorter rule name > lexical rule name).
- Parent canonicalization by normalized token bag (flags + optional tokens removed).
- Child rule validation: each child must map to exactly one canonical parent (else dropped).
- Metadata enrichment: sentence & paragraph boundary offsets.
See RESOLUTION.md for full reasoning, complexity, and future extension recommendations.
Performance Notes
- Matching cost reduced via adaptive anchor sampling and per‑alias offset maps.
- Regex-like escapes use pre‑compiled single‑byte patterns for speed.
- Caches (pattern part, prefix length, ListMatch presence, unbounded quantifier detection) materially cut repeated traversals.
- Resolution skips unnecessary work (e.g., no resolver for isolated parent rules).
Development
Formatting / linting (optional but recommended):
ruff check .
pylint dsl omg.py highlighter.py
pytest --cov
Type checking:
mypy dsl
Releasing (example):
python -m build
twine upload dist/*
Troubleshooting
| Issue | Likely Cause | Fix |
|---|---|---|
ValueError: Rule 'x' must include at least one list match |
Rule lacks [[alias]] |
Add an import + list match anchor |
Unsupported OMG DSL version |
DSL file version mismatch | Update version 1.0 or engine constant |
| No matches produced | Missing import flags (e.g. word-boundary) or list file path issue |
Verify list file contents & flags |
| Child rules disappear | Unresolved parent reference | Ensure corresponding parent rule matches same span |
| HTML missing colors for a rule | Rule produced zero matches | Confirm JSON lines include that rule |
Roadmap (Planned / Potential)
- Plugin resolver strategy interface (custom similarity algorithms)
- Parallel rule evaluation for very large haystacks
- Configurable overlap priority strategies
- More built-in resolver methods beyond
exact,fuzzy,contains - Richer IDE tooling (hover docs, go‑to definition)
Contributing
- Fork the repo and create a feature branch.
- Write tests under
tests/for new features or bug fixes. - Run
pytestto ensure all tests pass.pytest - Submit a pull request.
License
The OmegaOMG project is licensed under the Apache License 2.0.
OmegaOMG is not an official Apache Software Foundation (ASF) project.
Questions or ideas? Open an issue or start a discussion – contributions and feedback are welcome.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file omega_omg-0.2.1.tar.gz.
File metadata
- Download URL: omega_omg-0.2.1.tar.gz
- Upload date:
- Size: 79.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
48c2a82677a4c2a6da6f8f8b8650f0a7df95433059c1ed5b1cc2b977959c0d2a
|
|
| MD5 |
8540ca0063c1d5c46227205d4790d2ba
|
|
| BLAKE2b-256 |
29324efd4412f21bc01b0bd70896d748fb519e79aabde0031f334ff8608fd817
|
File details
Details for the file omega_omg-0.2.1-py3-none-any.whl.
File metadata
- Download URL: omega_omg-0.2.1-py3-none-any.whl
- Upload date:
- Size: 55.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49008b61a63f7bfa86d3f635b77ccb729c089b1e92ce18de70537d998ec6e60d
|
|
| MD5 |
eea1f6160c1f12c577fc94d6c8e60a71
|
|
| BLAKE2b-256 |
46ef82a4129df4f41cdb86da907924c0c3338c39068209bedde75c39ef50a08c
|