Working with Semantic Models (DAX queries)
Source:vignettes/semantic-model-refresh.Rmd
semantic-model-refresh.RmdA semantic model is the report-ready data behind Power BI and Fabric reports. It combines tables with relationships, measures, and business calculations. From R, you can query that model with DAX and refresh it after its source data changes.
Start by querying a small result. Refresh and monitoring come next, followed by the more specialized controls used for production models.
This guide uses a discovered FabricSemanticModel R6
object. Read its service fields directly. $dax_query()
corresponds to fabric_pbi_dax_query(), while the
$refresh*() methods correspond to the
fabric_pbi_refresh*() function family:
library(fabricQueryR)
model <- fabric_semantic_models("Analytics workspace")[[1]]Query the model with DAX
DAX is the query and calculation language used by semantic models.
Use $dax_query() (fabric_pbi_dax_query()) to
run a query. It normally begins with EVALUATE and returns a
table. If you are new to DAX, create and test a query in the model’s
DAX query view in Fabric, then use the same text from R:
rows <- model$dax_query(
dax = "EVALUATE TOPN(100, 'Customers')"
)
head(rows)Query the semantic model when you want its measures and relationships, or need the same business definition used by a report. Query the Warehouse or Lakehouse instead when you need the underlying source rows and SQL is a better fit.
For example, call $dax_query()
(fabric_pbi_dax_query()) to group a DAX measure by a model
column:
sales <- model$dax_query(
dax = paste(
"EVALUATE",
"SUMMARIZECOLUMNS(",
" 'Region'[Region],",
" \"Total Sales\", [Total Sales]",
")"
)
)The normal JSON mode returns one tibble and is the simplest option.
The later api = "arrow" mode is useful for richer types,
multiple result tables, or a stream, but requires a capacity-backed
model and additional tenant settings. The timeout argument
bounds the client HTTP request. For Arrow queries,
arrow_options$queryTimeout separately controls the
server-side query limit.
Check access before refreshing
Querying normally requires Read and Build permission on the model and the tenant setting that enables Execute Queries. Refreshing requires Write access. If a query succeeds but a refresh does not, ask the model owner or Fabric administrator to check those permissions and tenant settings.
Refresh after an upstream update
A standard refresh starts with $refresh()
(fabric_pbi_refresh()) and waits with
$refresh_wait()
(fabric_pbi_refresh_wait()):
refresh <- model$refresh()
completed <- model$refresh_wait(refresh, timeout = 1800)
completed$state
completed$start_time
completed$end_timePass the returned handle to status, wait, or cancel functions without copying IDs. If you save it and restore it in another R process, authenticate again.
For example, a data-load workflow can use the Lakehouse
$write_table() method
(fabric_lakehouse_write_table()) and refresh only after the
source update has committed successfully:
load <- lakehouse$write_table(
table = "Sales",
data = new_sales,
schema = "dbo",
mode = "overwrite"
)
refresh <- model$refresh(mode = "enhanced")
completed <- model$refresh_wait(
refresh,
timeout = 1800,
cancel_on_timeout = TRUE
)Client-side timeout in $refresh_wait()
(fabric_pbi_refresh_wait()) only bounds how long R waits.
Without cancel_on_timeout = TRUE, the Power BI refresh
keeps running.
Use enhanced refresh controls
Enhanced refresh through $refresh()
(fabric_pbi_refresh()) requires Power BI Premium, Premium
per user, Embedded, or Fabric capacity. Supplying an enhanced option
selects enhanced mode automatically, or set
mode = "enhanced" explicitly:
refresh <- model$refresh(
mode = "enhanced",
type = "Full",
objects = list(
list(table = "Sales", partition = "2026"),
list(table = "Calendar")
),
commit_mode = "Transactional",
max_parallelism = 4L,
retry_count = 1L,
timeout = "02:00:00"
)
completed <- model$refresh_wait(refresh, timeout = 5 * 60 * 60)The submission timeout controls an individual Power BI
attempt; the numeric timeout in $refresh_wait()
(fabric_pbi_refresh_wait()) controls how long R waits. Use
"Transactional" when the previous model should remain
available unless the complete refresh succeeds. See
?fabric_pbi_refresh before using partial-batch commits or
refresh-policy options.
Diagnose attempts and failures
Use $refresh_status()
(fabric_pbi_refresh_status()) when a refresh takes longer
than expected or fails:
status <- model$refresh_status(refresh)
status$state
status$attempts
status$messages
status$service_error
status$objects
status$details_urlThe normalized state distinguishes work that is queued, running,
completed, completed with warnings, failed, timed out, cancelled, or
disabled. Attempt details and details_url help diagnose the
service response; the complete response remains available in
raw.
By default, wait raises typed R conditions for service failures,
cancellation, service timeouts, and disabled refreshes. Keep the
terminal detail instead when building a monitoring table by calling
$refresh_wait() (fabric_pbi_refresh_wait())
with error_on_failure = FALSE:
result <- model$refresh_wait(
refresh,
error_on_failure = FALSE
)
if (result$state != "Completed") result$details_urlInspect history
Inspect recent refreshes with $refresh_history()
(fabric_pbi_refresh_history()) when you need to compare
duration or failure patterns:
history <- model$refresh_history(top = 10L)
history[[1]]$refresh_type
history[[1]]$state
history[[1]]$attempts
# Refresh an old history entry from its request ID and stored model context
latest <- model$refresh_status(history[[1]])Here $refresh_status() calls
fabric_pbi_refresh_status(), just as it does for a newly
submitted refresh.
More information
See Microsoft’s documentation for more information: - Refresh Dataset API - Enhanced refresh - Refresh execution details - Data refresh and capacity limits - How Direct Lake works