Index Types

The GigaMap’s bitmap index supports various index types.

"Normal" Index

This is just a standard index that can include duplicate values. In fact, this is the most efficient type, as the bitmap index can compress this dataset and minimize memory overhead.

// use the builder
final GigaMap<Person> gigaMap = GigaMap.<Person>Builder()
    .withBitmapIndex(PersonIndices.firstName)
    .withBitmapIndex(PersonIndices.lastName)
    ...
    .build();

// or register it after creating
GigaMap<Person> gigaMap = GigaMap.New();
gigaMap.index().bitmap().ensure(PersonIndices.firstName);
gigaMap.index().bitmap().ensure(PersonIndices.lastName);
...

Unique Index

Index with a unique constraint.

// use the builder
final GigaMap<Person> gigaMap = GigaMap.<Person>Builder()
    .withBitmapUniqueIndex(PersonIndices.id)
    ...
    .build();

// or register it after creating
GigaMap<Person> gigaMap = GigaMap.New();
gigaMap.index().bitmap().addUniqueConstraint(PersonIndices.id);
...

Identity Index

An identity index is used exclusively to identify an entity within the GigaMap. It can consist of one or more indexers.

When looking up or removing entities, the GigaMap doesn’t traverse all data, as that would be too inefficient. Instead, it creates an internal query based on the identity index definitions to look up entries. If no identity index is provided, a compound one will be created using all standard indices.

An identity index is not a unique index. It only defines which fields are used to identify entities — it does not enforce uniqueness. If you need to ensure that no two entities share the same identity value, you must add a unique constraint separately.
// use the builder
final GigaMap<Person> gigaMap = GigaMap.<Person>Builder()
    .withBitmapIdentityIndex(PersonIndices.id)
    ...
    .build();

// identity index with unique constraint
final GigaMap<Person> gigaMap = GigaMap.<Person>Builder()
    .withBitmapIdentityIndex(PersonIndices.id)
    .withBitmapUniqueIndex(PersonIndices.id) // enforce uniqueness at runtime
    ...
    .build();

// or register it after creating
GigaMap<Person> gigaMap = GigaMap.New();
final BitmapIndices<E> bitmap = this.gigaMap.index().bitmap();
bitmap.ensure(PersonIndices.id); // add index first
bitmap.setIdentityIndices(PersonIndices.id); // set as identity
bitmap.addUniqueConstraint(PersonIndices.id); // enforce uniqueness
...

Binary Index

A special bitmap index designed for high cardinality.

This index exclusively stores long values.

Each long-bit corresponds to an entry, meaning there will be 64 entries max, no matter how high the cardinality becomes.

Currently it only supports equality queries. Range queries are not supported yet.

Zero and Negative Values

All binary indexers support zero and negative values. Internally, each indexer maps the key to a non-zero long representation because the bitmap index uses bit positions as array indices, and a value of 0L would have no bits set.

For sub-64-bit types (Byte, Short, Integer, Float), this mapping is collision-free — no two distinct keys ever map to the same internal representation.

BinaryIndexerLong uses Long.MAX_VALUE as the internal representation for zero. As a consequence, Long.MAX_VALUE is not supported as an index key and will throw an IllegalArgumentException. All other long values are fully supported.

Byte Index

A composite bitmap index designed for high cardinality numeric types with range query support.

It decomposes numbers into individual bytes (base 256) and stores each byte position as a separate sub-index with at most 256 entries. This uses the same composite index infrastructure as IndexerLocalDate (which decomposes into year/month/day).

Byte indexers support both equality and range queries: is, not, in, notIn, lessThan, lessThanEqual, greaterThan, greaterThanEqual, and between.

// use the builder
final GigaMap<Product> gigaMap = GigaMap.<Product>Builder()
    .withBitmapIdentityIndex(ProductIndices.price)
    .build();

// query with range conditions
gigaMap.query(ProductIndices.price.between(10, 100));
gigaMap.query(ProductIndices.price.greaterThan(50));

Use byte indexers when you need range queries on numeric types with high cardinality. Use binary indexers when you only need equality queries.

Choosing Between Regular, Binary, and Byte Indexers

The bitmap index offers three families of indexers: regular indexers (e.g. IndexerString, IndexerLong), binary indexers (e.g. BinaryIndexerString, BinaryIndexerLong), and byte indexers (e.g. ByteIndexerInt, ByteIndexerLong). The right choice depends on your data characteristics and query needs.

Comparison

Aspect Regular Indexer Binary Indexer Byte Indexer

Cardinality

Low to medium (few distinct values, many entities per value)

High (many distinct values, few entities per value)

High (many distinct values, few entities per value)

Query types

Equality (is, in), predicates (is(predicate)), and - depending on the index type - range queries

Equality only (is, in)

Equality (is, in, not, notIn) and range queries (lessThan, greaterThan, between, etc.)

Key type

Any object with equals/hashCode

Must convert to long

Numeric types and Instant

Memory

On-heap hash table

Off-heap bit-position array

Composite sub-indices with at most 256 entries per byte position

Null values

Native support

Requires sentinel value handling

Requires sentinel value handling

Use Regular Indexer When

  • Indexed values have low cardinality — few distinct values shared by many entities (enums, categories, status fields)

  • You need predicate-based queries, e.g. firstName.is(name → name.startsWith("J"))

  • You need range queries via IndexerComparing

  • The key type does not naturally map to long

Typical use cases: enumerations, boolean flags, date/time fields, categories, multi-value fields

Use Binary Indexer When

  • Indexed values have high cardinality — many distinct values (unique IDs, foreign keys)

  • Only equality queries are needed (is, in)

  • The key can be efficiently converted to long (numeric IDs, TSID, UUID)

  • Memory efficiency matters for large datasets

Typical use cases: primary/foreign key indices, UUIDs, TSIDs, unique codes or reference numbers

Use Byte Indexer When

  • Indexed values have high cardinality — many distinct values

  • You need range queries (lessThan, greaterThan, between, etc.) on high-cardinality data

  • The key is a numeric type or Instant

  • You want the benefits of bitmap indexing for high-cardinality fields without sacrificing range query support

Typical use cases: prices, quantities, timestamps (as Instant), scores, measurements, or any numeric field that requires both high-cardinality support and range filtering