Delex (DAG multi-strategy blocking)¶
DAG-based multi-strategy blocking. madmatcher_pro.delex has an empty
__init__; import these symbols from their submodules, as shown below. You build
a BlockingProgram from rules and predicates and run it with PlanExecutor.
The advanced base classes at the bottom are only needed to write a custom
predicate or rule.
Running a blocking program¶
- class madmatcher_pro.delex.execution.plan_executor.PlanExecutor(*, index_table, search_table, build_parallelism=4, index_table_id_col='_id', ram_size_in_bytes=None, cost_est=None, optimize, estimate_cost, index_sample_sizes=(25000, 50000, 100000), filter_sample_size=10000, sample_seed=None)¶
Bases:
GraphExecutorCompiles a delex
BlockingPrograminto a plan and runs it over Spark.Construct with the
index_table/search_table(fromGraphExecutor) plusoptimizeandestimate_costflags, then callexecute()with the compiled program to produce a candidate table(id2, id1_list, ...)– the shared blocking-output contract.executealso exposes the opt-in crash-recovery andexclude_self(dedup) flags. The cost-estimation sampling knobs (index_sample_sizes/filter_sample_size/sample_seed) tune planning only and are used whenestimate_costis set.Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- Parameters:
index_table (DataFrame)
search_table (DataFrame)
build_parallelism (Annotated[int, Gt(gt=0)])
index_table_id_col (str)
ram_size_in_bytes (Annotated[int, Gt(gt=0)] | None)
cost_est (CostEstimator | None)
optimize (bool)
estimate_cost (bool)
index_sample_sizes (tuple[int, ...])
filter_sample_size (int)
sample_seed (int | None)
- execute(prog, search_table_id_col, projection=None, chunk_size=2000, *, enable_crash_recovery=False, checkpoint_dir=None, n_groups=10, rows_per_group=None, show_progress=False, validate_input=True, dashboard=None, dashboard_port=None, open_browser=None, exclude_self=False)¶
Compile prog into a plan and execute it.
- Parameters:
prog (BlockingProgram) – the blocking program to compile into a plan and run
search_table_id_col (str) – the id column of the search table
projection (list of str, optional) – search-table columns to carry into the output alongside the candidate lists; None (default) keeps only the search id column
chunk_size (int, default 2000) – target number of records per partition when repartitioning the tables for execution
- Returns:
The second return value differs by mode. Default (enable_crash_recovery=False) returns (candidate_df, PlanExecutionStats) with exec/optimize/cost times and total_time. enable_crash_recovery=True returns (union_df, ResumableBlockingStats), a different stats type (n_groups, groups_committed, groups_run_this_session, optimize/cost times, checkpoint_dir) with no graph_exec_stats or total_time, since a resumable run spans groups and processes.
- Return type:
tuple
Notes
enable_crash_recovery (keyword-only, default off) makes the blocking resumable: search records are split into n_groups hash-groups, each run through the full plan and committed with an atomic marker; a re-run with the same checkpoint_dir skips committed groups. It then requires checkpoint_dir. rows_per_group, if set, derives n_groups = ceil(num_records / rows). validate_input (default True) records the search row count and refuses a resume whose count changed (count-only: a same-count change isn’t caught); pass False only for a known-immutable input.
dashboard / dashboard_port / open_browser default to None, meaning “defer to the active MadMatcherSession, else the env/default (on)”; pass an explicit value to override. The global opt-out MADMATCHER_DASHBOARD=0 turns tracking off regardless. Any failure to start the dashboard is logged and swallowed, so it never blocks the blocking job.
Blocking programs and rules¶
- class madmatcher_pro.delex.lang.program.BlockingProgram(keep_rules, drop_rules)¶
Bases:
objectA blocking program: a set of keep rules (unioned) minus a set of drop rules.
A candidate pair is kept if it satisfies ANY keep rule, unless it also satisfies a drop rule. Compile and run it with
execute():from madmatcher_pro.delex.lang import BlockingProgram, KeepRule from madmatcher_pro.delex.lang.predicate import BM25TopkPredicate prog = BlockingProgram( keep_rules=[ KeepRule([BM25TopkPredicate("name", "name", "standard", 20)]), KeepRule([BM25TopkPredicate("description", "description", "standard", 20)]), ], drop_rules=[], )
- Parameters:
- validate()¶
Validate the program. A blocking program must contain at least one keep rule; raises
ValueErrorif it does not. Called automatically after construction.
- pretty_str()¶
create a pretty string of the entire blocking program
- Return type:
str
- class madmatcher_pro.delex.lang.rule.KeepRule(predicates)¶
Bases:
RuleA conjunctive blocking rule: keep candidate pairs that satisfy all its predicates.
A
BlockingProgramis a set ofKeepRules whose outputs are unioned. Each rule ANDs itspredicates(e.g. a BM25 top-k on name AND an exact match on zip), and must contain at least one indexable predicate (checked byvalidate()) so the rule can be driven from an index rather than a full cross product.- Parameters:
predicates (list of Predicate) – the predicates ANDed together; must include at least one indexable predicate
- validate()¶
check that this rule has at least one indexable predicate if not raise RuntimeError
- class madmatcher_pro.delex.lang.rule.DropRule(predicates)¶
Bases:
RuleA drop rule: remove candidate pairs that satisfy all its predicates.
- Parameters:
predicates (list of Predicate) – the predicates ANDed together; all must be streamable
- validate()¶
check that all the predicates in this rule are streamable if not raise RuntimeError
Predicates¶
The concrete predicates a blocking rule is built from. Import them from
madmatcher_pro.delex.lang.predicate.
- class madmatcher_pro.delex.lang.predicate.BM25TopkPredicate(index_col, search_col, tokenizer, k)¶
Bases:
Predicate- Parameters:
index_col (str) – the column in the indexed table that the BM25 index is built on
search_col (str) – the column in the search table used to query the index
tokenizer (str) – name of the tokenizer that splits each string into terms
k (int, > 0) – number of top-scoring candidates kept per search record
- class madmatcher_pro.delex.lang.predicate.ExactMatchPredicate(index_col, search_col, invert, lowercase=False)¶
Bases:
ThresholdPredicatean exact match predicate, i.e. if x == y return 1.0 else 0.0
- index_colstr
the column to be indexed
- search_colstr
the column that will be used for search
- invertbool
change predicate from index_col == search_col to index_col != search_col
- lowercasebool
lowercase the strings before comparing them
- Parameters:
index_col (str)
search_col (str)
invert (bool)
lowercase (bool)
- class madmatcher_pro.delex.lang.predicate.JaccardPredicate(index_col, search_col, tokenizer, op, val)¶
Bases:
SetSimPredicate- Parameters:
index_col (str) – the column in the indexed table to compare
search_col (str) – the column in the search table to compare against
tokenizer (Tokenizer) – tokenizer that splits each string into the token set the similarity is computed over
op (operator) – comparison operator from the
operatormodule (ge,gt,le,lt); a pair is kept whensimilarity(index_col, search_col) op valholdsval (float) – the similarity threshold compared against
- class madmatcher_pro.delex.lang.predicate.CosinePredicate(index_col, search_col, tokenizer, op, val)¶
Bases:
SetSimPredicate- Parameters:
index_col (str) – the column in the indexed table to compare
search_col (str) – the column in the search table to compare against
tokenizer (Tokenizer) – tokenizer that splits each string into the token set the similarity is computed over
op (operator) – comparison operator from the
operatormodule (ge,gt,le,lt); a pair is kept whensimilarity(index_col, search_col) op valholdsval (float) – the similarity threshold compared against
- class madmatcher_pro.delex.lang.predicate.OverlapCoeffPredicate(index_col, search_col, tokenizer, op, val)¶
Bases:
SetSimPredicate- Parameters:
index_col (str) – the column in the indexed table to compare
search_col (str) – the column in the search table to compare against
tokenizer (Tokenizer) – tokenizer that splits each string into the token set the similarity is computed over
op (operator) – comparison operator from the
operatormodule (ge,gt,le,lt); a pair is kept whensimilarity(index_col, search_col) op valholdsval (float) – the similarity threshold compared against
- class madmatcher_pro.delex.lang.predicate.EditDistancePredicate(index_col, search_col, op, val)¶
Bases:
StringSimPredicate- Parameters:
index_col (str) – the column in the indexed table to compare
search_col (str) – the column in the search table to compare against
op (operator) – comparison operator from the
operatormodule (ge,gt,le,lt); a pair is kept whensimilarity(index_col, search_col) op valholdsval (float) – the similarity threshold compared against
- class madmatcher_pro.delex.lang.predicate.JaroPredicate(index_col, search_col, op, val)¶
Bases:
StringSimPredicate- Parameters:
index_col (str) – the column in the indexed table to compare
search_col (str) – the column in the search table to compare against
op (operator) – comparison operator from the
operatormodule (ge,gt,le,lt); a pair is kept whensimilarity(index_col, search_col) op valholdsval (float) – the similarity threshold compared against
- class madmatcher_pro.delex.lang.predicate.JaroWinklerPredicate(index_col, search_col, op, val, prefix_weight=0.1)¶
Bases:
StringSimPredicate- Parameters:
index_col (str) – the column in the indexed table to compare
search_col (str) – the column in the search table to compare against
op (operator) – comparison operator from the
operatormodule (ge,gt,le,lt); a pair is kept whenjaro_winkler(index_col, search_col) op valholdsval (float) – the similarity threshold compared against
prefix_weight (float, default 0.1) – weight of the common-prefix boost in the Jaro-Winkler score
- class madmatcher_pro.delex.lang.predicate.SmithWatermanPredicate(index_col, search_col, op, val, gap_cost=1.0)¶
Bases:
StringSimPredicate- Parameters:
index_col (str) – the column in the indexed table to compare
search_col (str) – the column in the search table to compare against
op (operator) – comparison operator from the
operatormodule (ge,gt,le,lt); a pair is kept whensmith_waterman(index_col, search_col) op valholdsval (float) – the similarity threshold compared against
gap_cost (float, default 1.0) – the gap cost used by the Smith-Waterman alignment
Table validation¶
- madmatcher_pro.delex.utils.checks.check_tables(table_a, id_col_table_a, table_b, id_col_table_b)¶
Check that table_a and table_b have valid id columns.
- Parameters:
table_a (sql.DataFrame) – The table A to be indexed.
id_col_table_a (str) – The column name of the id column in table A.
table_b (sql.DataFrame) – The table B to be searched.
id_col_table_b (str) – The column name of the id column in table B.
- Raises:
ValueError – If table_a or table_b do not have a valid id column.
Advanced: extension base classes¶
Subclass these only to write a custom predicate or rule. Most users compose the concrete predicates above and do not need them.
- class madmatcher_pro.delex.lang.predicate.Predicate¶
Bases:
ABCabstract base class for all Predicates to be used in writing blocking programs
- abstract property streamable¶
True if the predicate can be evaluated over a single partition of the indexed table, otherwise False
- abstract property indexable¶
True if the predicate can be efficiently indexed
- abstract property sim¶
The simiarlity used by the predicate
- abstract property is_topk: bool¶
True if the self is Topk based, else False
- abstractmethod build(for_search, index_table, index_id_col='_id', cache=None)¶
build the Predicate over index_table using index_id_col as a unique id, optionally using cache to get or set the index
- Parameters:
for_search (bool) – build the predicate for searching, otherwise streaming / filtering
index_table (pyspark.sql.DataFrame) – the dataframe that will be preprocessed / indexed
index_id_col (str) – the name of the unique id column in index_table
cache (Optional[BuildCache] = None) – the cache for built indexes and hash tables
- abstractmethod contains(other)¶
True if the set output by self is a superset (non-strict) of other
- Return type:
bool
- abstractmethod search_batch(queries)¶
perform search with queries return a dataframe with schema (id1_list array<long>, scores array<float>, time float)
- Parameters:
queries (Series)
- Return type:
DataFrame
- search(itr)¶
perform search_batch for each batch in itr
- Parameters:
itr (Iterator[Series])
- Return type:
Iterator[DataFrame]
- abstractmethod filter_batch(queries, id1_lists)¶
filter each id_list in id1_lists using this predicate. This is, for each query, id_list pair in zip(queries, id1_lists), return only the ids which satisfy predicate(query, id) for id in id_list. Return a dataframe with schema (id1_list array<long>, scores array<float>, time float)
- Parameters:
queries (Series)
id1_lists (Series)
- Return type:
DataFrame
- filter(itr)¶
perform filter_batch for each batch in itr
- Parameters:
itr (Iterator[Tuple[Series, Series]])
- Return type:
Iterator[DataFrame]
- abstractmethod init()¶
initialize the predicate for searching or filtering
- abstractmethod deinit()¶
release the resources acquired by self.init()
- abstractmethod index_size_in_bytes()¶
return the total size in bytes of all the files associated with this predicate
- Return type:
int
- abstractmethod index_component_sizes(for_search)¶
return a dictionary of file sizes for each data structure used by this predicate, if the predicate hasn’t been built yet, the sizes are None
- Parameters:
for_search (bool) – return the sizes for searching or for filtering
- Return type:
dict[Any, int | None]
- class madmatcher_pro.delex.lang.predicate.ThresholdPredicate(index_col, search_col, op, val)¶
Bases:
Predicate,ABC- Parameters:
val (float)
- class madmatcher_pro.delex.lang.predicate.SetSimPredicate(index_col, search_col, tokenizer, op, val)¶
Bases:
ThresholdPredicate- Parameters:
index_col (str) – the column in the indexed table to compare
search_col (str) – the column in the search table to compare against
tokenizer (Tokenizer) – tokenizer that splits each string into the token set the similarity is computed over
op (operator) – comparison operator from the
operatormodule (ge,gt,le,lt); a pair is kept whensimilarity(index_col, search_col) op valholdsval (float) – the similarity threshold compared against
- class madmatcher_pro.delex.lang.predicate.StringSimPredicate(index_col, search_col, op, val)¶
Bases:
ThresholdPredicate- Parameters:
index_col (str) – the column in the indexed table to compare
search_col (str) – the column in the search table to compare against
op (operator) – comparison operator from the
operatormodule (ge,gt,le,lt); a pair is kept whensimilarity(index_col, search_col) op valholdsval (float) – the similarity threshold compared against
- class madmatcher_pro.delex.lang.rule.Rule(predicates)¶
Bases:
objectBase class for a
DropRuleorKeepRule.- Parameters:
predicates (list of Predicate) – the predicates ANDed together to form the rule (a pair satisfies the rule only if it satisfies every predicate)
- contains(other)¶
return True if self logically contains other else False. That is, for any given set of record pairs C, self(C) is a superset of other(C)
- pretty_str()¶
format the rule into a pretty string
- Return type:
str