AmberDB

 view release on metacpan or  search on metacpan

lib/AmberDB/Base/Facet.pm  view on Meta::CPAN

                    for my $val (@vals) {
                        my $text = $res->{"$blk:n:$val"};
                        if ( defined $text && $text ne '' ) {
                            $name_map{$val} = $text;
                        }
                    }
                }
            }

            # Şema option alanı fallback'i (örn: "1:Satışta,0:Satış Dışı")
            my $opt_str = $table_info->{blocks}->[$blk]->{option} // '';
            if ($opt_str) {
                for my $pair ( split /,/, $opt_str ) {
                    my ( $v, $l ) = split /:/, $pair, 2;
                    $name_map{$v} //= $l // $v;
                }
            }
        }

        # Active status for this block
        my %selected_vals = map { $_ => 1 } @{ $active_filter{$blk} // [] };
        my $active_cnt    = scalar keys %selected_vals;
        $active_counts{$blk} = $active_cnt;

        my @items;
        for my $val (@vals) {
            push @items, {
                uid     => "fc_${blk}_${val}",
                param   => "f$blk",
                val     => $val,
                label   => ( $name_map{$val} // $val ),
                count   => ( $counts->{$val} // 0 ),
                checked => ( $selected_vals{$val} ? "1" : "" ),
            };
        }

        my $group_data = {
            blk          => $blk,
            name         => $label,
            active       => ( $active_cnt ? "1" : "" ),
            active_count => $active_cnt,
            records      => \@items,
        };

        push @groups, $group_data;
        $groups_by_blk{$blk} = \@items;
    }

    my $res = {
        count         => $total_count,
        ids           => $filtered_ids,
        groups        => \@groups,
        groups_by_blk => \%groups_by_blk,
        active_counts => \%active_counts,
        counts        => \%all_counts,
    };

    return wantarray ? @groups : $res;
}

=encoding utf8

=head1 NAME

AmberDB::Index::Facet - Column-oriented facet indexing, disjunctive counting, and navigation menu generator

=head1 SYNOPSIS

  # Querying from AmberDB instance ($adb inherits AmberDB::Index::Facet):

  # 1. Generate full-catalog or filtered facet menu with disjunctive counts:
  my $menu_data = $adb->facet_menu(
      "catalog_product",
      { 1 => "5", 2 => [ "12", "14" ] }, # %selected_filters
      \@facet_block_definitions,
      { sort => 'count', top => 10 }      # %options
  );

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

  # 3. Direct facet key counts for a single block:
  my $counts = $adb->field_fltkeys("catalog_product", {
      target_block => 2,
      base_ids     => \@active_product_ids,
  });

=head1 DESCRIPTION

C<AmberDB::Index::Facet> provides a high-performance, column-oriented forward indexing and disjunctive facet aggregation engine designed for low-latency faceted navigation across large-scale catalogs.

B<Inheritance Note:> C<AmberDB> inherits from C<AmberDB::Index::Facet> via C<use parent>. All facet query and menu methods documented below are invoked directly on C<$adb>.

=head1 KEY ARCHITECTURAL FEATURES

=over 4

=item * B<1. Columnar Unified Storage (C<$table_path.fac>):> Facet data is stored in a unified columnar forward index file (C<$table_path.fac>). Each record's block values are keyed as C<$blk:$rid> mapping to packed value IDs, enabling fast single-co...

=item * B<2. Active-Only Storage Guarantee:> Facet index files store B<only currently active records>. Inactive, discontinued, or out-of-stock records violating C<facet_rules> / C<junk_rules> are excluded during indexing, eliminating the overhead of ...

=item * B<3. Bidirectional String Dictionary (C<.unq>):> Text facets (e.g. colors, specifications) map transparently between string labels and compact numeric dictionary IDs.

=item * B<4. Dynamic Scoping (C<base_ids>):> When computing facet counts within search results or subcategories, passing C<base_ids =E<gt> \@ids> bounds the aggregation strictly to matching records.

=item * B<5. Multi-Select Disjunctive Faceting:> Supports multi-selection where checking multiple items within the same filter group uses OR logic (showing counts of remaining options), while combining across different filter groups uses AND logic.

=back

=head1 METHODS

=head2 facet_menu($tableid, [\%options])

High-level faceted navigation menu generator.

Options:



( run in 0.627 second using v1.01-cache-2.11-cpan-364913b4093 )