Dr. Estera Kot

From Events to Answers · Part 2 of 7

Real-Time Intelligence in plain words: the path of one event

Five parts, one job each: how one tester's vote travels from a booth to an Activator alert in Microsoft Fabric.

By Dr. Estera Kot, CTO at Clouds on Mars and former Microsoft Principal Product Manager for the Apache Spark runtime in Fabric. Published . Product facts checked against Microsoft Learn on November 3, 2026.

In short

  1. Real-Time Intelligence is the Microsoft Fabric workload for data in motion. It has five parts with one job each: the event, Eventstream, Eventhouse, the Real-Time Dashboard, and Activator.
  2. The dashboard is for people. The rule is the product. In the demo, an Activator rule watched the running share, so nobody had to watch the chart.
  3. Design the event first. One flat JSON line carries a time, a trial ID, and a two-value choice. That shape kept the calculation in one short function.
  4. A rule without a minimum sample fires on noise. The demo rule waits for 20 testers, then fires once above 60.
  5. “Real time” here means within one minute: Activator read a KQL function every 60 seconds. The Learn default is 5 minutes.
The path of one event: five stops, one job each A route map. The main line runs from the event at a sampling booth, through Eventstream and Eventhouse, to Activator, which sends one email. A branch leaves the Eventhouse for the Real-Time Dashboard, the view for people. Each stop carries its one job and its item in the demo. The segments carry the timing: one event every 24 seconds, a query every 60 seconds, and a dashboard refresh every 30 seconds. Event Eventstream Eventhouse Activator Records one fact with a time Carries events in Stores events, computes the share Watches the share and acts simulate_trial_events.py es_blotter, source booths eh_oud, table blotter_events Winner alert, one email every 24 seconds into blotter_events query every 60 seconds 1 2 3 4 5 Real-Time Dashboard Shows people the share Live blotter test, 30 s refresh Main line: the path to an action Branch: a view for people The path of one event: five stops, one job each A vertical route map. The main line runs down from the event, through Eventstream and Eventhouse, to Activator, which sends one email. A branch leaves the Eventhouse for the Real-Time Dashboard, the view for people. Each stop carries its one job, its item in the demo, and its timing. Event Eventstream Eventhouse Real-Time Dashboard Activator Records one fact with a time Carries events in Stores events, computes the share Shows people the share Watches the share and acts simulate_trial_events.py, every 24 s es_blotter, source booths eh_oud, table blotter_events Live blotter test, 30 s refresh Winner alert, query every 60 s 1 2 3 4 5 Main line: the path to an action Branch: a view for people
Figure 1. The path of one event in the demo. The main line ends in an action. The dashboard sits on a branch, because it serves people who choose to look. Item names and timings come from the session kit and the exported item definitions.

What is Real-Time Intelligence in Microsoft Fabric

Real-Time Intelligence is the Microsoft Fabric workload for data in motion. It takes events in and keeps them in a database built for time. It shows them on live dashboards and acts on them with rules. Microsoft Learn says it reacts to events as they happen, instead of running on a schedule. For a beginner, it is five parts with one job each.

Dr. Kot taught it this way at a community session in Doha, described in Part 1, the overview. This part follows one event through all five parts, from a booth to an email.

The story: an oud fragrance house retests formula OB-106, Oud Daylight, with 40 testers at a launch evening. Each tester smells two paper strips, called blotters. One carries the new formula, the test. The other carries the current formula, the reference. The tester reaches for one first. In the earlier study ST-15, OB-106 reached 53 percent first choice. The business calls a formula a winner above 60 percent.

  1. Part and its one jobIn the demoStatus
  2. 1EventRecords one fact with a time.One JSON line per tester, ten fields, from simulate_trial_events.pyNot a Fabric item
  3. 2EventstreamCarries events in.es_blotter, custom endpoint source booths, destination blotter_eventsGA
  4. 3Eventhouse and KQL databaseStores events and computes the number.eh_oud, table blotter_events, functions running_share() and activator_state()GA
  5. 4Real-Time DashboardShows the number to people.Live blotter test: the running share with a line at 60, refreshed every 30 secondsGA Copilot generation TBC
  6. 5ActivatorWatches the number and acts.Winner alert: reads activator_state() every 60 seconds, one email per trialGA
Figure 3. Five parts, one job each. Statuses as checked on Microsoft Learn on November 3, 2026. Learn shows no preview label for Eventstream, Eventhouse, or the Real-Time Dashboard. Activator became generally available in November 2024. Copilot dashboard generation is explained below.

What an event is, and why you design it first

