Loading Data
const everyone = await gom.loadAll(PersonCareer);const one = await gom.load(PersonCareer, uuid); // undefined when there is noneconst open = await gom.loadAll(Issue, (q) => ({ where: q.state.eq('open') }));const raw = await gom.loadAll(Issue, 'n.state = $state', { state: 'open' }); // a predicate of your own, over ncount counts exactly what loadAll would return for the same type and filter:
await gom.count(Issue);await gom.count(Issue, (q) => ({ where: q.state.eq('open') }));await gom.count(RaisedAndAssignedIssue); // only the issues that meet the view's required relationshipsA fragment is counted by its labels. A view counts only the roots that meet its required relationships and paths, so
the number equals loadAll(...).length, not a count of nodes.
Vector Search (loadNearest)
Section titled “Vector Search (loadNearest)”loadNearest runs an approximate nearest-neighbour search and returns each hit with a similarity score. It works on a
view, by its root’s embedding, and on a fragment:
@NodeFragment({ labels: ['Proposition'] })export class PropositionNode { @NodeId() id: string; text: string; @VectorIndex({ similarity: 'COSINE' }) embedding?: number[];}
const hits: Scored<PropositionView>[] = await gom.loadNearest(PropositionView, queryEmbedding, { topK: 20 });hits.forEach((it) => console.log(it.score, it.value.proposition.text));The searched embedding is the fragment’s @VectorIndex field: inferred when there is one, and named with property
when there are several. The score is a similarity, higher meaning more similar, on every engine, so threshold means
the same thing everywhere.
| Option | Meaning |
|---|---|
topK |
How many to return. Without searchK, also how many the index is asked for. |
searchK |
How many the index is asked for, at least topK. topK then trims after the filter. |
threshold |
The least score a hit may have. |
where |
A condition applied after the search: references, or a predicate over n with bindings. |
partitionLabel |
Search the index of another label over the same property: one index per corpus or tenant. |
property |
Which @VectorIndex field, when the fragment has several. |
depth |
maxDepth overrides for a view. |
topK is the index’s k, not a promised count. A view’s required relationships, threshold and where filter
after the search, so a search can return fewer than topK.
k is also the search’s beam. On Lucene-backed engines the result queue is the HNSW candidate queue, so a small
k can miss a vector that really is nearest. searchK widens the search without widening the result:
// search with a beam of 200, and return the best 40 that pass the filterawait gom.loadNearest(PropositionView, queryEmbedding, { topK: 40, searchK: 200, where: (q) => [q.proposition.contextId.eq(ctx), q.mentions.any((m) => m.resolvedId.eq(entityId))]});A filtered search dilutes: at 22% selectivity, 40 asked for returns about 9, the nearest overall that happen to pass
rather than the nearest of those that pass. searchK mitigates that. A per-partition index avoids it: with one vector
index for each partition label, partitionLabel searches inside the partition, which is filtered by construction.
Full-Text Search (loadMatching)
Section titled “Full-Text Search (loadMatching)”loadMatching is the full-text mirror of loadNearest. The relevance is scaled to [0, 1], the best hit being 1:
@NodeFragment({ labels: ['Chunk'] })export class ChunkNode { @NodeId() id: string; @FullTextIndex() text: string;}
await gom.loadMatching(ChunkNode, 'graph databases', { topK: 20 });await gom.loadMatching(ChunkView, 'graph databases', { topK: 20, threshold: 0.5, where: (q) => q.chunk.sectionId.eq('s1') });The index is the fragment’s @FullTextIndex: on a property for one field, or on the class,
@FullTextIndex({ properties: ['title', 'body'] }), for several. Name one with property when the fragment declares
more than one. The text is the engine’s full-text language (Lucene on Neo4j): escape user input yourself.

