NAME

AmberDB::Index::Facet - High-Performance Columnar Facet Indexing, Disjunctive Counting, and Menu Generation for AmberDB

SYNOPSIS

# Schema definition in your .table file:
{
    name         => "Özellikler ve Nitelikler",
    use_facet    => 1,
    use_junk     => 1,
    junk_rules   => [
        [ 5, "ne", 1 ],                      # Out-of-sale products are excluded from facet
        [ "2->14", "ne", 1 ],                 # Inactive manufacturer products are excluded
    ],
    facet_block  => [
        { blk => 1, id => "cat",    label => "Kategori",     table => "catalog_category",    name_idx => 2 },
        { blk => 2, id => "firm",   label => "Firma",        table => "catalog_producer",    name_idx => 2, filter_block => [ 14, "eq", 1 ] },
        { blk => 3, id => "auth",   label => "Yazar",        table => "catalog_contributor", name_idx => 2 },
        { blk => 4, id => "price",  label => "Fiyat Dilimi" },
        { blk => 5, id => "status", label => "Satış Durumu", required => 1 },
    ],
}

# Querying from AmberDB ($dbp inherits AmberDB::Index::Facet):

# 1. Standard full-catalog or filtered facet menu:
my $menu_data = $dbp->facet_menu("catalog_attributes", \%selected, \@facet_defs, \%opts);

# 2. Dynamic Scope facet menu (e.g. within search results or category scope):
my $search_facets = $dbp->facet_menu(
    "catalog_attributes",
    \%selected,
    \@facet_defs,
    { base_ids => \@search_result_ids }
);

DESCRIPTION

AmberDB::Index::Facet provides a column-oriented forward indexing and disjunctive facet aggregation engine designed for fast faceted navigation across large-scale catalogs.

KEY ARCHITECTURAL FEATURES

1. Columnar Per-Block Storage (_${blk}.fac)

Rather than maintaining a massive monolithic matrix file, facet data is stored in partitioned columnar forward index files: ${table_path}_${blk}.fac. Each file maps Record ID to packed value IDs (using binary or tab-separated representation), enabling fast single-column sequential scanning and random lookups.

2. Active-Only Storage Guarantee

Facet index files store only currently active records. Inactive, discontinued, or junk records are automatically filtered out during index creation and mutation via facet_rules (which integrates with junk_rules). This eliminates the overhead of scanning 100K+ historical records when computing facet counts.

3. Bidirectional String Dictionary (_${blk}.str)

Non-relational string facets (e.g. colors, features) are indexed into a bidirectional .str dictionary with distinct key namespaces:

  • s:StringValue -> NumericID (Fast write/read conversion)

  • n:NumericID -> StringValue (Fast reverse label resolution)

  • lastid -> Auto-increment sequence tracker

4. Dynamic Scoping (base_ids)

When faceted menus are displayed on search result pages or narrow category listings, callers pass base_ids => \@ids. The engine processes only the scoped record IDs, bypassing entire-database iteration.

5. Multi-Select Disjunctive Faceting (OR-within-block, AND-across-blocks)

Supports multi-selection where checking multiple items within the same filter group uses OR logic (showing count of remaining options), while combining across different filter groups uses AND logic.

METHODS

facet_rules($table_info, @record)

Evaluates whether a record qualifies for inclusion in facet index files. Automatically delegates to !junk_rules if use_junk is enabled on the table.

facet_add($table_path, $table_info, \@records)

Indexes active records into per-block _${blk}.fac files.

facet_modify($table_path, $table_info, \@pairs)

Handles automated index updates and active/passive transitions during record updates.

facet_del($table_path, $table_info, \@records)

Removes deleted records from all per-block _${blk}.fac files.

field_fltkeys($tableid, \%opts)

Calculates facet key counts for target block directly from active _${target_block}.fac. Automatically translates numeric dictionary IDs to human-readable strings via .str.

field_allfltkeys($tableid, \@blk_list, \@base_scope)

Calculates facet key counts across multiple active block files in a single pass.

facet_menu($tableid, \%selected, \@facet_defs, \%opts)

High-level menu builder. Performs: 1. Active filtering intersection via field_filter. 2. Disjunctive per-group count calculations. 3. Top-N limiting and sorting (by count or label). 4. Label resolution via RDBM, bidirectional .str, or schema options.

AUTHOR

Maruf Cetin <marufcetin@gmail.com>

LICENSE AND COPYRIGHT

Copyright (C) 2020-2026 Maruf Cetin.

This library is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.