An event is one small fact that just happened, with a time stamp. In the demo, one event means one tester finished one paired blotter test. The booth sends one line of JSON with ten fields. Forty testers send forty events. Every later part reads these ten fields, so their shape decides how simple the rest of the build stays.

Here is tester 1, with the example time from the session design:

{
  "event_time": "2026-10-14T18:45:12+03:00",
  "study_id": "ST-16", "trial_id": "TR-2008", "formula_id": "OB-106",
  "tester_id": "T-001", "booth_id": "BOOTH-1", "panel_site": "Panel C",
  "first_choice": "reference",
  "dwell_test_s": 63.0, "dwell_reference_s": 101.8
}

Read as a sentence: at 6:45 PM, tester T-001 at booth 1 reached for the reference blotter first. The tester held the test blotter for 63.0 seconds and the reference for 101.8. It is one vote for the current formula.

IDFieldExampleWhy the field is there
V1event_timeLocal time with offsetOrders the events. The terminal and the wall clock show the same time.
V2study_id, trial_id, formula_idST-16, TR-2008, OB-106The keys. Activator follows each trial by trial_id. The formula ID links to the tables in Part 3.
V3tester_id, booth_id, panel_siteT-001, BOOTH-1, Panel CWho and where. The tester ID breaks ties when two events share a second.
V4first_choicetest or referenceThe only value the share needs.
V5dwell_test_s, dwell_reference_s63.0, 101.8Seconds with each blotter. Context for people, not used by the rule.

Dr. Kot's position: design the event before any Fabric item exists. Three choices keep every later step short. The event is flat, so it maps to one table row without parsing. The choice is a two-value text, so the share is one count divided by another. Every event carries the trial ID, so the rule can follow each trial on its own.

The design to avoid is a device that sends a total instead of the fact. A booth that sends “share so far: 58 percent” hides the votes. One lost or repeated message then breaks the total, and the Eventhouse cannot recompute it. Send the raw fact. Compute the number in one place.

Eventstream: the pipe, with a custom endpoint

An Eventstream is the Fabric item that carries events in. It receives events from sources and routes them to destinations without code. The demo stream, es_blotter, had one source, a custom endpoint called booths, and one destination, the table blotter_events. Learn notes that an Eventstream does not store data permanently. It passes events on.

A custom endpoint is the source for your own application. Learn says it gives you a connection string in Event Hubs format, with AMQP and Kafka as other options. The demo script used the Event Hubs format and one Python package, azure-eventhub.

Treat that connection string as a password, because it carries a shared access key. Keep it in an environment variable, never on a slide or in a repository.

Eventhouse and KQL database: where the number comes from

An Eventhouse is a database built for events. Learn says it organizes data by the time it arrived, so questions about recent data stay fast. One Eventhouse holds one or more KQL databases, and each database holds tables. The demo had one Eventhouse, eh_oud, with one table, blotter_events. Two saved functions turn its rows into the number the business cares about.

The first function, running_share(), is for the dashboard. It sorts events by time, then by tester ID. For each tester it counts testers so far and test votes so far. It divides one by the other and rounds to one decimal. After a full run it returns 40 rows, and the last one shows 65.0.

The second function, activator_state(), is for the rule. It reads running_share() and keeps only the latest row for each trial. It drops that row while fewer than 20 testers are counted. It returns at most one row per trial. Here it is, only to show where the number comes from:

running_share()
| summarize arg_max(n_testers, *) by trial_id
| where n_testers >= 20
| project trial_id, formula_id, n_testers, first_choice_pct

The summarize line keeps the latest row. The where line is the minimum-count guard. The guard lives in the query, not in the rule.

The rule cannot read running_share() directly. Learn explains that Activator runs a KQL query on a schedule and turns every returned row into an event. It stamps each event with the time of the run, not a time from the data. So the query must return the current state. The full running share would hand the rule 40 events on every run.

Real-Time Dashboard: built by Copilot from one sentence

A Real-Time Dashboard is a page of tiles. Each tile runs a KQL query on an Eventhouse and refreshes as new data arrives. In the session design, Copilot builds the dashboard from one sentence typed on the Eventhouse page. The sentence names the function, the measure, and the line at 60. Copilot writes the queries and picks the visuals.

“Show the running first choice share per trial over time from the running_share view, with a line at 60.”

Name the function in the prompt. From the raw table, Copilot may chart a count of events instead of a share.

Copilot generation status: TBC. The Learn release status page lists Generate a real-time dashboard as GA. The how-to page carries no label. In a recorded FabCon recap demo, the Copilot pane showed a Preview label. The Copilot for Real-Time Intelligence post shows that demo and tracks the status.

