iriq
iriq finds the shape of a URL: the route template behind it. Erase the
parts that vary, keep the parts that don't, and /users/123 and /users/999
both become /users/{user_id}. Point it at a pile of messy URLs and it
collapses them into a small set of stable, deterministic templates.
An IRI is a URL that's allowed to contain non-ASCII characters; if you know URLs, you know IRIs. The name is IRI Query.
This crate is both the library and the iriq command-line tool. This page
covers the library; the project README
covers the CLI.
Requires Rust 1.85 or newer.
Parse, normalize, extract
The pure functions need no setup and fail only with ParseError.
use ;
Learn from a stream with a corpus
A Corpus observes URLs and learns from what it sees: which slots vary, which
query params are enums, which values are HTTP statuses. It groups what it has
seen into clusters, one per route.
use Corpus;
The corpus changes a shape only at a position or param it has seen at least 5
times. Until then, corpus.normalize returns exactly what normalize does.
Persist a corpus
Corpus::open(path) picks the backend by extension: .db, .sqlite and
.sqlite3 are SQLite; anything else is JSON. For bulk ingest, hand
observe_all a slice of parsed IRIs: on SQLite it commits about a second's
worth at a time, so other processes writing the corpus get turns in between.
use BufRead;
use ;
If observe_all fails part-way, what it already committed stays. When
observations must land together or not at all, wrap them in batch: it commits
when the closure returns Ok and rolls back on Err or a panic. On SQLite it
holds the write lock until then, so keep it short.
save exports only JSON: saving to another .db path returns
Error::Unsupported and writes nothing.
Sharing a corpus between processes
- SQLite is the one to share. Many processes can observe into one
.dbat once, taking turns with the write lock: a writer waits up to 10 seconds for it, then returns an error.reinferand activation rebuild without the lock and take it only to install the result; abatchholds it until the closure returns. - JSON is single-writer. The file is read at
openand written atsave, so when two processes save the same file, the last one wins. - Activated recognizers. When another process activates a recognizer (the
CLI's
--activate-above), a long-livedCorpuspicks it up at the start of its nextbatch, andobservecounts as one. Reads outside a batch (normalize,clusters, …) keep classifying with what the corpus had before. Reopen the corpus, or read insidebatch(which on SQLite takes the write lock), to see the new ones.
Errors
Every Corpus operation returns iriq::Result<T>, whose error is
iriq::Error. Its Display names the corpus that failed; the underlying cause
is its source(). Error is #[non_exhaustive], so a match needs a _ arm.
use Error as _;
use ;
Error::Corrupt is a file that isn't a usable corpus (a JSON file that isn't
an iriq corpus). Error::Unsupported is one this build can't use: a SQLite
corpus from a newer iriq, or any .db in a build without the sqlite feature.
Error::Sqlite (only with that feature) is SQLite refusing an operation.
Features
sqlite (on by default) bundles SQLite through rusqlite, so there's no
system library to install. If you only need parsing, extraction or
normalization, turn it off to skip compiling the C library:
In-memory and JSON corpora still work; opening a .db returns
Error::Unsupported.
More
- API docs
- Project README: the CLI, and how classification and the corpus work
- Changelog
- License: MIT