Defining Queries
Given these example indexers, it is straightforward to define queries, just use the self-explanatory API.
This query searches for persons called 'John', firstName is a static imported field from the class where we defined our indices before.
gigaMap.query(firstName.is("John"));
Conditions can be linked with and and or, respectively.
This one searches for all persons called 'John' or 'Jim'.
gigaMap.query(firstName.is("John").or(firstName.is("Jim")));
Or use the in condition instead.
gigaMap.query(firstName.in("John", "Jim"));
It is possible to compare to fixed values, but we can also use predicates. This enables us to use any custom logic inside query definitions if the predefined ones are not sufficient.
gigaMap.query(firstName.is(name -> name.length() > 3));
Negation is also supported with not and notIn.
// all persons NOT called 'John'
gigaMap.query(firstName.not("John"));
// all persons called neither 'John' nor 'Jim'
gigaMap.query(firstName.notIn("John", "Jim"));
Multi-Value Queries
When using an IndexerMultiValue, each entity can have multiple indexed values (e.g. a list of tags or interests). The standard query methods work on the individual values in the collection:
-
is(key)— matches entities whose collection contains that key -
in(k1, k2, …)— matches entities whose collection contains any of the given keys (OR) -
not(key)— matches entities whose collection does not contain that key -
notIn(k1, k2, …)— matches entities whose collection contains none of the given keys
// persons interested in SPORTS
gigaMap.query(interests.is(Interest.SPORTS));
// persons interested in SPORTS or LITERATURE (or both)
gigaMap.query(interests.in(Interest.SPORTS, Interest.LITERATURE));
Additionally, IndexerMultiValue provides the all method, which matches entities whose collection contains all of the specified keys (AND logic).
// persons interested in both SPORTS and LITERATURE
gigaMap.query(interests.all(Interest.SPORTS, Interest.LITERATURE));
Predicates also work with multi-value indexers. The predicate is applied to each key in the index.
// persons with any interest matching a custom condition
gigaMap.query(interests.is(interest -> interest.name().startsWith("S")));
Range Queries
Byte indexers and temporal indexers support range queries.
// assuming price is a ByteIndexerInteger
gigaMap.query(price.greaterThan(100));
gigaMap.query(price.lessThanEqual(50));
gigaMap.query(price.between(10, 100));
Range conditions can be combined with other conditions.
gigaMap.query(price.between(10, 100).and(category.is("Electronics")));
Sub-Queries
A GigaMap.SubQuery contributes a set of entity ids to a query. Any bitmap-backed GigaQuery, any Lucene or vector search result, and ad-hoc id sets are all sub-queries. Combining them lets a single query intersect across different index types.
Combining a GigaQuery with a Sub-Query
Use query.and(subQuery) to narrow a bitmap query by any other id source. The result is a GigaQuery — scores, if any, are dropped.
// Lucene full-text hits narrowed by a bitmap status condition
LuceneSearchResult<Article> hits = luceneIndex.search("content:eclipse", 100);
List<Article> published = gigaMap.query(status.is("PUBLISHED"))
.and(hits)
.toList();
// Vector similarity hits narrowed by a bitmap category condition
VectorSearchResult<Doc> hits = vectorIndex.search(queryVector, 50);
List<Doc> techDocs = gigaMap.query(category.is("tech"))
.and(hits)
.toList();
Narrowing a Scored Search Result
A ScoredSearchResult (vector or Lucene) is itself a sub-query, and also exposes its own and(SubQuery). Unlike the GigaQuery variant, this one keeps the scored iteration alive — the returned object is another ScoredSearchResult, preserving the original score-descending order on the surviving entries.
// Narrow from the scored side; keep iterating with scores afterwards
ScoredSearchResult<Article> top = luceneIndex.search("content:eclipse", 100)
.and(gigaMap.query(status.is("PUBLISHED")));
for(var entry : top)
{
System.out.println(entry.entity().title() + " (" + entry.score() + ")");
}
Combining Queries
A GigaQuery itself is a sub-query too, so two queries on the same GigaMap can be intersected directly.
GigaQuery<Person> adults = gigaMap.query(age.greaterThanEqual(18));
GigaQuery<Person> berliners = gigaMap.query(city.is("Berlin"));
long count = adults.and(berliners).count();
Combining with a Fixed Id Set
For ad-hoc id sets — a pre-computed allow-list, an external system, a test fixture — use EntityIdMatcher.Ascending(…). It takes a sorted (or to-be-sorted) array of entity ids and exposes it as a SubQuery.
EntityIdMatcher allowed = EntityIdMatcher.Ascending(42L, 58L, 91L);
List<Person> matches = gigaMap.query(firstName.is("John"))
.and(allowed)
.toList();
Sub-query combination is always a logical AND: an entity is part of the result only if it matches both sides. Multiple .and(…) calls chain: query.and(subA).and(subB) requires an entity to be present in the main query, subA, and subB.
|