The requirements on Learn are firm. Copilot needs a paid F2 or P1 capacity or larger, never a trial, and the Copilot tenant setting. Outside the US and EU, Copilot is off until an admin allows processing outside the capacity's region. In Qatar, plan that conversation before the project starts.

The kit also carried a fallback dashboard, built through the API before the session. It had three tiles: the running share with a line at 60, the share now, and the testers so far. It refreshed every 30 seconds. On stage, Copilot built the dashboard live, so the fallback was not needed. Learn now describes Live refresh, on by default for new dashboards, which updates a tile when new data lands.

A dashboard needs a person who looks at it. Nobody at a launch evening watches a chart for 16 minutes.

Activator: the rule is the product

Activator is the Fabric item that watches data and acts when a condition is met. According to Learn, it can send an email or a Teams message. It can also start a Power Automate flow or a Fabric item. The demo rule in plain words: when first choice goes above 60 with at least 20 testers, send a message. It sends one email per trial.

Dr. Kot's position: the dashboard serves people who want to see the trend. The rule is the product, because it turns the trend into an action at the right moment, with nobody watching.

Here is the rule as built, read from its exported definition. The source is the function activator_state() in eh_oud, run every 60 seconds. The object is Trial, keyed by trial_id, with two attributes, first_choice_pct and n_testers. The condition is “becomes greater than 60.” The action is an email with the subject “Winner: a formula passed 60 percent first choice.”

The condition type decides whether the rule fires once or every minute. Learn describes two ways to alert on a KQL query. The “on each event” method alerts for every returned row on every run. A Numeric change condition, such as increases above 60, works differently. It fires only when the value moves from not meeting the condition to meeting it. The demo used the second kind.

With “on each event” and a 60-second check, the rule would email once a minute. It would go on from the crossing until someone cleared the table. That is an estimate, not a measurement. Learn caps email at 30 messages per rule, per recipient, per hour.

Learn allows email only to internal addresses in the creator's tenant. A workshop alert must go to an account in that tenant. Put the numbers in the message, too. The design asked for trial_id, n_testers, and first_choice_pct in the message context, but the exported definition lists no context fields. An email that says only “a formula passed 60” sends people back to the dashboard.

Why the rule waits for 20 testers

A share computed on a few testers moves in large steps. At tester 5, one tester is 20 percent of the count. At tester 31, one tester is about 3 percent. A rule that fires on the first value above 60 fires on noise. The demo rule ignores testers 1 to 19. It fires only when the share passes 60 after that. Both figures are simple arithmetic.

Running first-choice share for trial TR-2008, tester by tester A line chart of the running share of testers who reached for the test blotter first, for testers 1 to 40. Testers 1 to 19 sit in a shaded guard band where the rule query returns no row. The share starts at 0, touches exactly 60.0 at tester 5, stays between 44.4 and 58.6 from tester 6 to tester 29, reaches 60.0 at tester 30, passes the dashed winner line at tester 31 with 61.3 percent, and ends at 65.0 percent at tester 40. 0 20 40 60 80 Running first-choice share for the test blotter, percent 1 10 20 30 40 Tester number, in arrival order Guard: testers 1 to 19 The rule query returns no row. Winner line: above 60 Tester 5: 3 of 5, exactly 60.0 Tester 31: 19 of 31 = 61.3 The rule fires on its next check. 65.0 Running first-choice share for trial TR-2008, tester by tester The running share for testers 1 to 40. Testers 1 to 19 sit in a shaded guard band. The share touches 60.0 at tester 5, passes the dashed winner line at tester 31 with 61.3 percent, and ends at 65.0 percent. 0 20 40 60 80 Running share, percent 1 20 40 Tester number Guard: testers 1 to 19 Tester 5: 60.0 Tester 31: 61.3 Fires on next check. 65.0 Winner line: above 60
Figure 2. Running first-choice share for trial TR-2008, computed from the fixed sequence of 40 choices in the session simulator. The sequence is deterministic, so every run plots the same line. The shaded band marks the 20-tester guard: activator_state() returns no row before tester 20.
The 40 values behind Figure 2
  1. T1 0 of 1, 0.0
  2. T2 1 of 2, 50.0
  3. T3 1 of 3, 33.3
  4. T4 2 of 4, 50.0
  5. T5 3 of 5, 60.0
  6. T6 3 of 6, 50.0
  7. T7 4 of 7, 57.1
  8. T8 4 of 8, 50.0
  9. T9 4 of 9, 44.4
  10. T10 5 of 10, 50.0
  11. T11 6 of 11, 54.5
  12. T12 6 of 12, 50.0
  13. T13 7 of 13, 53.8
  14. T14 7 of 14, 50.0
  15. T15 8 of 15, 53.3
  16. T16 9 of 16, 56.3
  17. T17 9 of 17, 52.9
  18. T18 9 of 18, 50.0
  19. T19 10 of 19, 52.6
  20. T20 10 of 20, 50.0
  21. T21 11 of 21, 52.4
  22. T22 12 of 22, 54.5
  23. T23 12 of 23, 52.2
  24. T24 13 of 24, 54.2
  25. T25 14 of 25, 56.0
  26. T26 15 of 26, 57.7
  27. T27 15 of 27, 55.6
  28. T28 16 of 28, 57.1
  29. T29 17 of 29, 58.6
  30. T30 18 of 30, 60.0
  31. T31 19 of 31, 61.3
  32. T32 20 of 32, 62.5
  33. T33 20 of 33, 60.6
  34. T34 21 of 34, 61.8
  35. T35 22 of 35, 62.9
  36. T36 23 of 36, 63.9
  37. T37 23 of 37, 62.2
  38. T38 24 of 38, 63.2
  39. T39 25 of 39, 64.1
  40. T40 26 of 40, 65.0

