feat: queryAggregate() + HAVING, plus aggregate backfill, traversal depth/via, extraction typing (BR-ADV-FEATURES-BUN)
New report APIs:
- brain.queryAggregate(name, params) returns the clean AggregateResult[] shape
({ groupKey, metrics, count }) directly, instead of the search-Result wrapper that
find({ aggregate }) returns.
- HAVING: find({ aggregate, having }) and queryAggregate filter groups by computed
metric values (e.g. revenue > 1000), complementing where (which filters group keys).
Evaluated per group: O(groups), independent of entity count.
Fixes (all reproducible on Node; surfaced under Cortex+Bun by Memory):
- Aggregate backfill-on-define: defining an aggregate over a store that already holds
matching entities returned []. It now backfills from existing entities on first query
(storage-agnostic via getNouns), so it works under durable backends that reopen
pre-populated. groupBy:['noun'] resolves to the entity type; find({ aggregate }) rows
expose groupKey/metrics/count at the top level.
- Multi-hop find({ connected: { depth, via } }) honors depth and via at every hop
(was 1-hop only, with verb filtering applied to hop 1 only); BFS bounded by limit.
- extractEntities no longer bleeds a neighbour's type indicator across candidates; each
candidate is typed by its own span. Also fixes the "Dr." title pattern.
Adds real-embedding regression tests; full unit suite green.
This commit is contained in:
parent
513186d951
commit
1a98e4276a
9 changed files with 481 additions and 96 deletions
|
|
@ -30,12 +30,11 @@ const brain = new Brainy()
|
|||
await brain.init()
|
||||
|
||||
// Extract all entities
|
||||
const entities = await brain.extractEntities('John Smith founded Acme Corp in New York')
|
||||
// Returns:
|
||||
const entities = await brain.extractEntities('Sarah Chen founded Acme Corp')
|
||||
// Returns (fast pattern + embedding ensemble; confidences are approximate):
|
||||
// [
|
||||
// { text: 'John Smith', type: NounType.Person, confidence: 0.95 },
|
||||
// { text: 'Acme Corp', type: NounType.Organization, confidence: 0.92 },
|
||||
// { text: 'New York', type: NounType.Location, confidence: 0.88 }
|
||||
// { text: 'Sarah Chen', type: NounType.Person, confidence: 0.68 },
|
||||
// { text: 'Acme Corp', type: NounType.Organization, confidence: 0.85 }
|
||||
// ]
|
||||
|
||||
// Extract with filters
|
||||
|
|
@ -46,6 +45,17 @@ const people = await brain.extractEntities('...', {
|
|||
})
|
||||
```
|
||||
|
||||
> **What this is (and isn't).** `extractEntities` is a fast, dependency-free **heuristic
|
||||
> ensemble** (regex/pattern + type-embedding similarity + context), not a trained NER model.
|
||||
> Each candidate is typed by its own span — a type indicator in a neighbour's text (e.g. "Corp"
|
||||
> in "Sarah Chen founded Acme Corp") will **not** bleed onto another candidate.
|
||||
>
|
||||
> **Known limitation:** a bare proper-noun place name with no structural cue (e.g. "New York",
|
||||
> no comma, state code, or "in"/"at" preposition handling) can be typed as `Person` by the
|
||||
> generic full-name pattern. For high-precision typing, pass `types` to constrain results, supply
|
||||
> richer context, or post-validate. For state-of-the-art NER, drive extraction from an LLM at the
|
||||
> application layer and store the results in Brainy.
|
||||
|
||||
### Method 2: Direct Import (Advanced)
|
||||
|
||||
```typescript
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue