Querying ontology data
Ask Chat questions about your structured data — ontology object types backed by data sources answer lookups, filters, and summaries directly in the conversation.
Chat can answer questions about your organization's structured data — any ontology object type backed by a data source (incident reports, installations, observations, sensor readings, …). Ask in natural language; Chat discovers what data exists, filters it, and summarizes the matching records.
Queryable data requires an ontology object type with a silver_table binding to a live data source. Both usually ship together in a pack. See Authoring: Ontologies for how to declare bindings.
How it works
Four chat tools work together:
ontology_list_types— discovers the queryable surface: every object type across your readable ontologies that is backed by a data source. Chat calls this first when it doesn't know what data is installed.ontology_query— fetches matching records for one or more object types, with optional filters and a row limit. Chat then reasons over the returned rows to answer your question.ontology_search— hybrid search: an LLM translates the question into a structured ontology query (including relationship traversals — see below) while a keyword grep runs alongside it; results are merged with provenance tags.ontology_neighbors— walks the ontology graph one hop from a known record: everything linked to it, with the relationship name and direction.
No configuration is required — installing a pack that ships data sources and an ontology makes its object types queryable immediately.
Asking questions
Ask Chat naturally. Examples that trigger a data query:
- "How many critical drone incursions were detected this month?"
- "List the defense installations in Estonia"
- "Which incidents mention GPS jamming? Summarize the latest three."
- "Compare incursion counts per country since June 1st"
For geospatial questions ("show them on a map"), Chat uses the map visualization tool instead — the two compose: ask for a filtered summary first, then "plot those on a map".
Following relationships
Ontologies declare link types between object types (a unit operates a UAV, an incident references an installation). Chat uses them two ways:
- Relational questions in one shot — "which UAVs does Falcon Squadron operate?" translates into a search that filters one type through its relationship to another. This works for any reference link whose link type declares a join rule (
join: { sourceColumn, targetColumn }ondefineLinkType); links without a join rule are reported back honestly ("this link needs a join rule") instead of silently returning unrelated keyword matches. - Exploring from a known record — after any query or search result, Chat can ask for the record's neighbors: every linked instance, the relationship it came through, and its direction. Follow-up questions like "what else is connected to that installation?" resolve this way.
Listing questions that name a type directly — "print me all my drone observations" — also resolve through the ontology: when your question names one of the ontology's types, search returns that type's instances as structured matches rather than falling back to keyword hits. Relationship questions that would need two hops (X observed as O, O near Y) are answered one hop at a time; when a single search can't express the chain, the answer says so explicitly instead of returning an empty result.
Both paths run over the same governed reads as everything else — masked columns and clearance filtering apply before any linking happens.
Watches and detections
A watch is a standing detection rule in your ontology — for example an air build-up watch that fires when enough distinct aircraft roles gather over an area of interest within a time window (see Authoring: Watch rules). Two tools let Chat answer questions about them:
ontology_watches— lists the watches you are cleared to read: slug and name, whether it is enabled, the area it covers, its time window, what makes it fire (minimum distinct roles and score, or for a gone-quiet watch the minimum number of entities that stopped reporting plus any role or score minimum it also sets), its role weights and saturation cap, its suppression rules and the detection type it emits.ontology_watch_detections— the latest detections, newest first, for one watch or all of them: when each fired, its score, the distinct roles present, how many points each role added to the score (the same per-role breakdown the Analytics detection review shows) and whether that breakdown accounts for the whole score, the contact count, the area and the rule the watch fires on. For a watch with no detections it states that rule, so "why has it not fired?" is answered from the watch itself. Up to 20 per answer (Chat defaults to 10). Chat reads up to 200 detections of each detection type, oldest first; when a type has reached that many, Chat says so, does not call any detection the latest and does not say that a watch of that type has not fired, because newer ones may not have been read.
Examples:
- "What watches are we running, and which are enabled?"
- "How does the Kaliningrad build-up watch decide to fire?"
- "Has anything been detected in the last day? Show the latest detections."
- "When did the build-up watch last fire, and which roles were present?"
- "Which roles contributed to the latest build-up detection, and how much did each add to the score?"
- "Why hasn't the build-up watch fired?"
A detection's individual contributing contacts (callsigns, positions) are not returned in chat — open the detection in Analytics, where the governed read shows them subject to your clearance. The per-role breakdown is computed from the contacts returned with the detection; when none were returned, Chat says so instead of showing a breakdown. A detection keeps at most 64 of its contacts, highest weight first: when it counted more, Chat says the breakdown comes from that sample, and when the breakdown does not add up to the recorded score — the sample left scoring contacts out, or the watch's weights changed since it fired — Chat gives it as part of the score, not the reason the watch fired. If two ontologies define a watch with the same name and detection type, a detection does not record which of them fired it, so Chat does not break it down by either watch's weights — even when your question names one of those ontologies — and the Analytics detection review names both watches instead of showing a per-role breakdown.
An empty answer states each watch's rule and never takes the silence as proof that nothing happened: a disabled watch is not evaluated, a detection marked above your clearance is not shown to you, a watch records a detection only when it is evaluated, and it sees only the records of its target type that reach the ontology (sources such as ADS-B are cooperative) — for a gone-quiet watch, only an entity that was reporting before it went quiet.
Filters
Chat translates your question into filter clauses, combined with AND:
| Operator | Meaning |
|---|---|
eq / neq | Exact (in)equality, tolerant of string/number representations |
contains | Case-insensitive substring match |
gt / gte / lt / lte | Numeric comparison when both sides are numbers; otherwise lexicographic — ISO-8601 timestamps compare correctly |
in | Matches any value in a list of strings or numbers, with the same tolerance as eq |
Result limits
Responses are kept compact so the conversation stays fast:
- Up to 100 rows per object type per query (Chat defaults to 25).
- Long text fields are trimmed in tool results.
- When more records match than are shown, Chat is told the honest totals ("Found 70 incursions. Showing the first 25.") so it can refine the filter or aggregate instead of guessing.
Access control
Queries run under your workspace scope: only ontologies readable in your workspace are searched, and rows come from the same governed projection that powers the rest of the platform — there is no side channel to the underlying tables. Watches and detections follow the same rule: a watch or detection above your clearance is simply not returned.