The share starts at 0, because tester 1 chose the reference. It touches exactly 60.0 at tester 5, with three test votes in five. From tester 6 to tester 29 it stays between 44.4 and 58.6. It reaches 60.0 again at tester 30. It passes 60 at tester 31, with 19 test votes in 31, which is 61.3 percent. It ends at 26 of 40, 65.0 percent.

This sequence never puts the guard to a hard test. The early peak touches 60 but does not pass it. Suppose tester 6 had chosen the test blotter instead. The share would have been 4 of 6, or 66.7 percent. A rule without the guard would have fired at tester 6. That counterfactual is the case the guard exists for.

A guard limits noise. It does not remove it. At 20 testers, one tester is still 5 percent of the count. Treat 20 as a business choice, like 60, and write both numbers into the rule. Dr. Kot's rule of thumb: never put a threshold on a share without a count next to it.

What “real time” means in this demo

In this demo, real time means within about one minute. The booths send one event every 24 seconds. Tester 31 arrives 12 minutes after the start. Activator runs its query every 60 seconds, so the alert follows within one check after the share passes 60. Every delay in the chain is a setting, and none of them is zero.

On stage, the alert arrived after tester 31, as the session plan expected. The delay from the booth to the alert was not measured. Learn sets the default query frequency for a KQL source at 5 minutes. With the default, the alert could arrive up to 5 minutes after tester 31.

A shorter check costs capacity. Learn says that querying more often activates rules sooner and uses more capacity. Another Learn page adds that a query every 1 or 5 minutes keeps the Eventhouse always on. An idle Eventhouse costs less.

Activator can also read an Eventstream directly, with subsecond latency for stateless rules, according to Learn. That path sees one tester at a time. The rule needs a share over all testers so far, and that share lives in the Eventhouse.

Real time also depends on capacity. Under overload, Learn says Activator first slows or blocks its interface and keeps evaluating rules. After 24 hours of overload, rule evaluation pauses. Close other workloads on the capacity before a live demo.

The path of one event, from booth to alert

Follow tester 31, who pushes the share past 60, through all five parts. Steps E1 to E5 follow the session architecture.

IDPartWhat happens to tester 31
E1Booth, played by the simulatorTester T-031 at BOOTH-3 reaches for the test blotter first. At the show setting, the script sends the event 12 minutes after the start.
E2Eventstream, EventhouseThe event passes through es_blotter and lands as the 31st row of blotter_events.
E3Eventhouserunning_share() now counts 19 test votes in 31 testers: 61.3 percent. activator_state() returns that one row for trial TR-2008.
E4ActivatorOn its next run, within 60 seconds, the rule sees the share above 60 for the first time and sends one email. Ignoring ingestion delay, the check reads tester 31, 32, or 33, at 61.3, 62.5, or 60.6 percent. All three are above 60, so the rule fires once.
E5Ontology, data agentThe second half returns to 60 as a business rule in the ontology: a formula is a winner above 60. The ontology does not read these live events and sends no alert.

Step E5 is where the same 60 returns, in a second place. In Activator, 60 is a threshold that sends an email. In the ontology Preview, 60 is a written definition of the word winner that agents read. Learn says an ontology rule is a natural-language definition, and the ontology does not run it against data. The new ontology experience has no Activator integration today. So the rule lives in two places, and you keep both in step by hand. Part 3 explains what an ontology is, and why a data agent needs the same rule.

Reset between runs

Every rehearsal fills the table. Before the next run, clear it with one management command:

