0.9.4 (Feb 28, 2025)#
Distribution#
The name QuerySession
, unused since 0.9.0 (September 13, 2024), makes a come back in this release but, this time, with a different meaning.
QuerySession
becomes the entry point to create clusters of Atoti applications [6].
atoti.Cube.restrictions
has been introduced to secure query sessions.
For the sake of symmetry, atoti.Session.security.restrictions
has moved to atoti.tables.Tables.restrictions
(the old location remains available but is deprecated).
Learn how to Scale with distribution.
Performance#
Client/server communication#
Most components of Session
are exposed through mappings such as Cubes
or Tables
.
As a project grows, a lot of mapping lookups will be made to iteratively define the data model or to pass arguments to methods such as atoti.Cube.query()
.
For instance, the following code will make 3 lookups:
new_measure = tt.agg.sum(
m["Foo.SUM"], # 1
scope=tt.OriginScope({
l["Bar"], # 2
l["Baz"], # 3
})
)
Each lookup makes a request to the server to check that the key exists.
This is pretty quick but, when thousands of lookups are made, this client/server communication can add up.
mapping_lookup()
allows skipping these server requests.
Cube queries#
The aggregate cache of a cube can be restricted to a subset of measures [3].
This improvement comes with a new atoti.Cube.aggregate_cache
API deprecating the previous atoti.Cube.aggregates_cache
(with an “s”) one:
- cube.aggregates_cache.capacity = 200
+ cube.aggregate_cache = tt.AggregateCache(capacity=200)
- cube.aggregates_cache.capacity = -1
+ del cube.aggregate_cache
Hierarchy creation#
Creating hierarchies from columns of a table fully joined (i.e. all their keys are mapped) to the cube’s fact table do not require “rebuilding” the cube anymore [4]. This means that no time will be lost reindexing hierarchies or performing other expensive computations.
Data modeling#
Measures#
atoti.where()
was not respecting the order of condition_to_value when the same value was assigned to multiple conditions [2].
For example, in:
m["8"] = 8
m["Test"] = tt.where(
{
m["8"] < 5: -1, # False
m["8"] >= 5: 1, # True
m["8"] < 10: -1, # True
},
default=0,
)
Test was equal to -1
because the first and last conditions, being both assigned to the same value, were merged together and that merged condition became the first one evaluating to True
.
This incorrect merging of conditions has been removed: m["8"] >= 5
is correctly detected as the first condition evaluating to True
and so Test is equal to 1
.
Table columns#
Columns with an arrray data type can be made non-nullable.
atoti.Column.default_value
’s documentation has been updated accordingly.
Data loading#
Transactions#
data_transaction()
’s tables parameter allows some data transactions to execute concurrently [1].
CSV#
The atoti.CsvLoad.true_values
and atoti.CsvLoad.false_values
attributes can be configured to parse more values than "True"
, "true"
, "False"
, and "false"
as "boolean"
[5].
Dependencies#
Internal issue tracker references