.clear table blotter_events data

Learn says the command clears the data of an existing table, including streaming ingestion data. It needs Table Admin permission or higher. The table, both functions, the stream, and the rule stay in place.

Then check three things. The dashboard shows an empty chart. The rule is still on. Nobody starts the script before the first demo beat. After the session, pause the capacity or delete the workspace. A rule that queries every 60 seconds keeps the Eventhouse awake.

What the demo does not show

The demo shows the mechanics on 40 events. Four gaps matter most before a production build.

Part 5 lists the gaps between this demo and production.

The session kit, with the trial event simulator, is public on GitHub. The handout was shared through the Fabric Falcons community. For the wider build order, see the Microsoft Fabric implementation guide. To review an event design or an alert rule with Dr. Kot, book a slot.

Key facts at a glance

Product facts from Microsoft Learn, checked on November 3, 2026. Demo facts from the session kit.

IDFactSource
K1Real-Time Intelligence reacts to events as they happen, and the data does not have to flow at high rates.What is Real-Time Intelligence?
K2An Eventstream does not store data permanently. It forwards events to destinations.Get data into Microsoft Fabric
K3An Eventhouse holds one or more KQL databases and organizes data by arrival time.Eventhouse overview
K4Activator runs a KQL query every 5 minutes by default, set under Run query every.Ingestion from KQL Querysets
K5Activator turns each returned row into an event stamped with the run time, so the query must return current state.Ingestion from KQL Querysets
K6A Numeric change condition fires only when a value moves from not meeting the condition to meeting it.Ingestion from KQL Querysets
K7Activator email is capped at 30 messages per rule per recipient per hour, and 500 per Activator item per hour.Activator limitations
K8Under capacity overload, Activator keeps evaluating rules for up to 24 hours, then pauses rule evaluation.How Fabric capacity throttling affects Activator
K9Copilot dashboard generation needs a paid F2 or P1 capacity and is off by default outside the US and EU.Generate Real-Time dashboards with Copilot
K10A Fabric trial lasts 60 days and does not support Copilot.Try Microsoft Fabric for free
K11In the demo sequence, the share passes 60 at tester 31, with 19 of 31 at 61.3 percent, and ends at 65.0 percent.Session kit, trial event simulator
K12The demo rule read activator_state() every 60 seconds and fired when first_choice_pct became greater than 60.Session kit, exported Activator definition

Frequently asked questions

What is Real-Time Intelligence in Microsoft Fabric?

Real-Time Intelligence is the Microsoft Fabric workload for data in motion. An Eventstream carries events in, and an Eventhouse stores and queries them. A Real-Time Dashboard shows them, and Activator acts on them with rules. Each part has one job.

What is the difference between an Eventstream and an Eventhouse?

An Eventstream carries events and routes them to destinations. Microsoft Learn says it does not store data permanently. An Eventhouse is the database where events stay, organized by arrival time and queried with KQL.

Can Copilot build a Real-Time Dashboard in Fabric?

Yes. On the Eventhouse page, select Generate with Copilot under New Real-Time Dashboard and describe the dashboard you want. It needs a paid F2 or P1 capacity, not a trial, and the Copilot tenant setting. Outside the US and EU, Copilot stays off until an admin allows processing outside the capacity's region.

How often does Activator check a KQL query?

Every 5 minutes by default, according to Microsoft Learn. You change it under Run query every on the query source. A shorter interval activates rules sooner and uses more capacity. The demo in this post used 60 seconds.

Why does my Activator alert fire on every run instead of once?

This happens when the rule alerts on each event. With a KQL source, Activator turns every returned row into an event on every run. To alert once, assign the rows to an object, such as a trial. Then use a Numeric change condition, such as increases above 60. It fires only on the transition.

Does Real-Time Intelligence work on the Fabric free trial?

Yes, for the core parts. Microsoft Learn says the 60-day trial capacity supports all Fabric workloads. Copilot is not supported on trial capacities, so a dashboard generated by Copilot needs a paid F2 or P1 capacity.

About the author

Dr. Estera Kot is CTO at Clouds on Mars, a Microsoft and Databricks partner for data and AI in Europe and the Middle East. At Microsoft she was Principal Product Manager for the Apache Spark runtime in Azure Synapse Analytics and Microsoft Fabric, and she created the Native Execution Engine. She is a Microsoft MVP and holds a Ph.D. in Computer Science from the Warsaw University of Technology. She presented this series as the community session "From Events to Answers" at Microsoft Qatar HQ in Lusail, Doha, on October 14, 2026.

Sources

Microsoft Learn, checked on November 3, 2026.